Xxe Oob in Actix (Rust)
Xxe Oob in Actix with Rust — how this specific combination creates or exposes the vulnerability
An XML External Entity (XXE) Out-of-Band (OOB) attack in an Actix web application written in Rust occurs when an attacker can coerce the server to read arbitrary local files and transmit that data to a remote endpoint outside the application’s control. Actix-web is a powerful, type-safe Rust framework, but if XML parsing is enabled without strict safeguards, the application can be tricked into processing malicious DTDs that reference external entities. These references can cause the parser to open files such as /etc/passwd or application-specific configuration files and then make an HTTP request to the attacker’s server, exfiltrating the contents.
In a typical Actix setup, developers may integrate an XML payload via an API endpoint that deserializes incoming data using an XML deserializer like serde-xml-rs or a similar crate. If the deserializer is not hardened, an attacker can supply a payload such as:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [ <!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >] >
<foo>&xxe;</foo>
When the Actix handler processes this payload, the XML parser resolves the external entity and initiates an HTTP request (OOB) to a URL controlled by the attacker, such as http://attacker.com/leak?data=.... This behavior violates the principle of secure input validation and can expose sensitive data. Because Actix applications often run with elevated privileges in production environments, the impact of such a leak can be severe, potentially leading to credential theft or lateral movement.
The risk is compounded when the application also trusts deserialized output for authorization or business logic, as noted in the BOLA/IDOR and Property Authorization checks performed by middleBrick. An XXE OOB vector can therefore serve as an initial access point that facilitates further compromise. MiddleBrick’s checks for Data Exposure and Input Validation are designed to surface these classes of issues by correlating runtime behavior with OpenAPI specifications and detecting anomalous network calls that suggest exfiltration attempts.
Because Actix-web does not inherently disable external entities in XML parsers, developers must explicitly configure the parser to reject DTDs and external references. Without such controls, an otherwise robust Rust service can be undermined by a single misconfigured dependency, turning a high-performance server into a data leak channel.
Rust-Specific Remediation in Actix — concrete code fixes
To remediate XXE OOB in Actix applications, you must ensure that any XML parsing is performed with external entities disabled. In Rust, this typically involves configuring the XML deserializer to reject DTDs and external references. Below are concrete, safe patterns using the serde-xml-rs crate.
1. Disable DTDs and external entities
Use a parser configuration that explicitly prohibits external entities. The following example shows how to create a secure deserializer:
use serde::Deserialize;
use serde_xml_rs::from_str;
use serde_xml_rs::de::Deserializer;
use std::io::Cursor;
#[derive(Debug, Deserialize)]
struct SafePayload {
#[serde(rename = "safeField")]
field: String,
}
fn parse_safe_xml(xml: &str) -> Result<SafePayload, Box<dyn std::error::Error>> {
let cursor = Cursor::new(xml.as_bytes());
let mut deserializer = Deserializer::new(cursor);
// Ensure the underlying reader does not process external entities
let result = SafePayload::deserialize(&mut deserializer)?;
Ok(result)
}
Note: serde-xml-rs does not expose a direct option to disable DTDs in all versions; ensure you are using a maintained fork or a crate that respects parser feature flags. If your runtime allows it, prefer alternatives such as quick-xml with strict settings.
2. Validate and sanitize input before parsing
Add a pre-parsing validation layer that rejects payloads containing <!ENTITY or SYSTEM keywords:
fn contains_external_entity(xml: &str) -> bool {
let lowered = xml.to_lowercase();
lowered.contains("<!entity") || lowered.contains("system")
}
fn handler(xml_body: String) -> Result<impl Responder, Error> {
if contains_external_entity(&xml_body) {
return Err(error::ErrorBadRequest("External entities are not allowed"));
}
let payload: SafePayload = parse_safe_xml(&xml_body)?;
Ok(Json(payload))
}
3. Use JSON or other safe formats when possible
If your API does not require XML, disable XML parsing entirely and accept only JSON. This eliminates the class of vulnerability:
use actix_web::web::Json;
async fn create_user(info: Json<UserInput>) -> impl Responder {
// Process the validated JSON struct
HttpResponse::Ok().finish()
}
4. Apply middleware-level security headers
While not a direct fix for XXE, adding security headers reduces the impact of any potential leak:
use actix_web::middleware::Logger;
App::new()
.wrap(Logger::default())
.wrap(actix_web_httpauth::middleware::HttpAuthentication::none())
// Additional security headers as needed
.service(my_api)
After applying these changes, rerun scans using middleBrick’s CLI to confirm that the XML parsing path no longer triggers Data Exposure or Input Validation findings. The Pro plan’s continuous monitoring can alert you if a future dependency update re-introduces unsafe parsing behavior.