Preventing XML Bomb Attacks with Entity Depth Limits
XML entity expansion depth limits are a critical security mechanism designed to stop denial-of-service (DoS) attacks caused by recursive XML bombs, such as the Billion Laughs attack. This article explains the mechanics of recursive entity vulnerabilities, how modern XML parsers implement depth and count thresholds to intercept nested payloads, and the configuration practices required to secure XML processing pipelines against resource exhaustion.
The Mechanics of an XML Bomb
An XML bomb exploits the Document Type Definition (DTD) feature that allows users to declare custom entities. In a classic Billion Laughs attack, a series of entities are defined hierarchically:
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
]>
<root>&lol3;</root>When the parser encounters &lol3;, it resolves it to
ten instances of &lol2;, which each resolve to ten
instances of &lol1;, continuing down to
&lol;. While the original XML payload is only a few
hundred bytes, the fully expanded text grows exponentially, consuming
gigabytes of memory and CPU cycles until the server crashes.
How Parsers Track Entity Expansion Depth
XML parsers monitor and restrict recursive entity resolution through internal counters during the tokenization and parsing phases:
- Stack Depth Tracking: When an entity contains references to other entities, the parser increments a depth counter for each level of nesting. If the nesting exceeds a predetermined threshold (often between 10 and 20 levels), the parser immediately aborts processing and throws a fatal parse error.
- Total Entity Count Limits: Depth limits alone cannot prevent all attacks; a shallow payload referencing thousands of small, non-nested entities can still consume excessive resources (known as a Quadratic Blowup attack). Parsers counteract this by maintaining a cumulative count of expanded entities across the entire document.
- Cumulative Size Monitoring: Some parsers monitor the ratio of raw input size to expanded character size. If the expansion ratio exceeds a safety threshold (such as 100:1) or a hard byte limit, processing is halted.
Implementation Across Common Parsers
Different programming environments implement entity expansion defenses natively or through security features:
- Java (JAXP): Java provides the
FEATURE_SECURE_PROCESSING(FSP) flag. When enabled, it applies default limits to entity expansion depth and total entity counts. Administrators can also set specific system properties, such asjdk.xml.entityExpansionLimitandjdk.xml.elementAttributeLimit, to restrict parsing thresholds. - libxml2 (C/C++): Modern versions of
libxml2include built-in entity substitution caps and recursion depth limits (XML_MAX_ENTITY_LOOP). The parser refuses to expand entities recursively if the depth or total substitutions exceed safe internal thresholds. - .NET (System.Xml): The
XmlReaderSettingsclass includes theMaxCharactersFromEntitiesproperty. Setting this property limits how many characters can expand from entities, neutralizing exponential growth attacks regardless of nesting structure.
Complete Mitigation: Disabling DTD Processing
While entity depth and expansion limits provide a safety net, the most robust defense against XML bombs and XML External Entity (XXE) attacks is completely disabling external and inline DTD processing when DTDs are not strictly required:
- Disallowing the
DOCTYPEdeclaration entirely prevents parsers from processing<!ENTITY>definitions altogether. - Setting entity resolution features (such as
http://apache.org/xml/features/disallow-doctype-decl) totrueensures that any document containing a DTD is rejected before parsing begins.