Xml External Entities in Actix with Hmac Signatures
Xml External Entities in Actix with Hmac Signatures — how this specific combination creates or exposes the vulnerability
Xml External Entity (XXE) injection occurs when an XML parser processes external entity references within untrusted XML data, potentially leading to sensitive file reads, server-side request forgery, or denial of service. In Actix web applications that accept XML payloads, XXE is a concern when the XML parser is configured to resolve external entities. Hmac Signatures are commonly used to ensure the integrity and authenticity of requests by signing a canonical representation of the payload. When Hmac Signatures are used, the client computes a signature over the request body (often the raw XML) and sends it in a header. If the server first validates the Hmac Signature using the shared secret and then parses the XML, the signature validation step typically requires the raw, unchanged body. This creates a risk: developers might inadvertently enable or retain XML features that support external entities because they believe the signature protects the input. However, signature verification does not mitigate XXE; if the XML parser resolves external entities, the server can still disclose internal files or make internal HTTP requests before the application logic checks business-level integrity. Additionally, if the Hmac verification logic logs or echoes parts of the XML body for debugging, external entity expansions can exfiltrate data through out-of-band channels or error messages. The combination is problematic because the signature ensures integrity but does not affect parser behavior; a vulnerable XML parser remains exploitable even when requests are Hmac-signed. Attack patterns include embedding file:// or http:// entities to read Actix server files or trigger SSRF via the parser’s network resolution. This risk is particularly relevant when using Rust XML crates that allow external entity processing by default unless explicitly disabled. Defenses require disabling external entity resolution at the parser level and ensuring that signature verification operates only on sanitized, non-entity-expanded content.
Hmac Signatures-Specific Remediation in Actix — concrete code fixes
To remediate XXE in Actix while using Hmac Signatures, ensure the XML parser is configured to prohibit external entities and perform signature verification on the raw body before any parsing. Below are concrete code examples that demonstrate a secure approach in Actix using the xml-rs crate, which does not support external entities by default, and the hmac crate for signature validation.
- Verify Hmac Signature on the raw body and reject requests before parsing XML if the signature is invalid.
- Use a non-validating XML reader or explicitly disable external entities to prevent XXE.
- Avoid logging or echoing parsed XML content that could expose expanded entities.
Example: Secure Actix handler with Hmac verification and safe XML parsing
use actix_web::{post, web, HttpResponse, Result};
use hmac::{Hmac, Mac};
use sha2::Sha256;
use xml::reader::{EventReader, XmlEvent};
use std::io::Cursor;
type HmacSha256 = Hmac;
/// Verify Hmac signature over the raw body.
fn verify_hmac(body: &[u8], signature_header: &str, secret: &[u8]) -> bool {
// Expected signature format: hex-encoded Hmac-SHA256
let mut mac = HmacSha256::new_from_slice(secret).expect("HMAC can take key of any size");
mac.update(body);
let result = mac.finalize();
let computed = hex::encode(result.into_bytes());
// Constant-time comparison to avoid timing leaks
computed == signature_header
}
/// Parse XML safely without external entity expansion.
fn parse_xml_safely(data: &[u8]) -> Result, String> {
let cursor = Cursor::new(data);
let parser = EventReader::new(cursor);
let mut values = Vec::new();
for event in parser {
match event.map_err(|e| e.to_string())? {
XmlEvent::StartElement { name, .. } => {
values.push(name.local_name);
}
XmlEvent::Characters(chars) => {
values.push(chars);
}
XmlEvent::EndElement { name } => {
values.push(format!("{}>", name.local_name));
}
// Ignore other events; do not attempt to resolve external entities.
_ => {}
}
}
Ok(values)
}
#[post("/api/process")]
async fn process_xml(
body: web::Bytes,
headers: actix_web::http::HeaderMap,
) -> Result {
let secret = b"super-secret-shared-key";
let signature = headers.get("X-Hmac-Signature")
.and_then(|v| v.to_str().ok())
.ok_or_else(|| HttpResponse::BadRequest().body("Missing signature"))?;
// Verify Hmac on the raw body before any processing.
if !verify_hmac(&body, signature, secret) {
return Ok(HttpResponse::Unauthorized().body("Invalid signature"));
}
// Parse XML safely; xml-rs does not expand external entities by default.
match parse_xml_safely(&body) {
Ok(elements) => Ok(HttpResponse::Ok().json(elements)),
Err(e) => Ok(HttpResponse::BadRequest().body(format!("Invalid XML: {}", e))),
}
}
If you use a different XML library that supports external entities (for example, roxmltree with custom configuration), explicitly disable them:
// Example guidance for crates that allow entity expansion — disable it.
// Ensure your XML reader/ parser is configured to not resolve external entities.
// If using a crate that exposes parser features, prefer a non-validating, non-external mode.
For continuous protection, add the middleBrick CLI to your workflow: use middlebrick scan <url> to validate that your endpoints reject malformed or malicious XML before deploying. Teams using the Pro plan can enable continuous monitoring so that any regression in API security posture triggers alerts, and the GitHub Action can fail builds if the risk score drops below your defined threshold.