HIGH axumxml bomb

Xml Bomb in Axum

How Xml Bomb Manifests in Axum

An XML bomb (or billion laughs attack) exploits recursive entity expansion in XML parsers to cause excessive memory consumption or denial of service. In Axum, a Rust web framework, this vulnerability typically arises when an endpoint accepts XML payloads and uses an XML parser that does not limit entity expansion depth or node count. Axum itself does not include an XML parser; developers integrate third-party crates like quick-xml, xml-rs, or serde_xml_rs for XML handling. If these parsers are configured without security limits, a malicious XML payload with deeply nested entities can trigger exponential expansion.

For example, consider an Axum handler that deserializes XML into a Rust struct using serde_xml_rs without limits:

use axum::{extract::State, Json, Router};
use serde::Deserialize;
use serde_xml_rs::from_str;

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

async fn create_user(State(_state): State, Json(payload): Json) -> Result, &'static str> {
    // Dangerous: no limits on XML parsing
    let data: UserData = from_str(&payload).map_err(|_| "Invalid XML")?;
    Ok(Json(data))
}

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

An attacker could send a payload like:

<?xml version="1.0"?>
<!DOCTYPE root [
  <!ENTITY a0 "DoS">
  <!ENTITY a1 "&a0;&a0;&a0;&a0;&a0;&a0;&a0;&a0;&a0;&a0;>
  <!ENTITY a2 "&a1;&a1;&a1;&a1;&a1;&a1;&a1;&a1;&a1;&a1;>
  
]>
<root>&a10;</root>

This causes the parser to expand &a10 to 1 billion copies of "DoS", consuming gigabytes of memory and crashing the process. In Axum, since the request body is read into memory before parsing, this can lead to OOM (out-of-memory) kills, affecting service availability. The attack targets the unauthenticated surface — no credentials needed — making it detectable by black-box scanners like middleBrick.

Axum-Specific Detection

Detecting XML bomb vulnerabilities in Axum requires observing the application's response to maliciously crafted XML payloads. middleBrick performs black-box scanning by sending a series of XML bomb patterns to the endpoint and monitoring for signs of distress: prolonged response times, HTTP 500 errors, connection resets, or absent responses due to process crashes. Since middleBrick does not require agents or configuration, it scans the unauthenticated attack surface by simply submitting the API URL.

For Axum endpoints consuming XML, middleBrick sends payloads with increasing entity expansion depth (e.g., up to 10 entities) and measures response behavior. If the endpoint returns an error (like 400 Bad Request) or times out consistently under load, it may indicate missing parser limits. middleBrick also checks for verbose error messages that might leak stack traces, which could assist attackers in refining exploits.

Example detection flow:

  1. middleBrick identifies an endpoint accepting Content-Type: application/xml or text/xml.
  2. It sends a small XML bomb (e.g., 3 entities) and records baseline latency.
  3. It sends a larger payload (e.g., 6 entities) and compares response time.
  4. If latency grows exponentially or the connection drops, it flags a potential XML bomb vulnerability.
  5. The finding is reported with severity based on impact: if the endpoint crashes the service, severity is high; if it only causes slowdown, medium.

middleBrick does not need to see source code or internal logs — it infers risk from external behavior. This makes it effective for Axum services deployed in containers or serverless environments where internal monitoring may be limited.

Axum-Specific Remediation

Fixing XML bomb vulnerabilities in Axum involves configuring the XML parser to enforce limits on entity expansion, node count, and depth. Since Axum is agnostic to parsing libraries, the fix depends on the crate used. Below are remediation strategies for common XML parsers in Axum.

Using quick-xml with limits: quick-xml does not expand external entities by default but can still be vulnerable to internal entity bombs if not configured. Use Reader with custom limits:

use axum::{extract::State, Json, Router};
use quick_xml::Reader;
use quick_xml::events::Event;
use std::io::Cursor;

#[derive(Debug, serde::Deserialize)]
struct UserData {
    name: String,
    email: String,
}

async fn create_user(State(_state): State, Json(payload): Json) -> Result, &'static str> {
    let mut reader = Reader::from_str(&payload);
    reader.trim_text(true);
    reader.check_comments(true);
    
    // Set limits: max 1MB buffer, 1000 entities
    reader.set_buffer_capacity(1024 * 1024);
    
    let mut buf = Vec::new();
    let mut depth = 0u32;
    loop {
        match reader.read_event(&mut buf) {
            Ok(Event::Start(_)) => {
                depth += 1;
                if depth > 100 { return Err("XML too deep"); }
            }
            Ok(Event::End(_)) => { depth = depth.saturating_sub(1); }
            Ok(Event::Eof) => break,
            Err(e) => return Err(&format!("XML error: {}", e)),
            _ => {}
        }
        buf.clear();
    }
    
    // Now deserialize safely (or use manual parsing)
    let data: UserData = quick_xml::de::from_str(&payload)?;
    Ok(Json(data))
}

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

Using serde_xml_rs with max_depth: serde_xml_rs supports limiting recursion depth via Options:

use axum::{extract::State, Json, Router};
use serde::Deserialize;
use serde_xml_rs::{from_str, Options};

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

async fn create_user(State(_state): State, Json(payload): Json) -> Result, &'static str> {
    let mut opts = Options::default();
    opts.max_depth = 50; // Prevent deep nesting
    opts.max_buffersize = Some(1024 * 1024); // 1MB max
    
    let data: UserData = from_str_with_options(&payload, opts)
        .map_err(|_| "Invalid or unsafe XML")?;
    Ok(Json(data))
}

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

Alternative: Use JSON instead of XML Where possible, avoid XML entirely. JSON parsers like serde_json are not vulnerable to entity expansion attacks. If clients require XML, consider adding a middleware layer that validates and sanitizes input before reaching Axum handlers.

After applying fixes, validate with middleBrick by rescanning the endpoint. A resolved finding will show improved response times and absence of crash signals under XML bomb payloads.

Frequently Asked Questions

Can middleBrick detect XML bomb vulnerabilities in Axum apps that use custom XML parsing logic?
Yes. middleBrick performs black-box testing by sending XML bomb payloads to the endpoint and observing external symptoms like timeouts, errors, or crashes. It does not require visibility into internal parsing logic — only that the endpoint processes XML and is reachable over the network.
Does enabling XML parser limits in Axum affect legitimate large XML payloads?
It can, if limits are set too low. Configure limits based on expected legitimate use: e.g., if your API accepts XML up to 5MB with moderate nesting, set max_buffersize to 5MB and max_depth to 100. Test with realistic payloads before deploying to production.