HIGH xml external entitiesaxum

Xml External Entities in Axum

How Xml External Entities Manifests in Axum

XML External Entity (XXE) attacks occur when an application processes XML input containing references to external entities, allowing attackers to read arbitrary files, perform SSRF attacks, or cause denial of service through entity expansion. In Axum applications, XXE vulnerabilities typically manifest in three specific scenarios.

The most common occurrence is when Axum endpoints accept XML payloads and parse them without disabling external entity processing. Consider this vulnerable handler:

use axum::extract::Json;
use serde::Deserialize;

#[derive(Deserialize)]
struct UserData { 
    name: String,
    preferences: String,
}

async fn create_user(Json(user): Json<UserData>) -> String {
    // XML parsing happens here with default settings
    format!("User {} created", user.name)
}

let app = axum::Router::new()
    .route("/api/users", axum::routing::post(create_user));

The vulnerability appears because Axum's Json extractor uses serde_xml_rs by default for XML content, which doesn't disable external entities. An attacker can craft a payload like:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
  <!ELEMENT foo ANY >
  <!ENTITY xxe SYSTEM "file:///etc/passwd" >
]>
<root>
  <name>test</name>
  <preferences>&xxe;</preferences>
</root>

When this XML is deserialized, the preferences field will contain the contents of /etc/passwd, potentially exposing sensitive system information.

A second manifestation occurs in configuration files. Many Rust applications use XML for configuration, and Axum apps are no exception. If your application loads XML configuration files like:

use quick_xml::de::from_reader;

#[derive(Debug, Deserialize)]
struct Config {
    server: ServerConfig,
    database: DatabaseConfig,
}

#[derive(Debug, Deserialize)]
struct ServerConfig {
    port: u16,
    host: String,
}

// Vulnerable: no entity expansion disabled
let config: Config = from_reader(File::open("config.xml")?)?;

An attacker who can influence the configuration file path or contents could exploit XXE to read files or access internal services.

The third pattern involves XML-based APIs that accept XML-RPC or SOAP requests. Axum applications implementing these protocols without proper XML parser configuration are vulnerable to the same entity expansion and external entity attacks.

Axum-Specific Detection

Detecting XXE vulnerabilities in Axum applications requires examining both the code and runtime behavior. For code analysis, look for these specific patterns:

First, scan for XML deserialization without entity protection. In Axum applications, this typically involves searching for imports from serde_xml_rs, quick_xml, or similar XML crates without corresponding entity configuration. A vulnerable pattern looks like:

use serde::Deserialize;
use serde_xml_rs::from_reader;

#[derive(Deserialize)]
struct RequestData { /* fields */ }

// Vulnerable: no entity configuration
let data: RequestData = from_reader(request.body())?;

The secure pattern requires explicit entity disabling:

use serde::Deserialize;
use serde_xml_rs::Deserializer;
use xml::reader::ParserConfig;

#[derive(Deserialize)]
struct RequestData { /* fields */ }

// Secure: disable external entities
let mut config = ParserConfig::new();
config = config.trim_whitespace(true)
               .ignore_comments(true)
               .create_internal_parser(false)
               .allow_entities(false);
let mut de = Deserializer::new_with_config(body_reader, config);
let data: RequestData = Deserialize::deserialize(&mut de)?;

For runtime detection, middleBrick's black-box scanning approach is particularly effective for Axum applications. The scanner tests for XXE by sending XML payloads with external entity references to your API endpoints. When scanning an Axum application, middleBrick:

  • Sends XML payloads containing SYSTEM entity references pointing to localhost or known internal services
  • Tests for entity expansion by including deeply nested entity definitions to detect potential DoS vulnerabilities
  • Verifies whether the application processes external entities by checking for unexpected responses or timing differences

The scanner's API security checks specifically target the unauthenticated attack surface, which is crucial for XXE since many applications process XML in authentication endpoints or public APIs. middleBrick's findings include the exact payload that triggered the vulnerability and severity assessment based on the potential impact.

For Axum applications using OpenAPI specifications, middleBrick cross-references your API definitions with runtime findings. If your Axum app exposes XML endpoints through OpenAPI/Swagger specs, the scanner validates that the actual implementation matches the documented behavior and identifies any discrepancies that might indicate security issues.

Axum-Specific Remediation

Remediating XXE vulnerabilities in Axum applications requires a defense-in-depth approach. The primary fix is configuring XML parsers to disable external entity processing and entity expansion. Here are Axum-specific remediation patterns:

