HIGH xml external entitiesaxummutual tls

Xml External Entities in Axum with Mutual Tls

Xml External Entities in Axum with Mutual Tls — how this specific combination creates or exposes the vulnerability

XML External Entity (XXE) injection occurs when an XML parser processes external entity references in a way that can read local files, trigger SSRF, or cause denial of service. In Axum, if an HTTP endpoint accepts and parses untrusted XML payloads (for example via a body extractor that deserializes XML), an attacker can embed malicious entity definitions that read files or cause network interactions. When Mutual TLS is enabled, the server validates the client certificate during the TLS handshake before the application sees the request. This can create a false sense of security: operators may assume that strong authentication prevents injection, but XXE is a parsing issue, not an authentication issue. Mutual TLS does not stop an authenticated, authorized client from sending malicious XML; it only confirms identity. If a client certificate is required, an attacker who possesses a valid certificate (obtained through compromise or misissuance) can still send crafted XML to endpoints that parse XML, combining authentication with injection to bypass access controls that rely solely on transport-layer identity checks.

In Axum, common patterns that risk XXE include using XML readers or deserializers on request bodies without disabling external entity resolution. For example, if you use an XML crate that builds a reader with default features, the parser may resolve DOCTYPE declarations and fetch external DTDs. With Mutual TLS, the server may perform certificate verification early, but the application must still process the body. An endpoint like POST /import that expects client certificates and accepts XML can be abused if it does not explicitly disable external entities. Attack patterns include reading sensitive files from the server (e.g., /etc/passwd), SSRF via entity expansions that trigger internal service endpoints, or billion laughs attacks that exhaust memory. Because Mutual TLS ensures a known client identity, the resulting findings may map to compliance frameworks such as OWASP API Top 10 A03:2023 (Injection) and A07:2021 (Identification and Authentication Failures) when XXE is present despite certificate requirements.

Operational context matters: with middleBrick’s unauthenticated scan, the tool tests the surface without client certificates, so it may not trigger XXE paths that are gated by Mutual TLS. However, the scanner’s authentication checks and injection tests can still identify parsing risks if the endpoint processes XML in an unsafe way. When using the middleBrick CLI (middlebrick scan <url>) or the GitHub Action to fail builds on risky scores, teams can detect unsafe XML handling. The Pro plan’s continuous monitoring can track whether changes re-introduce XXE-prone configurations, and findings will include remediation guidance to harden parsing regardless of transport security.

Mutual Tls-Specific Remediation in Axum — concrete code fixes

To remediate XXE in Axum while accounting for Mutual TLS, focus on secure XML parsing and strict certificate handling. Disable external entities and DTDs in your XML parser, and avoid passing untrusted XML to general-purpose deserializers. Below are concrete Axum examples that combine Mutual TLS configuration with safe XML handling.

Mutual TLS setup in Axum (Tower/ Hyper) with rustls

Configure the server to require client certificates and validate them. This example uses rustls with an Axum service builder.

use axum::Router;
use std::net::SocketAddr;
use rustls::{Certificate, PrivateKey, ServerConfig};
use rustls_pemfile::{certs, pkcs8_private_keys};
use std::fs::File;
use std::io::BufReader;

async fn build_secure_router() -> Router {
    // Load server cert and key
    let cert_file = &mut BufReader::new(File::open("server.crt").unwrap());
    let key_file = &mut BufReader::new(File::open("server.key").unwrap());
    let cert_chain: Vec<Certificate> = certs(cert_file).unwrap().into_iter().map(Certificate).collect();
    let mut keys: Vec<PrivateKey> = pkcs8_private_keys(key_file).unwrap();
    let private_key = keys.remove(0);

    // Configure client authentication
    let mut server_config = ServerConfig::builder()
        .with_safe_defaults()
        .with_no_client_auth(); // start without client certs
    // To require client certs, build a client verifier (e.g., with known CAs)
    let client_root_store = rustls::RootCertStore::empty();
    // Assume `ca.crt` contains trusted CAs that issue client certificates
    let mut ca_file = BufReader::new(File::open("ca.crt").unwrap());
    let ca_certs: Vec<Certificate> = certs(&mut ca_file).unwrap().into_iter().map(Certificate).collect();
    for cert in ca_certs {
        client_root_store.add(&cert).unwrap();
    }
    let client_auth = rustls::server::AllowAnyAuthenticatedClient::new(client_root_store);
    server_config.client_auth = Some(Arc::new(client_auth));

    let tls_acceptor = std::sync::Arc::new(server_config);
    let listener = tokio_rustls::TlsListener::from_adapter(tls_acceptor, tokio::net::TcpListener::bind("0.0.0.0:8443").unwrap());

    // Build Axum router
    let app = Router::new()
        .route("/safe", axum::routing::post(|_: String| async { "ok" }));

    // Accept connections with TLS
    axum::serve(listener, app).await.unwrap();
}

Disable external entities in XML parsing

Use a safe XML parser configuration that prohibits DOCTYPE and external entity resolution. The following example uses the xml-rs crate in a controlled way to avoid entity expansion.

use axum::{routing::post, Json, Router};
use serde::Deserialize;
use std::io::Cursor;
use xml::reader::{EventReader, XmlEvent};

async fn handle_xml_without_xxe(body: String) -> String {
    let cursor = Cursor::new(body);
    let parser = EventReader::new(cursor);
    for event in parser {
        match event {
            Ok(XmlEvent::StartElement { name, attributes, namespace }) => {
                // Process elements safely; do not resolve external entities
                // Ensure no DOCTYPE events are processed by not enabling them in parser config
                // xml-rs does not resolve external entities by default when not using feature "entities"
                // If you need attribute handling, validate against a schema instead of expanding entities
            }
            Ok(XmlEvent::EndElement { name }) => { /* handle end */ }
            _ => { /* ignore other events */ }
        }
    }
    "processed".to_string()
}

// Example route that combines Mutual TLS identity with safe XML parsing
let app = Router::new()
    .route("/import", post(|body: String| async move {
        // Validate business logic here
        let result = handle_xml_without_xxe(body).await;
        Json(result)
    }));

Additional hardening

  • Do not use XML features that resolve external references; prefer JSON or strictly validated binary formats where possible.
  • If you must parse XML, use a parser with explicit feature flags that disable DTD and external entity resolution; audit dependencies for unsafe defaults.
  • Combine Mutual TLS with application-level authorization checks so that even authenticated requests are validated for permissions and input safety.

These steps ensure that Mutual TLS protects against unauthorized clients while the application itself prevents XXE, addressing both transport and parsing layers.

Frequently Asked Questions

Does Mutual TLS alone prevent XML External Entity attacks in Axum?
No. Mutual TLS authenticates the client at the transport layer but does not affect XML parsing behavior. An authenticated client can still send malicious XML if the server parses it unsafely. XXE mitigation requires secure parsing configuration that disables external entities and DTDs.
Can middleBrick detect XXE in endpoints protected by Mutual TLS?
middleBrick’s unauthenticated scan tests the public surface and can identify unsafe XML parsing patterns when present. For endpoints that require Mutual TLS, scans without client certificates may not trigger those paths. Use the middleBrick CLI or Dashboard to map findings to compliance frameworks and prioritize parsing hardening alongside certificate management.