Defending Against XXE
XXE is almost always a parser-configuration problem, not a coding one: the application hands attacker-controlled XML to a library whose external-entity and DTD processing is switched on. That makes it one of the easier classes to shut cleanly - turn those features off in the parser (ideally disable DTDs entirely), keep the library current, and the file-read/SSRF/DoS primitives in this cluster simply stop resolving.
1. Disable DTDs and external entities in the parser
Section titled “1. Disable DTDs and external entities in the parser”The complete fix. Configure the XML parser to reject document type definitions; if the app legitimately needs DTDs, you must then disable external general entities, external parameter entities, and external DTD loading - the last one matters, because an allowed DOCTYPE can still pull in an external DTD (an outbound fetch / SSRF, and the carrier for blind parameter-entity exfil) even with the entity flags off. The exact switch is per-library - use the official setting, don’t hand-roll:
// Java - the strongest single switch: forbid DOCTYPE entirelyDocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
// If DOCTYPE MUST be allowed, drop the line above and instead disable all three:dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); // external DTD fetch (SSRF)dbf.setXIncludeAware(false);dbf.setExpandEntityReferences(false);// JAXP belt-and-braces: forbid any external accessdbf.setAttribute(javax.xml.XMLConstants.ACCESS_EXTERNAL_DTD, "");dbf.setAttribute(javax.xml.XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");Equivalents:
- Python: parse with
defusedxmlinstead of the stdlib (xml.etree,lxmlwith resolvers) - it disables entities and DTDs by default. - .NET: on
XmlReaderSettings, setDtdProcessing = DtdProcessing.Prohibit(the default on modern framework versions); don’t set anXmlResolver. - PHP (libxml): avoid the deprecated
libxml_disable_entity_loader()dance - on modern libxml (2.9+) external entities are off by default; don’t re-enable them withLIBXML_NOENT. - libxml2 generally: don’t pass
XML_PARSE_NOENT/XML_PARSE_DTDLOAD.
Harden all of: custom DTDs, external general and parameter entities, external DTD loading (the SSRF/blind-exfil carrier when DOCTYPE is permitted), XInclude, and entity-reference expansion (the last blocks billion-laughs entity-expansion DoS).
2. Keep XML libraries and components current
Section titled “2. Keep XML libraries and components current”Because XXE is a library-behaviour issue, patching is unusually effective here:
- Modern parsers increasingly disable external entities by default (libxml 2.9+, recent .NET); an out-of-date library is often the whole reason a target is vulnerable.
- This extends to everything that parses XML downstream: SOAP stacks, SVG/image and document processors, and transitive dependencies. Keep them patched alongside the core parser.
3. Don’t leak parser errors
Section titled “3. Don’t leak parser errors”Error-based XXE (blind exfil) exfiltrates file contents through parser error messages. Disable runtime/verbose error display in production and return generic errors, so a forced parse failure can’t carry data back.
4. Reduce the attack surface and add depth
Section titled “4. Reduce the attack surface and add depth”- Prefer JSON where a format choice exists; dropping XML (and XML-based APIs like SOAP) removes the class outright for that endpoint.
- WAF can block classic
<!DOCTYPE ... <!ENTITYpatterns - a secondary layer that is evadable, never the fix. - Egress controls: blocking outbound traffic from the app server limits blind/OOB exfil and SSRF even if a parser is misconfigured.
For the report
Section titled “For the report”- Primary: disable DTD processing (or, if DOCTYPE must stay, external general + parameter entities, external DTD loading, and XInclude) in every XML parser the app uses, via the library’s official setting; prefer a hardened wrapper like
defusedxml. - Coverage: apply it to every XML sink - SOAP, SVG/image, document, and PDF processors included, not just the obvious endpoint.
- Patch: update XML libraries and XML-consuming components to current versions.
- Containment: suppress verbose parser errors; restrict the app server’s outbound network access; WAF as a secondary layer.
Avoid presenting a WAF rule as the fix - the parser configuration is the fix; the WAF only buys time.
Related
Section titled “Related”- Identifying - the entity-processing signals this configuration removes
- Blind exfil - why suppressing parser errors matters
- Uploads: limited uploads - the SVG/document parsers that also need hardening