How do I fix XXE?

Direct answer

Disable external entity resolution and DTD processing in your XML parser. Most parsers enable them by default, which means an uploaded XML file can read files off your server or make requests from it. In Python, use `defusedxml`; in Java, set the parser features; elsewhere, check the documentation rather than assuming.

Muhammad HasanUpdated

XML External Entity injection exploits a feature of XML: documents can define entities that reference external resources, and parsers will fetch them.

<?xml version="1.0"?>
<!DOCTYPE root [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
<root>&xxe;</root>

If the parser resolves that entity, the file's contents end up in the parsed document and often in the response.

The same mechanism reaches network resources, which makes XXE a route to SSRF. Including cloud metadata endpoints, and a way to cause denial of service through recursive entity expansion.

The fix by language

Python. Use defusedxml, which is a drop-in replacement with the dangerous features disabled:

from defusedxml.ElementTree import parse
tree = parse(uploaded_file)

Recent xml.etree versions are safer than they were, but defusedxml is unambiguous and easy to review.

Java, the parser needs configuring explicitly:

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
dbf.setXIncludeAware(false);
dbf.setExpandEntityReferences(false);

disallow-doctype-decl alone covers most of it by rejecting the DTD outright. The same applies to SAXParserFactory, XMLInputFactory and TransformerFactory. Each needs its own configuration.

.NET, modern XmlReader defaults are safe; set DtdProcessing = DtdProcessing.Prohibit explicitly and avoid legacy XmlTextReader.

Node. Most XML libraries don't resolve external entities by default. Check the specific library rather than assuming, particularly wrappers around libxml.

PHP, modern versions with libxml2 2.9+ disable it by default. libxml_disable_entity_loader(true) on older stacks.

Where XML arrives

Less common than it was, and still present: SOAP endpoints, SAML assertions in SSO flows, RSS and sitemap ingestion, SVG uploads, XML configuration import, office document formats, and anything speaking to a legacy system.

SAML is worth singling out. It's XML, it's security-critical, and it's parsed before authentication has happened.

Blind XXE

If the parsed content isn't reflected back, the bug is still exploitable, data can be exfiltrated through an out-of-band channel to a server the attacker controls. Absence of output in the response is not evidence of safety.

Better still, don't accept XML

Where a format is your choice rather than a protocol requirement, JSON has no equivalent mechanism. Reducing XML parsing to the places it's genuinely required removes the class of bug rather than configuring around it.

How to check what you've got

One of the classes scanners handle well. Parser instantiation without the safe features set is a recognisable pattern with a short dataflow. Grep for DocumentBuilderFactory, SAXParser, XMLInputFactory, etree.parse and simplexml_load.

Go deeper

Fast remediation with Kolega

Related answers

See what your own repository returns

Connect a repo and run a scan. No credit card, no pipeline changes.

Get started for free