Skip to content
đźź High7.5

Billion Laughs Attack (XML Bomb)

Denial of Service attacks via recursive entity expansion causing memory exhaustion and CPU consumption.

CWE-776: Improper Restriction of Recursive Entity ReferencesOWASP Top 10:2021 - A05: Security Misconfiguration

Overview

The Billion Laughs attack (also known as an XML bomb or exponential entity expansion attack) is a Denial of Service attack that exploits XML entity expansion to consume excessive memory and CPU resources.

How It Works: Define entities that reference other entities recursively. Each level of expansion multiplies the data size exponentially, quickly exhausting server resources.

Attack Impact:

  • Memory exhaustion (OutOfMemoryError)
  • CPU saturation (100% utilization)
  • Application crash or hang
  • Server unavailability
  • Resource starvation for other users

Why It's Called "Billion Laughs": The classic payload expands the string "lol" billions of times through 9 levels of entity references, creating approximately 3GB of data from a tiny XML file.

Related Attacks:

  • Quadratic Blowup Attack (less severe expansion)
  • External Entity Expansion (combines with XXE)
  • DTD Recursion (similar principle in DTDs)

Classic Billion Laughs Payload

XMLbillion-laughs.xml⚠️ Vulnerable
1<?xml version="1.0"?>
2<!DOCTYPE lolz [
3  <!ENTITY lol "lol">
4  <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
5  <!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
6  <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
7  <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
8  <!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
9  <!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
10  <!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
11  <!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
12  <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
13]>
14<lolz>&lol9;</lolz>

Exponential Expansion Mathematics

Let's calculate the expansion:

  • lol = "lol" (3 bytes)
  • lol1 = 10 Ă— lol = 10 Ă— 3 = 30 bytes
  • lol2 = 10 Ă— lol1 = 10 Ă— 30 = 300 bytes
  • lol3 = 10 Ă— lol2 = 10 Ă— 300 = 3,000 bytes
  • lol4 = 10 Ă— lol3 = 10 Ă— 3,000 = 30,000 bytes
  • lol5 = 10 Ă— lol4 = 10 Ă— 30,000 = 300,000 bytes
  • lol6 = 10 Ă— lol5 = 10 Ă— 300,000 = 3,000,000 bytes (3 MB)
  • lol7 = 10 Ă— lol6 = 10 Ă— 3 MB = 30 MB
  • lol8 = 10 Ă— lol7 = 10 Ă— 30 MB = 300 MB
  • lol9 = 10 Ă— lol8 = 10 Ă— 300 MB = 3,000 MB (3 GB)

Final Result: A 750-byte XML file expands to approximately 3 GB in memory!

Each reference level multiplies the size by 10, creating exponential growth: Size = base_size Ă— (expansion_factor ^ levels) Size = 3 Ă— (10 ^ 9) = 3,000,000,000 bytes

Attack Variants