For applications using serde_xml_rs with Axum's Json extractor, replace the default extractor with a secure wrapper:

use axum::extract::reify_body::ReifiableBody;
use axum::extract::FromRequestParts;
use axum::http::request::Parts;
use axum::middleware::Next;
use axum::response::Response;
use futures_util::future;
use serde::Deserialize;
use serde_xml_rs::Deserializer;
use xml::reader::ParserConfig;
use axum::body::HttpBody;

#[derive(Deserialize)]
pub struct SecureXmlData { /* your fields */ }

pub struct SecureXml(Option<SecureXmlData>);

#[async_trait]
impl<B> FromRequestParts<&'static Parts> for SecureXml
where
    B: HttpBody + Send,
    B::Data: Send,
    B::Error: Into<std::io::Error>,
{
    type Rejection = String;

    async fn from_request_parts(parts: &'static Parts, body: &B) -> Result<Self, Self::Rejection> {
        let mut config = ParserConfig::new();
        config = config.trim_whitespace(true)
                       .ignore_comments(true)
                       .create_internal_parser(false)
                       .allow_entities(false);
        
        let bytes = hyper::body::to_bytes(body).await.map_err(|e| e.to_string())?;
        let mut de = Deserializer::new_with_config(&*bytes, config);
        let data = SecureXmlData::deserialize(&mut de).map_err(|e| e.to_string())?;
        
        Ok(SecureXml(Some(data)))
    }
}

// Usage in handler
async fn create_user(SecureXml(data): SecureXml) -> String {
    if let Some(user_data) = data.0 {
        format!("User {} created securely", user_data.name)
    } else {
        "Invalid XML".to_string()
    }
}

This wrapper ensures that all XML parsing through Axum endpoints uses a parser configuration that explicitly disables external entities and entity expansion.

For applications using quick_xml, the remediation pattern is similar:

use quick_xml::de::from_reader;
use quick_xml::de::ParserConfig;
use std::io::Read;

// Secure XML parsing for configuration files
let mut config = ParserConfig::new();
config = config.create_internal_parser(false)
               .set_entity_checker(|_| None);
let reader = config.create_reader(File::open("config.xml")?)?;
let config: Config = from_reader(reader)?;

Another critical remediation step is input validation at the Axum layer. Implement middleware that checks the Content-Type header and rejects XML content for endpoints that don't explicitly require it:

async fn xml_rejection_middleware(
    mut req: axum::http::Request,
    next: axum::middleware::Next,
) -> Result<axum::http::Response, axum::http::Error> {
    if req.headers().get("content-type")
        .and_then(|ct| ct.to_str().ok())
        .map_or(false, |ct| ct.contains("xml")) {
        
        // Check if endpoint actually needs XML
        let path = req.uri().path();
        if !path.starts_with("/api/xml") && !path.starts_with("/soap") {
            return Ok(axum::http::Response::builder()
                .status(400)
                .body(axum::http::Body::from("XML not accepted"))?);
        }
    }
    
    next.run(req).await
}

For comprehensive protection, integrate middleBrick's continuous monitoring into your development workflow. The Pro plan's scheduled scanning can automatically test your Axum APIs for XXE vulnerabilities whenever configuration changes or new endpoints are deployed. Combined with the GitHub Action, you can fail builds if security scans detect XXE vulnerabilities, ensuring these issues are caught before production deployment.

Frequently Asked Questions

How does middleBrick detect XXE vulnerabilities in Axum applications?
middleBrick performs black-box scanning by sending XML payloads containing external entity references to your API endpoints. The scanner tests for both entity expansion and external entity processing by including payloads that reference localhost services and system files. For Axum applications, middleBrick specifically targets the unauthenticated attack surface, sending requests to public endpoints and validating whether the application processes external entities. The scanner provides detailed findings including the exact payload that triggered the vulnerability and severity assessment based on the potential impact.
Can I use middleBrick to scan my Axum application during development?
Yes, middleBrick offers multiple integration options for development workflows. The CLI tool allows you to scan your running Axum application from the terminal with the command middlebrick scan http://localhost:3000. The GitHub Action can be added to your CI/CD pipeline to automatically scan staging or development APIs before deployment. For Pro plan subscribers, continuous monitoring can be configured to scan your Axum APIs on a schedule, providing ongoing security assessment as your application evolves.