Safeguard
Application Security•

CWE-611 XXE: How XML External Entities Leak Files and Fix

An XML parser that resolves external entities can read local files, make server-side requests, and burn CPU. How XXE works and the parser settings that stop it.

Safeguard Security Team
4 min read

CWE-611 is XML External Entity injection, usually shortened to XXE. The product processes an XML document that can contain entities with URIs that resolve to documents outside the intended sphere of control, and so embeds the wrong documents in its output.

Anything that parses XML from outside can be hit: SOAP services, SVG and Office file converters, feed readers, SAML handlers, and import features. It is also a dependency problem, since the parser that ships inside a library decides your exposure.

How it happens

XML lets a document declare an entity and point it at a URI. If the parser's default entity resolver is on, it fetches whatever the URI names.

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

If the application echoes any part of the parsed document back, the file contents come with it.

// Vulnerable pattern: default parser settings
DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document d = db.parse(request.getInputStream());

MITRE lists several observed cases.

  • CVE-2022-42745: recruiter software allowed reading arbitrary files using XXE.
  • CVE-2012-5656: XXE during SVG image conversion.
  • CVE-2012-2239: XXE in a PHP application allowed reading the application's configuration file.
  • CVE-2005-1306: a browser control could let remote attackers determine whether files exist via JavaScript containing XML script.

What an attacker gains

The record describes three kinds of impact.

  • File disclosure. With a crafted DTD and a default entity resolver enabled, an attacker may read arbitrary files on the system by defining an external entity with a file URI.
  • Outbound requests. Using schemes such as http, an attacker can force the application to make outgoing requests to servers they cannot reach directly. That can bypass firewall restrictions, hide the source of attacks, or probe internal systems.
  • Denial of service. A URI pointing at a large file or a device that always returns data, such as /dev/random, can consume excessive CPU or memory.

How to find it

Static analysis (SAST) can find some instances by modelling data flow into XML parsers. Review is simple in principle: find each XML parser construction in your code and confirm DTD and external entity handling are disabled.

Also look at what you ship. Third party libraries parse XML on your behalf, so a dependency scan tells you which parser versions and libraries are present. Safeguard has a free in-browser dependency scan at gold.safeguard.sh/scan that needs no login, keeps the file on your machine, and handles up to 100 dependencies.

To test a live endpoint, submit a document with an entity that points at a harmless file you control and see whether the content is echoed or the request is made.

Click through it at your own pace, or open it full screen.

How to fix it

MITRE's mitigation is to configure the parser: many XML parsers and validators can be set to disable external entity expansion. Do this during implementation and system configuration.

DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
f.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
f.setFeature("http://xml.org/sax/features/external-general-entities", false);
f.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
f.setXIncludeAware(false);
f.setExpandEntityReferences(false);
# Python: defusedxml refuses entity tricks by default
from defusedxml.ElementTree import fromstring
tree = fromstring(untrusted_xml)

Steps to apply across a codebase:

  1. Inventory every XML parser, including those inside libraries and converters.
  2. Turn off DTDs entirely if you do not need them, since that removes the whole class.
  3. If you do need DTDs, disable external entities and external parameter entities.
  4. Limit what the process can read and which hosts it can reach, so a miss does less harm.
  5. Keep parser libraries current, because defaults have changed over time.

Quick check

Why can XXE reach internal systems? The parser makes the request from the server. An attacker can point an entity at an internal address and use the application as a proxy.

What is the strongest single fix? Disable DTD processing, or at least external entity expansion, in the XML parser configuration.

Sources

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.