Improper Restriction of XML External Entity Reference

Description

Improper Restriction of XML External Entity Reference (XXE) occurs when XML input containing a reference to an external entity is processed by a weakly configured XML parser. External entities can reference files on the system, internal network resources, or remote URLs. When XML parsers process these references without proper restrictions, attackers can read local files (including sensitive configuration files and credentials), perform server-side request forgery (SSRF) to access internal services, cause denial of service through recursive entity expansion ("Billion Laughs" attack), or potentially achieve remote code execution in certain configurations.

Risk

XXE vulnerabilities remain prevalent in enterprise applications that process XML data. Multiple IBM WebSphere Application Server vulnerabilities (CVE-2024-45086, CVE-2024-45072, CVE-2024-22354) enabled XXE attacks allowing file disclosure and SSRF. CVE-2025-11700 in N-able N-central allows low-privileged attackers to read arbitrary files. These vulnerabilities are particularly dangerous because they can access files outside the web root, including /etc/passwd, database credentials, and private keys. XXE can also be used to pivot into internal networks by making the vulnerable server request internal resources, effectively bypassing firewalls.

Solution

Disable external entity processing in XML parsers. For Java, disable DTDs entirely or set XMLConstants.FEATURE_SECURE_PROCESSING. For Python, use defusedxml library instead of standard XML libraries. For PHP, use libxml_disable_entity_loader(true). For .NET, set XmlReaderSettings.DtdProcessing to DtdProcessing.Prohibit. Use less complex data formats like JSON when XML features aren't needed. Validate and sanitize XML input. Implement network segmentation to limit SSRF impact. Use allowlisting for any required external entities.

Common Consequences

ImpactDetails
ConfidentialityScope: File Disclosure

Attackers can read arbitrary files on the server, including configuration files, credentials, and source code.
IntegrityScope: Server-Side Request Forgery

Attackers can make requests to internal services, accessing resources not exposed to the internet.
AvailabilityScope: Denial of Service

Recursive entity expansion (Billion Laughs) can consume all available memory, crashing the server.

Example Code + Solution Code

Vulnerable Code

// VULNERABLE: Default XML parser settings allow XXE
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;

public class XMLProcessor {
    public Document parseXML(String xmlInput) throws Exception {
        // Default factory allows external entities!
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        return builder.parse(new InputSource(new StringReader(xmlInput)));
    }
}

// Attacker sends:
// <?xml version="1.0"?>
// <!DOCTYPE foo [
//   <!ENTITY xxe SYSTEM "file:///etc/passwd">
// ]>
// <root>&xxe;</root>
# VULNERABLE: Standard library XML parsers are unsafe
from xml.etree import ElementTree

def parse_xml(xml_string):
    # ElementTree is vulnerable to XXE by default
    root = ElementTree.fromstring(xml_string)
    return root

# VULNERABLE: lxml with dangerous parser settings
from lxml import etree

def parse_xml_lxml(xml_string):
    # Default lxml parser resolves external entities
    parser = etree.XMLParser()
    root = etree.fromstring(xml_string.encode(), parser)
    return root
<?php
// VULNERABLE: SimpleXML and DOMDocument are unsafe by default
function parseXML($xmlString) {
    // External entities are processed!
    $xml = simplexml_load_string($xmlString);
    return $xml;
}

// Attacker can read files:
// <?xml version="1.0"?>
// <!DOCTYPE data [
//   <!ENTITY xxe SYSTEM "file:///etc/passwd">
// ]>
// <data>&xxe;</data>
?>

Fixed Code

// SAFE: Disable external entities and DTDs
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.XMLConstants;

public class SecureXMLProcessor {
    public Document parseXMLSafe(String xmlInput) throws Exception {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

        // Disable DTDs entirely
        factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);

