Common causes
1. Nested aliases that multiply
An alias to a list that itself contains aliases multiplies at every level. Legitimate configs almost never nest aliases more than one or two levels deep; flatten the data or expand it once in the source.
a: &a [x, x, x]
b: &b [*a, *a, *a]
c: [*b, *b, *b]a: [x, x, x]
b: [x, x, x, x, x, x, x, x, x]2. Normal anchor reuse (safe)
Sharing one block of defaults with <<: *defaults, as GitLab CI and Docker Compose files do, expands each alias once and is harmless. Limits in safe parsers are set high enough not to affect this.
defaults: &defaults
retries: 2
timeout: 30
job_a:
<<: *defaults
job_b:
<<: *defaultsdefaults: &defaults
retries: 2
timeout: 30
job_a:
<<: *defaults
timeout: 60
job_b:
<<: *defaults3. Parsing untrusted YAML without limits
PyYAML’s safe_load blocks arbitrary object construction but does not limit alias expansion. For uploads and API input, cap the input size, and prefer a parser with an alias limit or reject aliases outright.
config = yaml.safe_load(request.data)if len(request.data) > 64_000:
abort(413)
config = yaml.safe_load(request.data)Frequently asked questions
Why is it called "billion laughs"?
The name comes from the original XML version of the attack, which nested entities that each expanded to ten copies of the string “lol” until a tiny file produced a billion of them. YAML aliases allow the same trick.
Is it dangerous to open such a file in PasteKit?
No. Everything runs in your browser, the formatter never expands aliases, and the Tree view and conversions stop after a fixed number of expansions with a clear error.
Which parsers protect against it?
Go’s yaml.v2 (since 2.2.8) and yaml.v3, SnakeYAML 1.26 and later, and the JavaScript yaml package all limit alias expansion. PyYAML and js-yaml have no such limit, so limit input size yourself.