XML External Entity

XML External Entity (XXE): How a Parser Reads /etc/passwd For You

An XML parser that resolves external entities will fetch any file or URL an attacker names. Here is how XXE turns a document upload into local file disclosure and SSRF, and the parser settings that stop it cold.

SelfSec Team3 min read
Part 1 of 4from theXML External Entityseries
<!ENTITY x SYSTEM "file:///etc/passwd">
On this page

XML is more powerful than most developers realise. Beyond elements and attributes, the format lets a document define entities — and external entities can point at files on disk or URLs on the network. XML external entity (XXE) injection abuses a parser that resolves those entities: by declaring one that references a local file or an internal address, an attacker makes the server read sensitive files, reach internal services, and exfiltrate data. The root cause is depressingly simple — many XML libraries enable external-entity and DTD processing by default.

This post shows how a single crafted document turns a routine XML endpoint into a file-disclosure and SSRF primitive, and how to configure the parser so it never happens.

How it happens

Anywhere an application accepts XML — SOAP services, SAML, document uploads, sitemaps, SVG, config import — it must parse it. The vulnerability appears when the parser is left at its default settings, which often resolve DOCTYPE-declared entities. Consider a Java endpoint that reads an uploaded XML order:

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(request.getInputStream());

String item = doc.getElementsByTagName("item").item(0).getTextContent();

This looks ordinary, and for well-formed orders it works fine. But DocumentBuilderFactory does not disable external entities by default. The parser will dereference any entity the document declares — including one that points outside the document entirely.

A concrete attack

Instead of a normal order, the attacker uploads an XML body with a DOCTYPE that defines an external entity pointing at a local file:

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

When the parser hits &xxe;, it resolves the entity by reading file:///etc/passwd and substitutes the file's contents into the element. Whatever the application does next with that element — echo it back, store it, include it in an error — now carries the file. The response body comes back containing:

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
...

The same technique swaps the target for an internal URL to turn the parser into a server-side request forger:

<!DOCTYPE foo [
  <!ENTITY xxe SYSTEM "http://169.254.169.254/latest/meta-data/">
]>
<foo>&xxe;</foo>

Now the server fetches cloud metadata on the attacker's behalf — credentials and all.

The attacker did not break the parser. They used a standard XML feature exactly as specified — the parser was simply configured to trust the document about which files and URLs to read.

What an attacker gains

XXE is a versatile primitive that opens several doors at once:

  • Local file disclosure — read /etc/passwd, source code, configuration files and application secrets directly off the server's disk.
  • Server-side request forgery — make the server hit internal-only services and cloud metadata endpoints (like 169.254.169.254) that are unreachable from outside.
  • Out-of-band exfiltration — with parameter entities and an attacker-hosted DTD, steal data even when the response shows nothing (blind XXE).
  • Denial of service — entity-expansion bombs can exhaust memory and CPU.

On many stacks, file disclosure alone hands over the keys: a leaked database password or cloud credential is enough to compromise far more than the XML endpoint.

The fix: disable DTDs and external entities in the parser

XXE is one of the rare classes with a clean, definitive fix: turn off the dangerous features at the parser. Since the application almost never needs DOCTYPEs or external entities, disable them outright. In Java:

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);

DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(request.getInputStream());

With disallow-doctype-decl set, the earlier payload is rejected before any entity is resolved — there is nothing to dereference. The same principle applies on every platform:

  • Disable DTD processing and external-entity resolution in whichever XML library you use; most expose a single flag or a secure-processing mode.
  • Prefer simpler data formats like JSON where you control the contract — they have no equivalent of external entities.
  • Keep XML libraries patched, since defaults and bypasses change between versions.

How SelfSec proves this one

Scanner behaviour
Module
XXE
How it probes
Submits external-entity and parameter-entity payloads to every XML-accepting endpoint the crawl finds, including SOAP and WSDL surfaces.
How it confirms
File-read evidence in the response, or an out-of-band entity fetch when the parser answers silently.

Reported as CWE-611 · ATT&CK T1190 · SARIF 2.1.0

A reflected response alone is not enough to promote a XML External Entity finding — the classical engine has to confirm the behaviour before it reaches the report. See the detection engine

SelfSec is intended strictly for authorized security testing of systems you own or are explicitly permitted to assess.

Do both things about XML External Entity

SelfSec covers this class from both sides — the scanner confirms it in your own app, the firewall blocks it in front of your origin while the fix ships.

The XML External Entity series

  1. 01OverviewXML External Entity (XXE): How a Parser Reads /etc/passwd For YouReading
  2. 02Blind / Out-of-BandBlind XXE: Exfiltrating Files With Out-of-Band Parameter Entities5 min
  3. 03Denial of ServiceBillion Laughs: Denial of Service Through XML Entity Expansion5 min
  4. 04File-Backed FormatsXXE in File Uploads: SVG, DOCX and Other XML-Backed Formats5 min

Related reading