← Home ← Codex ← DEBT ← Engine
Browse by Category
+ added · updated 7d
← Back to glossary

XML Entity Expansion (Billion Laughs / XXE)

Security CWE-611 OWASP A5:2021 CVSS 9.1 PHP 5.0+ Intermediate
debt(d5/e3/b3/t7)
d5 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'specialist tool catches it' (d5). Detection hints list semgrep and psalm as tools that can detect XML parsing without entity expansion limits (e.g., LIBXML_NOENT not disabled, simplexml_load_string without restrictions). These are SAST/specialist tools rather than default linters or compiler errors, placing this squarely at d5.

e3 Effort Remediation debt — work required to fix once spotted

Closest to 'simple parameterised fix' (e3). The quick_fix describes calling libxml_disable_entity_loader(true) and setting LIBXML_NONET flags — a small, localized change at each XML parsing call site. This is slightly more than a single-line patch because it may need to be applied at multiple parsing locations across a component, but does not require cross-cutting refactors.

b3 Burden Structural debt — long-term weight of choosing wrong

Closest to 'localised tax' (b3). The fix applies only to XML parsing call sites. While it applies across web, api, and cli contexts, the actual code change is confined to wherever XML is parsed. It doesn't reshape architecture or slow down unrelated work streams — future maintainers only need to remember this when adding new XML parsing code.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap' (t7). The misconception field states developers believe entity expansion is 'only a theoretical DoS risk,' when in fact a crafted document can expand from kilobytes to gigabytes crashing the server in milliseconds. The common_mistakes also note that developers assume expansion attacks only apply to XXE (external entity loading), when internal entity expansion is equally dangerous — this contradicts how developers reason about the XXE/entity distinction, making it a serious cognitive trap.

About DEBT scoring →

Also Known As

billion laughs attack XML bomb exponential entity expansion

TL;DR

Denial-of-service via exponentially nested XML entities (Billion Laughs) or SSRF/file-read via external entity references (XXE).

Explanation

Two related XML attacks: the Billion Laughs DoS defines nested entities that expand exponentially (lol1 = 10×lol0, lol2 = 10×lol1 ... lol9 = billions of characters), exhausting server memory parsing a tiny document. XXE (XML External Entity) uses <!ENTITY ext SYSTEM 'file:///etc/passwd'> to read local files or <!ENTITY ext SYSTEM 'http://internal/'> to trigger SSRF. PHP's libxml is vulnerable by default. Mitigations: call libxml_disable_entity_loader(true) (PHP < 8.0) or use LIBXML_NONET | LIBXML_NOENT flags with simplexml_load_string() / DOMDocument::loadXML(). In PHP 8.0+ external entity loading is disabled by default. Never parse untrusted XML with a SAX/DOM parser that hasn't had entity expansion disabled.

Common Misconception

XML entity expansion is only a theoretical DoS risk. A crafted document with nested entity references can expand to gigabytes in memory from kilobytes of input, crashing a server in milliseconds. Always disable entity expansion when parsing untrusted XML.

Why It Matters

The billion laughs attack uses nested entity references to expand a small XML document to gigabytes, exhausting memory and crashing the parser — one request, full DoS.

Common Mistakes

  • Parsing user-supplied XML without setting LIBXML_NOENT to disable entity expansion.
  • Using SimpleXML or DOMDocument on untrusted input without calling libxml_disable_entity_loader(true) first.
  • Not setting resource limits (memory, CPU time) for XML parsing operations.
  • Assuming entity attacks only apply to XXE — expansion attacks do not require external entity loading.

Avoid When

  • Never parse user-supplied XML with unlimited entity expansion enabled — a single crafted document can exhaust server memory.
  • Do not use DOMDocument or SimpleXML on untrusted input without configuring safe parse options first.

When To Use

  • Disable entity expansion when parsing untrusted XML using LIBXML_NOENT awareness and libxml_disable_entity_loader().
  • Set a maximum entity expansion depth/count limit when processing XML from external sources.

Code Examples

✗ Vulnerable
$xml = simplexml_load_string($untrusted); // XXE possible pre-PHP 8
✓ Fixed
libxml_disable_entity_loader(true); // PHP < 8.0
$xml = simplexml_load_string($untrusted, 'SimpleXMLElement', LIBXML_NOENT | LIBXML_NONET);

Tags


Added 15 Mar 2026
Edited 31 Mar 2026
Views 122
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings W 0 pings T 1 ping F 0 pings S 0 pings S 0 pings M 1 ping T 0 pings W 0 pings T 0 pings F 0 pings S 1 ping S 1 ping M 2 pings T 0 pings W 0 pings T 0 pings F 1 ping S 0 pings S 0 pings M 2 pings T 1 ping W 0 pings T 0 pings F 0 pings S 1 ping S 1 ping M 1 ping T 0 pings W 0 pings T
No pings yet today
No pings yesterday
Amazonbot 13 PetalBot 13 Ahrefs 8 ChatGPT 7 SEMrush 7 Bing 6 Brave Search 4 Perplexity 3 Unknown AI 3 Scrapy 3 Google 2 Applebot 2 Sogou 2 Claude 1 Twitter/X 1
crawler 71 crawler_json 4
DEV INTEL Tools & Severity
🔴 Critical ⚙ Fix effort: Low
⚡ Quick Fix
Set LIBXML_NONET when parsing XML and configure libxml_disable_entity_loader(true) for PHP < 8.0 — Billion Laughs attack uses nested entity expansion to exhaust memory with a tiny XML file
📦 Applies To
PHP 5.0+ web api cli
🔗 Prerequisites
🔍 Detection Hints
XML parsing without entity expansion limits; LIBXML_NOENT not disabled; simplexml_load_string without entity restrictions
Auto-detectable: ✓ Yes semgrep psalm
⚠ Related Problems
🤖 AI Agent
Confidence: High False Positives: Low ✓ Auto-fixable Fix: Low Context: Line
CWE-776 CWE-400


✓ schema.org compliant