CME-1317

XML External Entity Prevention (Secure XML Parser Configuration)

Description

Configures XML parsers to disable external entity resolution, DTD processing, and XInclude expansion, preventing XXE attacks that exploit default-permissive XML parser behavior to read local files, perform SSRF, or cause denial of service via entity expansion (billion laughs). Covers all major XML parsing APIs: Java (DocumentBuilderFactory, SAXParserFactory, XMLInputFactory with FEATURE_SECURE_PROCESSING and disallow-doctype-decl), Python (defusedxml, lxml with resolve_entities=False), .NET (XmlReaderSettings with DtdProcessing.Prohibit), PHP (libxml_disable_entity_loader), C/C++ (libxml2 without XML_PARSE_NOENT), and Go (xml.Decoder with strict mode). The control must be applied at parser instantiation — not as post-parse validation — because entity resolution occurs during parsing. When XML input is required but DTDs are needed for schema validation, use catalog-based resolution with a local-only catalog that rejects network fetches.

CVSS Vector Impacts

Metric Transition Rationale
Confidentiality (C) H → N External entity resolution is disabled at the parser level; the attacker cannot use file:// or http:// entity references to read local files or probe internal services because the parser rejects all external entity declarations before resolution occurs
Availability (A) H → N DTD processing is disabled, preventing entity expansion bombs (billion laughs) that cause exponential memory consumption; the parser rejects DOCTYPE declarations before recursive entity expansion begins

CWE Relationships

Verification

Verify that XML parsers are configured to disable external entities and DTD processing across all application languages in use

$ grep -rn 'FEATURE_SECURE_PROCESSING\|disallow-doctype-decl\|ACCESS_EXTERNAL_DTD\|ACCESS_EXTERNAL_SCHEMA\|IS_SUPPORTING_EXTERNAL_ENTITIES\|SUPPORT_DTD' <app_source>/
# Expected: Java XML parser configured with XXE-prevention features (external DTD/schema access disabled, entity support disabled)
Platform: any
$ grep -rn 'defusedxml\|resolve_entities.*False\|no_network.*True\|etree.XMLParser.*resolve_entities' <app_source>/
# Expected: Python XML parsing uses defusedxml or explicitly disables entity resolution
Platform: any
$ grep -rn 'DtdProcessing.Prohibit\|ProhibitDtd.*true\|XmlResolver.*null' <app_source>/
# Expected: .NET XML parsing prohibits DTD processing or sets XmlResolver to null
Platform: any
$ grep -rn 'libxml_disable_entity_loader' <app_source>/
# Expected: PHP XML parsing has external entity loading disabled via libxml_disable_entity_loader(true)
Platform: any
$ grep -rn 'LIBXML_NOENT\|XML_PARSE_NOENT' <app_source>/
# Expected: Zero matches — LIBXML_NOENT/XML_PARSE_NOENT enables entity substitution (misleading name) and is a vulnerability indicator, not a safety control
Platform: any
$ grep -rn 'xml\.NewDecoder\|xml\.Decoder\|encoding/xml' <app_source>/ | head -10
# Expected: Go XML parsing present — verify no external entity resolution configuration (Go xml.Decoder does not resolve external entities by default)
Platform: any
$ printf '<?xml version="1.0"?><!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/hostname">]><root>&xxe;</root>' | curl -s -o /dev/null -w '%{http_code}' -X POST -H 'Content-Type: application/xml' -d @- <app_endpoint>
# Expected: ^(400|403|422)$
Platform: any

Remediation

any Java XML parser XXE hardening (DocumentBuilderFactory / SAXParserFactory)

cat > <app_source>/src/main/java/com/example/SecureXmlParser.java << 'JAVA'
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.XMLConstants;
public class SecureXmlParser {
  public static DocumentBuilderFactory newSecureDocumentBuilderFactory() throws Exception {
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
    dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
    dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
    dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
    dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
    dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
    dbf.setXIncludeAware(false);
    dbf.setExpandEntityReferences(false);
    return dbf;
  }
}
JAVA
any Python XML parsing via defusedxml (drop-in safe replacement)

pip install defusedxml
find <app_source>/ -name '*.py' -exec sed -i 's/from xml\.etree import ElementTree/import defusedxml.ElementTree as ElementTree/g; s/import xml\.etree\.ElementTree/import defusedxml.ElementTree/g; s/from xml\.sax /from defusedxml.sax /g' {} +
linux ModSecurity WAF rule to block XXE payloads at the reverse proxy

printf 'SecRule REQUEST_BODY "<!DOCTYPE[^>]*(?:ENTITY|SYSTEM|PUBLIC)" "id:1317001,phase:2,deny,status:403,log,msg:XXE attempt blocked by CME-1317,severity:CRITICAL"
SecRule REQUEST_BODY "<!\[CDATA\[" "id:1317002,phase:2,deny,status:403,log,msg:CDATA injection blocked by CME-1317,severity:CRITICAL,chain"
SecRule REQUEST_HEADERS:Content-Type "(?:text|application)/xml" ""
' > /etc/httpd/modsecurity.d/local_rules/cme-1317-xxe-block.conf
apachectl configtest && apachectl graceful || { nginx -t && nginx -s reload; }
← CME-1316: Algorithmic Complexity Safeguards (Pattern/Regex Execution Limits) CME-1318: LDAP Injection Prevention →