HIGH xml external entitiesactixmutual tls

Xml External Entities in Actix with Mutual Tls

Xml External Entities in Actix 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 that an attacker can control. In Actix web applications that accept XML payloads, XXE can expose file contents, trigger SSRF, or lead to denial of service. When mutual TLS (mTLS) is used, the server authenticates the client via a client certificate before the application code runs. While mTLS protects transport-layer identity and reduces unauthorized access, it does not reduce the impact of a misconfigured XML parser. An authenticated client with a valid certificate can still send malicious XML, and because the server trusts the client certificate, the request may proceed with higher privileges or be forwarded internally, increasing the risk of successful XXE exploitation.

In Actix, developers often integrate XML deserialization using crates such as serde_xml_rs or quick-xml. If entity expansion and external DTD loading are not explicitly disabled, an attacker who can deliver an XML body (e.g., via an API endpoint that accepts configuration or document uploads) can define external entities that read local files like /etc/passwd or trigger http requests to internal services only reachable from the server. Even with mTLS ensuring that only trusted clients can connect, the server-side route handler must still treat the XML content as untrusted input. Without disabling DOCTYPE and external references, the combination of mTLS and XXE creates a scenario where strong client authentication coexists with a vulnerable parser, potentially allowing trusted clients to probe internal infrastructure or exfiltrate data through crafted entities.

Consider an Actix endpoint that receives an XML document to update a user profile. If the route does not sanitize or restrict XML features, an attacker with a valid client certificate can submit an XML payload with a SYSTEM entity pointing to file:///etc/shadow or an internal http://metadata service. The parser resolves the external reference and returns sensitive content, which may be logged or processed further. Because mTLS prevents unauthenticated scans, the attacker may perform targeted probing with valid credentials, relying on the server’s trust in the certificate to bypass network-level restrictions. Therefore, the presence of mTLS narrows the attacker surface to authenticated entities, but does not eliminate the need to secure XML processing, validate input, and enforce strict parser configurations to prevent XXE.

Mutual Tls-Specific Remediation in Actix — concrete code fixes

Remediation centers on disabling external entity resolution in the XML parser and ensuring mTLS is correctly enforced at the Actix layer. For XML parsing, avoid accepting DOCTYPE declarations and external DTDs. When using serde_xml_rs or quick-xml, configure the parser to reject external entities and to not resolve SYSTEM or PUBLIC identifiers. Treat XML input as untrusted regardless of mTLS status, and apply principle of least privilege to any downstream calls made with parsed data.

For mTLS in Actix, present the client certificate to your application for identity verification, but do not rely on it for input validation. Use the certificate details for authorization decisions, and ensure routes that accept XML payloads explicitly enforce feature restrictions in the parser. Below are concrete code examples for an Actix web service that enforces mTLS and safely handles XML input.

Example 1: Actix server with mTLS enabled and client certificate extraction. This configuration requires a client certificate for TLS handshakes, and extracts the peer certificate for logging or authorization. It does not, by itself, prevent XXE, so XML parsing must be secured separately.

use actix_web::{web, App, HttpResponse, HttpServer, Responder};
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};

fn create_ssl_config() -> std::io::Result {
    let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls())?;
    builder.set_private_key_file("key.pem", SslFiletype::PEM)?;
    builder.set_certificate_chain_file("cert.pem")?;
    // Require client certificate for mTLS
    builder.set_verify(openssl::ssl::SslVerifyMode::PEER | openssl::ssl::SslVerifyMode::FAIL_IF_NO_PEER_CERT, 
        openssl::ssl::SslVerifyCallback::new(|_, _| true));
    builder.check_private_key()?;
    Ok(builder.build())
}

async fn index() -> impl Responder {
    HttpResponse::Ok().body("API is running with mTLS")
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    let ssl_builder = create_ssl_config()?;
    HttpServer::new(move || {
        App::new()
            .wrap(actix_web_httpauth::middleware::HttpAuthentication::basic(|_req, credentials| {
                // placeholder: implement proper identity checks using cert info
                async { Ok(()) }
            }))
            .route("/", web::get().to(index))
    })
    .bind_openssl("127.0.0.1:8443", ssl_builder)?
    .run()
    .await
}

Example 2: Secure XML parsing with quick-xml that disables external entities and DOCTYPE. Ensure that the parser does not follow external references, preventing XXE when processing client-supplied XML.

use quick_xml::Reader;
use quick_xml::events::Event;
use std::io::Cursor;

fn parse_xml_safely(input: &str) -> Result<(), String> {
    let mut reader = Reader::from_reader(Cursor::new(input.as_bytes()));
    reader.trim_text(true);
    reader.expand_empty_elements(true);
    // Disable DTD and external entities explicitly
    reader.check_entities(false);
    let mut buf = Vec::new();
    loop {
        match reader.read_event(&mut buf) {
            Ok(Event::Eof) => break,
            Ok(_) => { /* process safe events */ }
            Err(e) => return Err(format!("XML error: {}", e)),
        }
        buf.clear();
    }
    Ok(())
}

// Example usage inside an Actix handler:
// async fn handle_xml(web::Bytes(bytes) : web::Bytes) -> impl Responder {
//     match parse_xml_safely(std::str::from_utf8(&bytes).unwrap_or_default()) {
//         Ok(_) => HttpResponse::Ok().finish(),
//         Err(e) => HttpResponse::BadRequest().body(e),
//     }
// }

Example 3: Combining mTLS identity extraction with safe XML handling. Use the client certificate to derive authorization context, but always treat XML content as untrusted. If you use serde_xml_rs, limit features and avoid reading external resources by pre-processing or using a secure fork with entity expansion disabled.

use actix_web::{web, Error, HttpResponse};
use openssl::x509::X509;

// Dummy: extract certificate from request extensions (set by TLS acceptor)
fn get_peer_cert(req: &actix_web::HttpRequest) -> Option {
    req.extensions().get::().cloned()
}

async fn submit_data(req: actix_web::HttpRequest, body: web::Bytes) -> Result {
    if let Some(cert) = get_peer_cert(&req) {
        // Use certificate subject for authorization
        let subject = cert.subject_name();
        // Proceed to safe XML parsing
        match parse_xml_safely(std::str::from_utf8(&body).unwrap_or_default()) {
            Ok(_) => Ok(HttpResponse::Ok().body("Processed")),
            Err(e) => Ok(HttpResponse::BadRequest().body(e)),
        }
    } else {
        Ok(HttpResponse::Forbidden().body("Client certificate required"))
    }
}

These examples emphasize that mTLS secures transport and provides client identity, but secure XML parsing requires disabling external entities and DOCTYPEs. Combine mTLS with parser hardening to reduce the attack surface for XXE in Actix services.

Frequently Asked Questions

Does mutual TLS prevent XML External Entity attacks?
No. Mutual TLS authenticates clients at the transport layer but does not affect XML parser behavior. XXE must be mitigated by disabling external entities and DOCTYPE processing in the XML parser.
How can I verify my Actix XML parsing is safe against XXE?
Test with an XML payload containing a SYSTEM external entity (e.g., ) and ensure the parser returns an error or does not resolve the reference. Confirm that DOCTYPE and external DTDs are disabled in your parser configuration.