XMLdos-variants.xml⚠️ Vulnerable
1<!-- Quadratic Blowup (less severe but still effective) -->
2<?xml version="1.0"?>
3<!DOCTYPE bomb [
4  <!ENTITY a "aaaaaaaaaa..." (10,000 a's)>
5]>
6<bomb>&a;&a;&a;&a;&a;...</bomb> (repeat &a; 10,000 times)
7<!-- Creates 10,000 Ă— 10,000 = 100,000,000 bytes (100 MB) -->
8
9<!-- External Entity Expansion -->
10<!DOCTYPE bomb [
11  <!ENTITY xxe SYSTEM "file:///dev/random">
12]>
13<bomb>&xxe;</bomb>
14<!-- Reads infinite random data, crashes parser -->
15
16<!-- Parameter Entity Recursion -->
17<!DOCTYPE bomb [
18  <!ENTITY % a "&a;&a;">
19  %a;
20]>
21<!-- Infinite recursion, stack overflow -->

Vulnerable Java Code

JavaVulnerableXMLParser.java⚠️ Vulnerable
1import javax.xml.parsers.DocumentBuilder;
2import javax.xml.parsers.DocumentBuilderFactory;
3import org.w3c.dom.Document;
4import java.io.ByteArrayInputStream;
5
6public class VulnerableXMLParser {
7    
8    public void parseXML(String xmlData) {
9        try {
10            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
11            
12            // VULNERABLE: Default settings allow entity expansion
13            // No limits on entity expansion depth or size
14            
15            DocumentBuilder builder = factory.newDocumentBuilder();
16            Document doc = builder.parse(
17                new ByteArrayInputStream(xmlData.getBytes())
18            );
19            
20            // When billion laughs payload is parsed:
21            // 1. Parser expands &lol9;
22            // 2. Recursively expands &lol8; ten times
23            // 3. Continues until expanding 1 billion "lol" strings
24            // 4. OutOfMemoryError: Java heap space
25            
26            System.out.println("Parsed successfully");
27            
28        } catch (OutOfMemoryError e) {
29            System.err.println("Memory exhausted!");
30            // Application crashes or hangs
31        } catch (Exception e) {
32            System.err.println("Parse error: " + e.getMessage());
33        }
34    }
35}

Secure Java Implementation

JavaSecureXMLParser.javaâś“ Secure
1import javax.xml.parsers.DocumentBuilder;
2import javax.xml.parsers.DocumentBuilderFactory;
3import javax.xml.XMLConstants;
4import org.w3c.dom.Document;
5import java.io.ByteArrayInputStream;
6
7public class SecureXMLParser {
8    
9    public Document parseXML(String xmlData) throws Exception {
10        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
11        
12        // PRIMARY DEFENSE: Disable DOCTYPE declarations
13        factory.setFeature(
14            "http://apache.org/xml/features/disallow-doctype-decl",
15            true  // Blocks all entity-based attacks
16        );
17        
18        // If DOCTYPE needed, disable entity expansion
19        factory.setFeature(
20            XMLConstants.FEATURE_SECURE_PROCESSING,
21            true  // Enables secure processing limits
22        );
23        factory.setExpandEntityReferences(false);  // Don't expand entities
24        
25        // Set entity expansion limits (if parser supports)
26        factory.setAttribute(
27            "http://www.oracle.com/xml/jaxp/properties/entityExpansionLimit",
28            "100"  // Maximum 100 entity expansions
29        );
30        
31        // Disable external entities (prevents XXE + external expansion)
32        factory.setFeature(
33            "http://xml.org/sax/features/external-general-entities",
34            false
35        );
36        factory.setFeature(
37            "http://xml.org/sax/features/external-parameter-entities",
38            false
39        );
40        factory.setFeature(
41            "http://apache.org/xml/features/nonvalidating/load-external-dtd",
42            false
43        );
44        
45        DocumentBuilder builder = factory.newDocumentBuilder();
46        return builder.parse(new ByteArrayInputStream(xmlData.getBytes()));
47    }
48}

Python Defense with defusedxml

Pythonsecure_parser.pyâś“ Secure
1from defusedxml import ElementTree as DefusedET
2from defusedxml.lxml import fromstring as defused_fromstring
3import xml.etree.ElementTree as ET
4
5# VULNERABLE: Standard library without protection
6def parse_vulnerable(xml_data):
7    # This will expand entities and crash on billion laughs
8    tree = ET.fromstring(xml_data)
9    return tree
10
11# SECURE: Using defusedxml
12def parse_secure(xml_data):
13    # defusedxml blocks:
14    # - Entity expansion beyond safe limits
15    # - DTD processing
16    # - External entity references
17    try:
18        tree = DefusedET.fromstring(xml_data)
19        return tree
20    except DefusedET.DTDForbidden:
21        print("DTD processing blocked")
22    except DefusedET.EntitiesForbidden:
23        print("Entity expansion blocked")
24    except DefusedET.ExternalReferenceForbidden:
25        print("External reference blocked")
26
27# For lxml:
28def parse_lxml_secure(xml_data):
29    # defusedxml.lxml automatically applies protections
30    tree = defused_fromstring(xml_data)
31    return tree
32
33# Manual configuration (if defusedxml not available):
34from lxml import etree
35
36def parse_manual_secure(xml_data):
37    parser = etree.XMLParser(
38        resolve_entities=False,  # Don't expand entities
39        no_network=True,         # Block network access
40        huge_tree=False,         # Limit tree size
41        load_dtd=False          # Don't load DTDs
42    )
43    tree = etree.fromstring(xml_data, parser)
44    return tree

Detection and Monitoring

Code Review Indicators:

  • XML parsers without entity expansion limits
  • Missing DOCTYPE restrictions
  • No use of secure parsing libraries (defusedxml, etc.)
  • ExpandEntityReferences enabled
  • No memory or CPU limits for XML processing

Runtime Detection:

  • Sudden CPU spikes during XML parsing
  • Memory usage rapidly increasing to maximum
  • OutOfMemoryError or similar exceptions
  • Application hang or unresponsiveness
  • Long parse times for small XML files

Testing Methodology:

  1. Submit classic billion laughs payload
  2. Monitor server memory and CPU
  3. Measure parse time (should timeout or reject)
  4. Try variants with different expansion depths
  5. Test quadratic blowup attacks
  6. Verify parser limits are enforced

Monitoring & Alerting:

  • Alert on high memory usage during XML parsing
  • Track XML parse duration metrics
  • Monitor for OutOfMemoryError exceptions
  • Set resource limits (cgroups, containers)
  • Implement parse timeouts

Prevention Best Practices

Primary Defenses:

  1. Disable DOCTYPE Processing: Strongest protection - completely disallow DOCTYPE declarations Blocks all entity-based attacks (XXE and DoS)

  2. Disable Entity Expansion: If DOCTYPE needed, disable entity reference expansion Set expandEntityReferences=false

  3. Use Secure Libraries: Python: defusedxml, lxml with secure config Java: Xerces with secure features .NET: XmlReaderSettings with secure defaults PHP: libxml_disable_entity_loader(true)

  4. Set Entity Expansion Limits: Java: entityExpansionLimit (default 64000) Configure lower limits for untrusted input Limit entity nesting depth

Additional Defenses:

  1. Resource Limits: Set maximum memory for XML parser processes Use containers/cgroups to limit resources Implement parse timeouts

  2. Input Validation: Reject XML with excessive <!ENTITY definitions Limit XML document size (before parsing) Check for suspicious patterns

  3. Defense in Depth: Combine multiple protections Monitor and alert on anomalies Regular security testing