OWASP Cheat Sheet Series: XML External Entity Prevention Cheat Sheet

# XML External Entity Prevention Cheat Sheet

## Introduction

An *XML eXternal Entity injection* (XXE), which is now part of the [OWASP Top 10](https://owasp.org/www-project-top-ten/OWASP_Top_Ten_2017/Top_10-2017_A4-XML_External_Entities_%28XXE%29) via the point **A4**, is attack against applications that parse XML input. This issue is referenced in the ID [611](https://cwe.mitre.org/data/definitions/611.html) in the [Common Weakness Enumeration](https://cwe.mitre.org/index.html) referential. An XXE attack occurs when untrusted XML input with a **reference to an external entity is processed by a weakly configured XML parser**, and this attack could be used to stage multiple incidents, including:

- A denial of service attack on the system
- A [Server Side Request Forgery](https://owasp.org/www-community/attacks/Server_Side_Request_Forgery) (SSRF) attack
- The ability to scan ports from the machine where the parser is located
- Other system impacts.

This cheat sheet will help you prevent this vulnerability.

For more information on XXE, please visit [XML External Entity (XXE)](https://en.wikipedia.org/wiki/XML_external_entity_attack).

## General Guidance

**The safest way to prevent XXE is always to disable DTDs (External Entities) completely.** Depending on the parser, the method should be similar to the following:

``` java
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
```

Disabling [DTD](https://www.w3schools.com/xml/xml_dtd.asp)s also makes the parser secure against denial of services (DOS) attacks such as [Billion Laughs](https://en.wikipedia.org/wiki/Billion_laughs_attack). **If it is not possible to disable DTDs completely, then external entities and external document type declarations must be disabled in the way that's specific to each parser.**

### XML Parser Security Features Matrix

| Security Feature                                | Default (Parser-Dependent)  | Purpose                                               | **What Happens If Missing?**                              |
| ----------------------------------------------- | --------------------------- | ----------------------------------------------------- | --------------------------------------------------------- |
| **External Entities Disabled**                  | Usually **disabled** (safe) | Blocks external resource loading                      | Full XXE possible → SSRF, file disclosure, internal scans |
| **Disallow DOCTYPE Declaration**                | Varies                      | Prevents ENTITY definitions                           | Classic XXE payloads become fully functional              |
| **Disable External DTD Loading**                | Usually **disabled**        | Stops loading remote DTDs                             | Enables Blind XXE, SSRF behind firewalls                  |
| **Secure Processing Mode**                      | Varies                      | Restricts recursion, network access, entity expansion | Billion Laughs DoS and resource depletion become possible |
| **Disable Parameter Entities**                  | Varies                      | Prevents `%entity;` injections                        | Advanced XXE payloads bypass simple protections           |
| **XInclude Disabled**                           | Usually **disabled**        | Prevents including external files                     | File read via `file://` and SSRF becomes possible         |
| **Limit Entity Expansion Count**                | Usually **enabled**         | Prevents recursive entity abuse                       | Memory exhaustion → parser or server DoS                  |
| **Schema Validation Without External Fetching** | Usually safe                | Ensures validation does not fetch external URLs       | Silent external HTTP calls triggered during validation    |

### Quick Impact Matrix (What Happens If Missing?)

| Missing Control                         | Resulting Vulnerability                      |
| --------------------------------------- | -------------------------------------------- |
| DOCTYPE not disabled                    | Standard XXE fully exploitable               |
| External entities enabled               | SSRF, file exfiltration, port scanning       |
| External DTD loading allowed            | Blind XXE → hidden SSRF attacks              |
| No expansion limits                     | Billion Laughs DoS                           |
| XInclude enabled                        | Local file disclosure + SSRF                 |
| Secure processing disabled              | Critical protections bypassed                |
| Schema validation fetches external URLs | Application makes unwanted outbound requests |

### Minimal XML Hardening Rules

- Disable DOCTYPE
- Disable external entities
- Disable external DTD loading
- Enable secure processing mode
- Disable XInclude
- Limit entity expansion
- Do not use legacy XML parsers
- Never parse untrusted XML with default settings

**Detailed XXE Prevention guidance is provided below for multiple languages (C++, Cold Fusion, Java, .NET, iOS, PHP, Python, Semgrep Rules) and their commonly used XML parsers.**

## C/C++

### libxml2

The Enum [xmlParserOption](http://xmlsoft.org/html/libxml-parser.html#xmlParserOption) should not have the following options defined:

- `XML_PARSE_NOENT`: Expands entities and substitutes them with replacement text
- `XML_PARSE_DTDLOAD`: Load the external DTD

Note:

Per: According to [this post](https://mail.gnome.org/archives/xml/2012-October/msg00045.html), starting with libxml2 version 2.9, XXE has been disabled by default as committed by the following [patch](https://gitlab.gnome.org/GNOME/libxml2/commit/4629ee02ac649c27f9c0cf98ba017c6b5526070f).

Search whether the following APIs are being used and make sure there is no `XML_PARSE_NOENT` and `XML_PARSE_DTDLOAD` defined in the parameters:

- `xmlCtxtReadDoc`
- `xmlCtxtReadFd`
- `xmlCtxtReadFile`
- `xmlCtxtReadIO`
- `xmlCtxtReadMemory`
- `xmlCtxtUseOptions`
- `xmlParseInNodeContext`
- `xmlReadDoc`
- `xmlReadFd`
- `xmlReadFile`
- `xmlReadIO`
- `xmlReadMemory`

### libxerces-c

Use of `XercesDOMParser` do this to prevent XXE:

``` cpp
XercesDOMParser *parser = new XercesDOMParser;
parser->setCreateEntityReferenceNodes(true);
parser->setDisableDefaultEntityResolution(true);
```

Use of SAXParser, do this to prevent XXE:

``` cpp
SAXParser* parser = new SAXParser;
parser->setDisableDefaultEntityResolution(true);
```

Use of SAX2XMLReader, do this to prevent XXE:

``` cpp
SAX2XMLReader* reader = XMLReaderFactory::createXMLReader();
parser->setFeature(XMLUni::fgXercesDisableDefaultEntityResolution, true);
```

## ColdFusion

Per [this blog post](https://hoyahaxa.blogspot.com/2022/11/on-coldfusion-xxe-and-other-xml-attacks.html), both Adobe ColdFusion and Lucee have built-in mechanisms to disable support for external XML entities.

### Adobe ColdFusion

As of ColdFusion 2018 Update 14 and ColdFusion 2021 Update 4, all native ColdFu