Safeguard
Vulnerability Guides

What Is XXE (XML External Entity Injection)?

XXE abuses an XML parser's ability to load external entities to read local files, reach internal services, or knock a server offline. Here is how to stop it.

Daniel Osei
Security Researcher
Updated 5 min read

XML External Entity injection (XXE) is a vulnerability that arises when an application parses XML input with a parser that is configured to resolve external entities. By defining a malicious entity inside the document's Document Type Definition (DTD), an attacker can force the parser to read local files, open network connections to internal systems (server-side request forgery), or exhaust memory and crash the service. It is catalogued as CWE-611 and sits inside the A05:2021 – Security Misconfiguration category of the OWASP Top 10. In practical terms, an XXE XML attack turns the parser's own entity-resolution feature into a weapon.

The core problem is a default that made sense in 1998 and is dangerous today: many XML libraries resolve external entities out of the box. XXE has driven real incidents for years — CVE-2019-9670, an XXE flaw in Zimbra Collaboration Suite's mailbox component, was chained into full remote code execution and exploited in the wild against enterprise mail servers. Any endpoint that accepts XML — SOAP APIs, SAML assertions, SVG uploads, XML-based document formats, RSS ingestion — is a candidate.

How an XXE XML Attack Works

XML lets a document declare entities, which are placeholders the parser expands when it reads the document. Internal entities are harmless string substitutions. External entities tell the parser to fetch content from a URI — a file path or a URL — and inline it. When user-controlled XML reaches a parser that honors those external references, the attacker controls what gets fetched.

The canonical file-disclosure payload declares an entity that points at a local file and then references it in an element the response will echo back:

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

If the application reflects the parsed data value anywhere in its response, the contents of /etc/passwd come back with it. Swap the file:// URI for http://169.254.169.254/latest/meta-data/ and the same bug becomes an SSRF that reaches a cloud metadata endpoint and steals instance credentials. A third variant, the "billion laughs" attack (CWE-776), nests entities that expand exponentially to consume gigabytes of memory and cause denial of service. Even when the app returns nothing useful, blind XXE exfiltrates data over an out-of-band channel by making the parser call back to an attacker-controlled server.

Vulnerable vs. Fixed

The fix is not to sanitize the XML — it is to configure the parser to refuse external entities and DTDs entirely.

// VULNERABLE: default DocumentBuilderFactory resolves external entities
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(userSuppliedXmlStream); // XXE reachable here
// FIXED: disable DTDs outright — the strongest single control
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(userSuppliedXmlStream); // entities no longer resolved

Setting disallow-doctype-decl to true is the highest-value control: if the parser rejects any document containing a DTD, every entity-based attack disappears at once. The remaining flags are belt-and-suspenders for parsers or workflows that legitimately need a DTD.

Prevention Checklist

  • Disable DTD processing wherever you accept untrusted XML — this alone stops classic and blind XXE.
  • Turn off external general and parameter entities if you cannot disable DTDs completely.
  • Prefer simpler data formats like JSON where XML is not required, removing the attack surface entirely.
  • Patch and pin XML libraries, since default hardening has changed across versions of libxml2, Xerces, and language runtimes.
  • Validate uploads that are secretly XML, such as SVG, DOCX, and SOAP bodies, through the same hardened parser.
  • Apply egress controls so a parser that is tricked into SSRF still cannot reach cloud metadata or internal hosts.

How Safeguard Detects XXE

XXE lives in two places: your own parser configuration and the third-party libraries that do the parsing. Safeguard's software composition analysis inventories every XML-handling dependency and flags versions with known entity-resolution CVEs, so you learn immediately if a transitive library ships unsafe defaults. On the runtime side, the dynamic testing engine submits benign out-of-band XXE probes to XML endpoints and watches for the tell-tale callback that proves a parser resolved an external entity — evidence, not conjecture.

When a finding lands, automated remediation proposes the exact parser-hardening flags for your language and opens a pull request, and you can gate merges by running the Safeguard CLI in your pipeline so an unhardened parser never ships. If you are comparing dependency-scanning depth, our Snyk comparison covers how transitive parser risk is surfaced.

Frequently Asked Questions

Is XXE still relevant if I use modern frameworks? Yes. While many current libraries ship safer defaults, plenty of enterprise stacks, SOAP services, and document-processing pipelines still enable DTDs. Configuration drift, legacy parsers, and copy-pasted setup code keep XXE alive in 2026.

Can XXE happen without file disclosure? Absolutely. Blind XXE exfiltrates data over out-of-band channels, and entity-expansion variants cause denial of service without reading a single file. The SSRF variant — reaching internal or cloud-metadata endpoints — is often the most damaging outcome.

Does input validation stop XXE? Not reliably. Attackers can encode payloads, use parameter entities, or hide DTDs in nested formats. The durable fix is disabling DTD and external-entity processing in the parser itself, not trying to filter malicious XML.


Want to know whether any XML parser in your stack still resolves external entities? Create a free account or follow the parser-hardening guide in the Safeguard docs.

Never miss an update

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