        // Or disable external entities specifically
        factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
        factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
        factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);

        // Enable secure processing
        factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);

        // Disable XInclude
        factory.setXIncludeAware(false);
        factory.setExpandEntityReferences(false);

        DocumentBuilder builder = factory.newDocumentBuilder();
        return builder.parse(new InputSource(new StringReader(xmlInput)));
    }
}

// SAFE: SAX parser with security features
import org.xml.sax.XMLReader;
import javax.xml.parsers.SAXParserFactory;

public XMLReader createSecureSAXReader() throws Exception {
    SAXParserFactory factory = SAXParserFactory.newInstance();
    factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
    factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
    factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
    factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);

    return factory.newSAXParser().getXMLReader();
}
# SAFE: Use defusedxml library
import defusedxml.ElementTree as ET

def parse_xml_safe(xml_string):
    # defusedxml blocks external entities by default
    root = ET.fromstring(xml_string)
    return root

# SAFE: Configure lxml to block external entities
from lxml import etree

def parse_xml_lxml_safe(xml_string):
    # Disable network access and entity resolution
    parser = etree.XMLParser(
        resolve_entities=False,
        no_network=True,
        dtd_validation=False,
        load_dtd=False
    )
    root = etree.fromstring(xml_string.encode(), parser)
    return root

# SAFE: Use defusedxml for all XML operations
from defusedxml import defuse_stdlib
defuse_stdlib()  # Patches standard library XML modules

# Now even standard library is safer
from xml.etree import ElementTree
root = ElementTree.fromstring(xml_string)  # Safer after defuse_stdlib()
<?php
// SAFE: Disable entity loading before parsing
function parseXMLSafe($xmlString) {
    // Disable external entity loading
    $previousValue = libxml_disable_entity_loader(true);

    // Use LIBXML_NOENT to not substitute entities
    // and LIBXML_DTDLOAD to not load external DTD
    $options = LIBXML_NONET | LIBXML_NOENT;

    // Suppress errors and handle them explicitly
    libxml_use_internal_errors(true);

    $xml = simplexml_load_string($xmlString, 'SimpleXMLElement', $options);

    // Restore previous setting
    libxml_disable_entity_loader($previousValue);

    if ($xml === false) {
        throw new Exception('Invalid XML');
    }

    return $xml;
}

// SAFE: DOMDocument with security settings
function parseXMLDOMSafe($xmlString) {
    libxml_disable_entity_loader(true);

    $dom = new DOMDocument();
    $dom->loadXML($xmlString, LIBXML_NONET | LIBXML_NOENT);

    return $dom;
}

// SAFE: Best practice - validate against schema
function parseXMLWithValidation($xmlString, $schemaPath) {
    libxml_disable_entity_loader(true);

    $dom = new DOMDocument();
    $dom->loadXML($xmlString, LIBXML_NONET | LIBXML_NOENT);

    if (!$dom->schemaValidate($schemaPath)) {
        throw new Exception('XML validation failed');
    }

    return $dom;
}
?>

Exploited in the Wild

IBM WebSphere Application Server (IBM, 2024)

CVE-2024-45086, CVE-2024-45072, and CVE-2024-22354 in IBM WebSphere Application Server allow XXE attacks enabling sensitive information disclosure, memory consumption, and SSRF attacks against internal services.

N-able N-central (N-able, 2025)

CVE-2025-11700 in N-able N-central versions before 2025.4 allows low-privileged attackers to craft malicious XML that reads arbitrary files, exposing sensitive configuration and credential information.

Eclipse JGit (Eclipse, 2025)

XXE vulnerability in Eclipse JGit affected Elastic Enterprise Search and Elasticsearch, demonstrating supply chain impact when vulnerable XML processing exists in widely-used libraries.


Tools to test/exploit


CVE Examples


References

  1. MITRE. "CWE-611: Improper Restriction of XML External Entity Reference." https://cwe.mitre.org/data/definitions/611.html

  2. OWASP. "XML External Entity (XXE) Processing." https://owasp.org/www-community/vulnerabilities/XML_External_Entity_(XXE)_Processing