Xml External Entities in Axum with Mongodb
Xml External Entities in Axum with Mongodb — how this specific combination creates or exposes the vulnerability
XML External Entity (XXE) injection occurs when an application processes XML input that references external entities, and those entities are resolved in a way that exposes local files, triggers SSRF, or consumes excessive resources. In an Axum application that deserializes XML payloads and uses the parsed data to build queries for MongoDB, an attacker-controlled external entity can lead to unintended data access or server-side request forgery against internal services.
Consider an endpoint that accepts an XML document to configure or filter a MongoDB query. If the XML parser is configured to resolve external entities (e.g., via libxml2 features such as XML_PARSE_EXTERNAL_GENERAL_ENTITIES), an attacker can supply an entity that reads sensitive files or forces the server to make HTTP requests to internal endpoints. For example:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<query><filter>>{"username": "&xxe;"}</filter></query>
If Axum deserializes this XML and directly embeds the resolved value into a MongoDB filter, the application may unintentionally disclose the contents of /etc/passwd. Additionally, an external entity can force Axum to make outbound HTTP requests, enabling SSRF against internal MongoDB management interfaces or other internal services. Even when Axum does not directly parse XML, a downstream service or library (such as a logging formatter or an internal API client) might do so, creating an indirect XXE path into the MongoDB pipeline.
Moreover, if the MongoDB driver or an ODM layer is invoked with data derived from XML, crafted external entities can manipulate query contents in ways that bypass intended validation. For instance, an attacker could inject a MongoDB query operator through entity expansion to alter the semantics of a filter. Because the scan tests for such behaviors among the 12 checks, it flags combinations where untrusted XML input intersects with database operations, helping you identify whether your Axum endpoints expose an unauthenticated attack surface that can be abused via XXE.
Mongodb-Specific Remediation in Axum — concrete code fixes
To secure an Axum application that interacts with MongoDB, prevent XML external entity resolution by disabling external entity processing in your XML parser. If you do not need XML input, avoid XML parsers entirely and prefer JSON-based APIs. When XML support is required, configure the parser to deny DOCTYPE declarations and external entities.
Below is a Rust example using the roxmltree parser, which does not resolve external entities by design, reducing risk compared to more feature-rich parsers. This approach ensures that any XML provided by clients is treated as static data without external fetches:
use axum::{routing::post, Router};
use serde::{Deserialize, Serialize};
use std::net::SocketAddr;
#[derive(Debug, Deserialize, Serialize)]
struct QueryFilter {
username: String,
}
async fn handle_query(body: String) -> String {
// Use a safe, non-validating XML parser if you must accept XML.
// roxmltree does not resolve external entities.
let doc = roxmltree::Document::parse(&body).expect("valid XML");
// Extract data safely without DTD/entity resolution.
let filter_node = doc.descendants().find(|n| n.has_tag_name("filter"));
if let Some(node) = filter_node {
let username = node.text().unwrap_or("").to_string();
// Build a MongoDB filter using a safe driver interface.
let filter = doc! { "username" => username };
// Serialize filter for logging or further processing; do not forward raw XML.
return serde_json::to_string(&filter).unwrap_or_default();
}
String::new()
}
#[tokio::main]
async fn main() {
let app = Router::new().route("/query", post(|body: String| async move { handle_query(body) }));
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
axum::Server::bind(&addr)
.serve(app.into_make_service())
.await
.unwrap();
}
If you use a more capable XML library that supports DTDs, explicitly disable external entity resolution. For example, with the xml-rs crate, avoid setting features that enable external general entities:
use xml::reader::{EventReader, XmlEvent};
use std::io::Cursor;
fn parse_safe_xml(input: &str) -> Vec<String> {
let cursor = Cursor::new(input);
let parser = EventReader::new(cursor);
let mut results = Vec::new();
for event in parser {
match event {
Ok(XmlEvent::StartElement { name, .. }) => {
results.push(name.local_name);
}
_ => {}
}
}
results
}
// Ensure the XML reader is not configured to resolve external entities.
// Avoid using features or settings that expand DOCTYPEs or SYSTEM references.
For MongoDB interactions, always use the official MongoDB Rust driver with strongly typed filters and avoid constructing queries by concatenating raw XML-derived strings. Validate and sanitize all inputs before building BSON documents:
use mongodb::{bson::doc, Client};
async fn safe_mongo_query(client: &Client, username: String) {
let filter = doc! { "username": username };
let collection = client.database("test").collection("users");
let _cursor = collection.find(filter, None).await.expect("find query");
// Process results safely; do not embed raw XML in queries.
}
By combining a safe XML parsing strategy with strict input validation and the MongoDB Rust driver’s typed APIs, you reduce the risk of XXE and related injection paths. The scanner can help verify whether your endpoints remain resilient against unauthenticated XXE attempts targeting this stack.