HIGH xml external entitiesactixjwt tokens

Xml External Entities in Actix with Jwt Tokens

Xml External Entities in Actix with Jwt Tokens — how this specific combination creates or exposes the vulnerability

XML External Entity (XXE) injection occurs when an XML parser processes external entity references within untrusted XML data. In Actix web applications that accept XML payloads—such as SAML metadata or legacy SOAP integrations—misconfigured XML readers can be tricked to read local files, perform SSRF requests, or disclose internal service endpoints. When JWT tokens are involved, the interaction typically arises in two scenarios. First, an API endpoint might accept an XML body that includes a JWT token as an embedded claim or as a value inside an XML element; if the XML parser resolves external entities, an attacker can leverage this to exfiltrate the JWT or use it to infer validation behavior. Second, an endpoint that receives a JWT in an Authorization header might still parse an uploaded XML document (for example, during federation or configuration import), and a malicious XXE payload can be chained to probe internal endpoints that rely on the JWT for authorization.

Consider an Actix service that deserializes an XML upload containing a JWT claim for authorization context. If the XML parser is configured to resolve DOCTYPE external entities, an attacker can supply an XML such as <!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/hostname" >]> and include a token element holding a captured JWT. The XXE can read files on the server and, depending on how the application uses the JWT, may gain insights into token structure or trigger error messages that leak the JWT content. Even when the JWT itself is not directly extracted, the attacker can use XXE to make the server perform SSRF requests to internal services that require a valid JWT, effectively chaining the weaknesses. Because Actix applications often use typed extractors for headers and bodies, a developer might focus on validating the JWT signature and overlook that an XML body is parsed before authorization checks are applied, creating a path for unauthenticated attackers to exploit the combined attack surface.

The impact is elevated when the JWT is used to convey authorization decisions that the server trusts after verifying its signature. An XXE that reads configuration files may reveal locations of public keys or JWKS endpoints used to validate the JWT, simplifying token forgery. Moreover, if the Actix runtime logs raw XML or token values verbosely, XXE can be used to manipulate log entries and hide follow-up attacks. Because the vulnerability spans parsing logic (XML), transport (HTTP headers with JWT), and authorization (claims-driven access), remediation must address each layer without assuming that a valid JWT alone guarantees safe processing of untrusted XML.

Jwt Tokens-Specific Remediation in Actix — concrete code fixes

Remediation focuses on disabling external entity resolution for XML parsers, validating JWTs using robust libraries, and ensuring that XML processing does not interfere with token-based authorization. Below are concrete Actix snippets that illustrate a secure approach.

1) Use a non-XML parser or strict DTD handling. If you do not need DTDs, avoid XML libraries that enable external entity resolution. For JSON-based workflows, prefer JSON deserializers instead.

// In Cargo.toml, prefer serde_json for JWT claims when possible
dependencies = [
    "actix-web = "4",
    "serde = { version = "1.0", features = ["derive"] }",
    "serde_json = "1.0",
    "jsonwebtoken = "9",
]

2) If XML is required, configure the parser to prohibit external entities. For example, using the roxmltree crate which does not resolve external entities by design:

use actix_web::{web, HttpResponse};
use roxmltree::Document;

async fn handle_xml_jwt(body: String) -> HttpResponse {
    // Parse without external entity expansion
    let doc = match Document::parse(&body) {
        Ok(d) => d,
        Err(_) => return HttpResponse::BadRequest().body("Invalid XML"),
    };
    // Example: extract a <token> element safely
    let token_node = doc.descendants().find(|n| n.has_tag_name("token"));
    let token = match token_node {
        Some(n) => n.text().unwrap_or(""),
        None => return HttpResponse::BadRequest().body("Missing token"),
    };
    // Validate JWT using jsonwebtoken crate
    use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation};
    let validation = Validation::new(Algorithm::HS256);
    match decode::(&token, &DecodingKey::from_secret("secret".as_ref()), &validation) {
        Ok(token_data) => HttpResponse::Ok().json(token_data.claims),
        Err(_) => HttpResponse::Unauthorized().body("Invalid token"),
    }
}

3) When you must accept XML with external references, enforce a secure XML2 configuration that disables DTD and entity expansion. With the xml-rs crate, avoid default readers that enable external entities:

use actix_web::{web, HttpResponse};
use xml::reader::{EventReader, XmlEvent};
use std::io::Cursor;

async fn handle_xml_with_entities(body: String) -> HttpResponse {
    let cursor = Cursor::new(body.as_bytes());
    let parser = EventReader::new(cursor);
    for event in parser {
        match event {
            Ok(XmlEvent::StartElement { name, .. }) if name.local_name == "token" => {
                // Read token content carefully; do not resolve external entities
                // In a full implementation, you would collect character data here
            }
            Err(e) => return HttpResponse::BadRequest().body(format!("XML error: {}", e)),
            _ => {}
        }
    }
    // Continue with JWT validation as shown above
    HttpResponse::Ok().body("Processed")
}

4) Always validate and verify JWTs before acting on any data derived from XML. Use a well-maintained library and enforce expected algorithms, issuer, and audience claims to prevent token substitution regardless of XML behavior:

use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation, TokenData};
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
struct Claims {
    sub: String,
    exp: usize,
    // add other expected claims
}

fn validate_jwt(token: &str) -> Result<TokenData<Claims>, jsonwebtoken::errors::Error> {
    let mut validation = Validation::new(Algorithm::HS256);
    validation.validate_exp = true;
    validation.set_issuer(&["trusted-issuer"]);
    validation.set_audience(&["my-api"]);
    decode::(&token, &DecodingKey::from_secret("secret".as_ref()), &validation)
}

5) Apply defense in depth: restrict file permissions so that even if an attacker can read files via XXE, the JWT material is not stored in world-readable locations, and ensure logs redact JWT values. Combine input validation on XML content with runtime monitoring for anomalous entity expansion attempts.

Frequently Asked Questions

Can a valid JWT prevent XXE exploitation in Actix?
No. A valid JWT relates to authorization, while XXE is a parsing flaw. An attacker can still read files or perform SSRF regardless of token validity; secure XML parsing is required independently.
Does middleBrick detect XXE risks involving JWT tokens?
middleBrick scans unauthenticated attack surfaces and includes checks for SSRF and data exposure patterns. If your API accepts XML and references JWTs in ways that enable entity expansion, findings may surface related data exposure and injection risks in the report.