Overview
XML External Entity (XXE) injection is a class of attack that targets XML parsers that are configured to process external entity declarations defined in a Document Type Definition (DTD). When an attacker can supply or influence XML input, they can define a custom entity that references an external resource — such as a local file path, an internal network endpoint, or a remote URL — and cause the parser to fetch and embed that resource into the parsed document.
XXE vulnerabilities exist because the XML 1.0 specification legitimately supports external entities for modularity purposes. Most modern applications have no business need for this feature, but many XML libraries enable it by default, creating an attack surface whenever user-controlled XML is parsed without explicit hardening.
Sensagraph automatically tests XML-accepting endpoints for XXE by injecting crafted DTD payloads and observing parser behavior, including out-of-band data exfiltration channels.
How it works
The XML specification allows documents to declare entities — named references that the parser replaces with content at parse time. External entities extend this by pointing the parser to an external resource using a URI:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<root>&xxe;</root>
If the parser resolves the external entity, the contents of /etc/passwd are substituted into the document body and potentially reflected back to the attacker in the server response.
Common XXE attack variants
- Classic (in-band) XXE: The resolved entity value is reflected directly in the application response, enabling straightforward file read.
- Error-based XXE: The parser triggers a parse error containing sensitive data, which leaks through error messages even when the response body is not reflected.
- Out-of-band (OOB) XXE / Blind XXE: The parser makes an outbound HTTP or DNS request carrying exfiltrated data to an attacker-controlled server, useful when the response is never shown to the attacker.
- SSRF via XXE: The external entity URI targets an internal network resource (e.g.,
http://169.254.169.254/latest/meta-data/on cloud instances), enabling server-side request forgery to reach services not accessible from the internet. - Billion Laughs (XML Entity Expansion / DoS): Nested entity references expand exponentially, exhausting parser memory and CPU — covered separately under CWE-776.
- XInclude attacks: When full DTD control is not available, attackers may use XInclude directives to include external files if the parser supports XInclude processing.
- XXE via file upload: File formats that are XML-based (SVG, DOCX, XLSX, ODT, RSS feeds) can carry malicious DTD declarations; the server parses them during file processing without the developer realising XML is involved.
Why parsers are vulnerable
- Many XML libraries (Java's
DocumentBuilderFactory, Python'sxml.etree/lxml, PHP'sSimpleXML/DOMDocument, .NET'sXmlDocument) enable external entity resolution by default or have historically done so. - Developers who are unaware that a component processes XML (e.g., a SAML library, an OpenDocument parser, or a SOAP framework) may not apply hardening to that component.
- Schema validation does not prevent XXE — the entity is resolved before schema validation occurs.
Business impact
A successful XXE attack can have severe consequences depending on the server environment and parser capabilities:
- Sensitive file disclosure: Reading system files such as
/etc/passwd, application configuration files, private keys, and credentials stored on the server filesystem. - Credential and secret theft: Source code, API keys, database connection strings, and cloud provider metadata service tokens are all reachable via local file URIs or SSRF.
- Internal network reconnaissance: SSRF via XXE allows attackers to probe internal hosts, enumerate open ports, and access services such as internal admin panels, Kubernetes APIs, or cloud metadata endpoints.
- Remote code execution: In specific configurations (e.g., PHP with
expect://URI support, or certain Java parsers), XXE can escalate to RCE. - Denial of service: Billion Laughs and similar payloads can crash or severely degrade the parser process.
- Compliance violations: Unauthorised access to personal data via XXE may constitute a breach under GDPR, HIPAA, PCI-DSS, or similar regulations, triggering notification obligations and potential fines.
How to fix it
-
Disable external entity processing in the XML parser (primary control): Configure the parser to reject external entities and DTD processing entirely. The exact API varies by language and library:
- Java (DocumentBuilderFactory): Set features
http://apache.org/xml/features/disallow-doctype-decltotrue, or disablehttp://xml.org/sax/features/external-general-entitiesandhttp://xml.org/sax/features/external-parameter-entities. - Python (lxml): Use
etree.XMLParser(resolve_entities=False, no_network=True)and avoidxml.etree.ElementTreefor untrusted input (it does not support disabling entities cleanly in older versions). - PHP: Call
libxml_disable_entity_loader(true)(PHP < 8.0) or useLIBXML_NOENTflags carefully; preferLIBXML_NONETto block network access. - .NET: Set
XmlReaderSettings.DtdProcessing = DtdProcessing.ProhibitandXmlReaderSettings.XmlResolver = null. - Node.js: Prefer libraries such as
fast-xml-parserwith entity expansion disabled; avoidlibxmljswith external entity support.
- Java (DocumentBuilderFactory): Set features
- Use less complex data formats where possible: If the use case does not require XML features such as mixed content or namespaces, replace XML with JSON, Protocol Buffers, or MessagePack, which have no concept of external entities.
- Apply allow-list input validation: Reject XML documents that contain a
DOCTYPEdeclaration unless your application has a specific, controlled need for it. This can be enforced at the application layer before passing input to the parser. - Keep XML libraries up to date: Library vendors regularly patch default-insecure entity-handling behaviour. Maintain a software composition analysis (SCA) process to track vulnerable versions.
- Disable XInclude processing: If your parser supports XInclude and you do not use it, explicitly disable it to prevent XInclude-based bypass of entity restrictions.
- Implement network-level controls: Even if XXE is exploited, egress filtering that blocks unexpected outbound connections from the application server limits the usefulness of out-of-band exfiltration and SSRF pivoting.
- Apply least privilege to the application process: The process running the XML parser should have read access only to files it needs. Use OS-level sandboxing (seccomp, AppArmor, containers with read-only mounts) to limit blast radius.
- Audit XML-consuming components: Inventory all places where XML is processed, including indirect paths such as SAML authentication libraries, office document converters, RSS parsers, and third-party integrations, and verify each is hardened.
References
- OWASP – XML External Entity (XXE) Processing
- OWASP Cheat Sheet – XXE Prevention
- OWASP Top 10 2021 – A05: Security Misconfiguration
- MITRE CWE-611 – Improper Restriction of XML External Entity Reference
- MITRE CWE-776 – Improper Restriction of Recursive Entity References in DTDs
- MITRE CWE-918 – Server-Side Request Forgery (SSRF)
- W3C XML 1.0 Specification – External Entities
- PortSwigger Web Security Academy – XXE Injection