CVE-2026-53550: JS-YAML Denial of Service Vulnerability
MODERATECVE-2026-53550 is a MODERATE (CVSS 5.3) denial of service vulnerability (CWE-407: Inefficient Algorithmic Complexity) affecting JS-YAML libraries in the npm ecosystem. The issue involves quadratic-complexity dos in merge key handling via repeated aliases. Remediation is available by upgrading affected packages to version 4.2.0, 3.15.0.
CVE-2026-53550 at a Glance
Security Impact
CVSS: 5.3
The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L).
How to Fix CVE-2026-53550
To remediate this vulnerability, upgrade all affected JS-YAML dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.
npm install js-yaml@4.2.0
npm install js-yaml@3.15.0
Run the following command in your project directory to verify that all resolved dependencies use the patched release:
npm ls js-yaml
How to Check if You Are Affected
To determine whether your Node.js application is affected by CVE-2026-53550, inspect your project dependencies using npm:
npm ls js-yaml
Analyze the terminal output to locate any version of JS-YAML in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 4.2.0), your application is affected.
Note: The npm ls js-yaml command inspects dependencies declared in your package.json and lockfile; it does not perform automated runtime dynamic scanning.
Technical Details
Vulnerability Mechanism & Technical Analysis
This vulnerability is classified under CWE-407: Inefficient Algorithmic Complexity, where an algorithm in a product has an inefficient worst-case computational complexity that may be detrimental to system performance and can be triggered by an attacker, typically using crafted manipulations that ensure that the worst case is being reached. In JS-YAML, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.
Source Advisory Statement
CVE-2026-53550 Affected JS-YAML Versions
2 component(s)| Product / Package | Ecosystem | Affected Versions | Fixed Version |
|---|---|---|---|
|
js-yaml
|
npm |
≥ 4.0.0
< 4.2.0
|
4.2.0
|
|
js-yaml
|
npm |
< 3.15.0
|
3.15.0
|
References
Frequently Asked Questions
What is CVE-2026-53550?
Which JS-YAML versions are affected?
What version fixes CVE-2026-53550?
Is js-yaml affected?
What is the CVSS score of CVE-2026-53550?
What CWE is associated with CVE-2026-53550?
How can I check npm dependencies for CVE-2026-53550?
Machine-readable OSV JSON
OSV v1.5 Schema
{
"schema_version" : "1.4.0",
"id" : "GHSA-h67p-54hq-rp68",
"modified" : "2026-06-29T15:05:57Z",
"published" : "2026-06-15T17:15:07Z",
"aliases" : [ "CVE-2026-53550" ],
"summary" : "JS-YAML: Quadratic-complexity DoS in merge key handling via repeated aliases",
"details" : "### Summary\nA crafted YAML document can trigger algorithmic CPU exhaustion in `js-yaml` merge-key processing (`<<`) by repeating the same alias many times in a merge sequence. \nThis causes quadratic parse-time behavior relative to input size and can block a Node.js worker/event loop for seconds with a relatively small payload (tens of KB), resulting in denial of service.\n\n### Details\nThe issue is in merge handling inside `lib/loader.js`:\n\n- `storeMappingPair(...)` iterates every element of a merge sequence when key tag is `tag:yaml.org,2002:merge`.\n- For each element, it calls `mergeMappings(...)`.\n- `mergeMappings(...)` computes `Object.keys(source)` and performs `_hasOwnProperty.call(destination, key)` checks for each key.\n\nWhen input is of the form:\n\na: &a {k0:0, k1:0, ..., kK:0}\nb: {<<: [*a, *a, *a, ... repeated M times ...]}\nall *a entries refer to the same anchored object. After the first merge, subsequent merges are semantically no-ops, but the parser still reprocesses all keys each time.\nResulting work is O(K * M), while input size is O(K + M), giving quadratic scaling as payload grows.\nRelevant code path:\nlib/loader.js in storeMappingPair(...) merge branch (keyTag === 'tag:yaml.org,2002:merge')\nlib/loader.js mergeMappings(...)\n\n\n### Root cause\nFile: lib/loader.js\nFunction: storeMappingPair(state, _result, overridableKeys, keyTag, keyNode,\n valueNode, startLine, startLineStart, startPos)\nLines: ~359-366\n\n if (keyTag === 'tag:yaml.org,2002:merge') {\n if (Array.isArray(valueNode)) {\n for (index = 0, quantity = valueNode.length; index < quantity; index += 1) {\n mergeMappings(state, _result, valueNode[index], overridableKeys);\n }\n } else {\n mergeMappings(state, _result, valueNode, overridableKeys);\n }\n }\n\nWhen the merge value is a sequence (YAML 1.1 <<: [ *a, *a, ... ]), each element\nis handed to mergeMappings() without deduplication. mergeMappings() then does\n\n sourceKeys = Object.keys(source);\n for (index = 0; index < sourceKeys.length; index += 1) {\n key = sourceKeys[index];\n if (!_hasOwnProperty.call(destination, key)) {\n setProperty(destination, key, source[key]);\n overridableKeys[key] = true;\n }\n }\n\nEvery alias reference in the sequence resolves (by design) to the SAME object\nvia state.anchorMap. After the first merge, every subsequent merge of that same\nreference is a pure no-op semantically, but still performs:\n\n * one Object.keys(source) call (O(K))\n * K _hasOwnProperty.call checks on the destination\n\nTotal: M * K hasOwnProperty checks + M Object.keys allocations, while the final\nobject and all observable side effects are identical to a single merge.\n\nYAML semantics for `<<:` are idempotent and commutative over duplicate sources,\nso collapsing duplicates preserves behavior exactly; this isn't a spec trade-off.\n\n\n### PoC\nEnvironment:\njs-yaml version: 4.1.1\nNode.js: v24.5.0\nPlatform: arm64 macOS (reproduced consistently)\nReproduction script:\nCreate many keys in one anchored map (&a).\nMerge that same alias repeatedly via <<: [*a, *a, ...].\nMeasure parse time and compare with control payload using single merge (<<: *a).\nObserved repeated runs (same machine):\nK=M=1000, input 9,909 bytes: ~33–36 ms\nK=M=2000, input 20,909 bytes: ~121–123 ms\nK=M=4000, input 42,909 bytes: ~524–537 ms\nK=M=6000, input 64,909 bytes: ~1,608–1,829 ms\nK=M=8000, input 86,909 bytes: ~3,395–3,565 ms\nControl (single merge, similar key counts):\nK=2000: ~1–2 ms\nK=4000: ~3 ms\nK=8000: ~5 ms\nAlso verified: repeated-merge output equals single-merge output (same key count and same JSON), confirming excess time is redundant computation.\n\n\n### Impact\nThis is a denial-of-service vulnerability (CPU exhaustion / algorithmic complexity).\nAny service parsing untrusted YAML with js-yaml can be impacted, including API backends, CI tools, config processors, and automation services. An attacker can submit crafted YAML to significantly increase CPU time and reduce availability.\n\n### Suggested fix:\nDedupe the merge source list by reference before invoking mergeMappings. Any of\nthe following are minimal and preserve YAML 1.1 merge semantics:\n\ndedupe in storeMappingPair:\n\n if (keyTag === 'tag:yaml.org,2002:merge') {\n if (Array.isArray(valueNode)) {\n var seen = new Set();\n for (index = 0, quantity = valueNode.length; index < quantity; index += 1) {\n var src = valueNode[index];\n if (seen.has(src)) continue; // idempotent; skip redundant alias\n seen.add(src);\n mergeMappings(state, _result, src, overridableKeys);\n }\n } else {\n mergeMappings(state, _result, valueNode, overridableKeys);\n }\n }",
"severity" : [ {
"type" : "CVSS_V3",
"score" : "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L"
} ],
"affected" : [ {
"package" : {
"ecosystem" : "npm",
"name" : "js-yaml"
},
"ranges" : [ {
"type" : "ECOSYSTEM",
"events" : [ {
"introduced" : "4.0.0"
}, {
"fixed" : "4.2.0"
} ]
} ],
"database_specific" : {
"last_known_affected_version_range" : "<= 4.1.1"
}
}, {
"package" : {
"ecosystem" : "npm",
"name" : "js-yaml"
},
"ranges" : [ {
"type" : "ECOSYSTEM",
"events" : [ {
"introduced" : "0"
}, {
"fixed" : "3.15.0"
} ]
} ]
} ],
"references" : [ {
"type" : "WEB",
"url" : "https://github.com/nodeca/js-yaml/security/advisories/GHSA-h67p-54hq-rp68"
}, {
"type" : "ADVISORY",
"url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-53550"
}, {
"type" : "PACKAGE",
"url" : "https://github.com/nodeca/js-yaml"
} ],
"database_specific" : {
"cwe_ids" : [ "CWE-407" ],
"severity" : "MODERATE",
"github_reviewed" : true,
"github_reviewed_at" : "2026-06-15T17:15:07Z",
"nvd_published_at" : "2026-06-22T16:16:38Z"
}
}