YAML alias bombs: "excessive aliasing" and the billion laughs attack

YAML anchors (&name) and aliases (*name) let a document reuse a node. Each level of this sample repeats the previous one nine times, so five short lines describe 59,049 strings, and a few more levels reach billions, which is enough to exhaust a server’s memory when the document is converted to plain data. Safe parsers count alias expansions and stop. PasteKit formats the text without expanding aliases, and the Tree view and YAML-to-JSON conversion refuse to expand it.

Seen as:

  • ReferenceError: Excessive alias count indicates a resource exhaustion attack
  • yaml: document contains excessive aliasing
  • org.yaml.snakeyaml.error.YAMLException: Number of aliases for non-scalar nodes exceeds the specified max=50
  • Too many alias expansions — this looks like a "billion laughs" alias bomb, so it was not expanded

Input

Settings

History

Load from URL

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.

Before
a: &a [x, x, x]
b: &b [*a, *a, *a]
c: [*b, *b, *b]
After
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.

Before
defaults: &defaults
  retries: 2
  timeout: 30
job_a:
  <<: *defaults
job_b:
  <<: *defaults
After
defaults: &defaults
  retries: 2
  timeout: 30
job_a:
  <<: *defaults
  timeout: 60
job_b:
  <<: *defaults

3. 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.

Before
config = yaml.safe_load(request.data)
After
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.

Related