Skip to content

fix(deps): update dependency js-yaml [security]#5023

Open
renovate[bot] wants to merge 1 commit into
masterfrom
renovate/npm-js-yaml-vulnerability
Open

fix(deps): update dependency js-yaml [security]#5023
renovate[bot] wants to merge 1 commit into
masterfrom
renovate/npm-js-yaml-vulnerability

Conversation

@renovate

@renovate renovate Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

This PR contains the following updates:

Package Change Age Confidence
js-yaml ^4.1.1^4.2.0 age confidence
js-yaml ^4.1.1^5.0.0 age confidence

JS-YAML: Quadratic-complexity DoS in merge key handling via repeated aliases

CVE-2026-53550 / GHSA-h67p-54hq-rp68

More information

Details

Summary

A 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.
This 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.

Details

The issue is in merge handling inside lib/loader.js:

  • storeMappingPair(...) iterates every element of a merge sequence when key tag is tag:yaml.org,2002:merge.
  • For each element, it calls mergeMappings(...).
  • mergeMappings(...) computes Object.keys(source) and performs _hasOwnProperty.call(destination, key) checks for each key.

When input is of the form:

a: &a {k0:0, k1:0, ..., kK:0}
b: {<<: [*a, *a, *a, ... repeated M times ...]}
all *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.
Resulting work is O(K * M), while input size is O(K + M), giving quadratic scaling as payload grows.
Relevant code path:
lib/loader.js in storeMappingPair(...) merge branch (keyTag === 'tag:yaml.org,2002:merge')
lib/loader.js mergeMappings(...)

Root cause

File: lib/loader.js
Function: storeMappingPair(state, _result, overridableKeys, keyTag, keyNode,
valueNode, startLine, startLineStart, startPos)
Lines: ~359-366

if (keyTag === 'tag:yaml.org,2002:merge') {
  if (Array.isArray(valueNode)) {
    for (index = 0, quantity = valueNode.length; index < quantity; index += 1) {
      mergeMappings(state, _result, valueNode[index], overridableKeys);
    }
  } else {
    mergeMappings(state, _result, valueNode, overridableKeys);
  }
}

When the merge value is a sequence (YAML 1.1 <<: [ *a, *a, ... ]), each element
is handed to mergeMappings() without deduplication. mergeMappings() then does

sourceKeys = Object.keys(source);
for (index = 0; index < sourceKeys.length; index += 1) {
  key = sourceKeys[index];
  if (!_hasOwnProperty.call(destination, key)) {
    setProperty(destination, key, source[key]);
    overridableKeys[key] = true;
  }
}

Every alias reference in the sequence resolves (by design) to the SAME object
via state.anchorMap. After the first merge, every subsequent merge of that same
reference is a pure no-op semantically, but still performs:

  • one Object.keys(source) call (O(K))
  • K _hasOwnProperty.call checks on the destination

Total: M * K hasOwnProperty checks + M Object.keys allocations, while the final
object and all observable side effects are identical to a single merge.

YAML semantics for <<: are idempotent and commutative over duplicate sources,
so collapsing duplicates preserves behavior exactly; this isn't a spec trade-off.

PoC

Environment:
js-yaml version: 4.1.1
Node.js: v24.5.0
Platform: arm64 macOS (reproduced consistently)
Reproduction script:
Create many keys in one anchored map (&a).
Merge that same alias repeatedly via <<: [*a, *a, ...].
Measure parse time and compare with control payload using single merge (<<: *a).
Observed repeated runs (same machine):
K=M=1000, input 9,909 bytes: ~33–36 ms
K=M=2000, input 20,909 bytes: ~121–123 ms
K=M=4000, input 42,909 bytes: ~524–537 ms
K=M=6000, input 64,909 bytes: ~1,608–1,829 ms
K=M=8000, input 86,909 bytes: ~3,395–3,565 ms
Control (single merge, similar key counts):
K=2000: ~1–2 ms
K=4000: ~3 ms
K=8000: ~5 ms
Also verified: repeated-merge output equals single-merge output (same key count and same JSON), confirming excess time is redundant computation.

Impact

This is a denial-of-service vulnerability (CPU exhaustion / algorithmic complexity).
Any 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.

Suggested fix:

Dedupe the merge source list by reference before invoking mergeMappings. Any of
the following are minimal and preserve YAML 1.1 merge semantics:

dedupe in storeMappingPair:

if (keyTag === 'tag:yaml.org,2002:merge') {
  if (Array.isArray(valueNode)) {
    var seen = new Set();
    for (index = 0, quantity = valueNode.length; index < quantity; index += 1) {
      var src = valueNode[index];
      if (seen.has(src)) continue;   // idempotent; skip redundant alias
      seen.add(src);
      mergeMappings(state, _result, src, overridableKeys);
    }
  } else {
    mergeMappings(state, _result, valueNode, overridableKeys);
  }
}

Severity

  • CVSS Score: 5.3 / 10 (Medium)
  • Vector String: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


Release Notes

nodeca/js-yaml (js-yaml)

v4.2.0

Compare Source

Added
  • Added docs/safety.md with notes about processing untrusted YAML.
  • Added maxDepth (100) loader option. Not a problem, but gives a better
    exception instead of RangeError on stack overflow.
  • Added maxMergeSeqLength (20) loader option. Not a problem after merge fix,
    but an additional restriction for safety.
  • Added sourcemaps to dist/ builds.
Changed
  • Stop resolving numbers with underscores as numeric scalars, #​627.
  • Switched dev toolchains to Vite / neostandard.
  • Updated demo.
  • Reorganized tests.
  • dist/ files are no longer kept in the repository.
Fixed
  • Fix parsing of properties on the first implicit block mapping key, #​62.
  • Fix trailing whitespace handling when folding flow scalar lines, #​307.
  • Reject top-level block scalars without content indentation, #​280.
  • Ensure numbers survive round-trip, #​737.
  • Fix test coverage for issue #​221.
  • Fix flow scalar trailing whitespace folding, #​307.
  • Fix digits in YAML named tag handles.
Security
  • Fix potential DoS via quadratic complexity in merge - deduplicate repeated
    elements (makes sense for malformed files > 10K).

Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

👻 Immortal: This PR will be recreated if closed unmerged. Get config help if that's undesired.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

@renovate renovate Bot added dependencies Pull requests that update a dependency file renovate-bot labels Jun 16, 2026
@renovate
renovate Bot requested a review from a team as a code owner June 16, 2026 01:46
@renovate renovate Bot added the dependencies Pull requests that update a dependency file label Jun 16, 2026
@renovate
renovate Bot requested a review from schogges June 16, 2026 01:46
@netlify

netlify Bot commented Jun 16, 2026

Copy link
Copy Markdown

Deploy Preview for kuma-gui failed.

Name Link
🔨 Latest commit 9e5d7dd
🔍 Latest deploy log https://app.netlify.com/projects/kuma-gui/deploys/6a5a5a7aa3baee00089ef880

@renovate
renovate Bot force-pushed the renovate/npm-js-yaml-vulnerability branch from 1c9a595 to 4488773 Compare June 16, 2026 14:32
@schogges

Copy link
Copy Markdown
Contributor

I'm currently stuck in trying to update the transitive js-yaml of lockfile-lint to match the version specified in overrides in root manifest. It's sticking to js-yaml@3.14.2 whatever I've tried so far.

Before

@kumahq/kuma-gui-monorepo@0.1.0
├─┬ @kumahq/config@1.0.0 -> ./packages/config
│ ├─┬ @apidevtools/json-schema-ref-parser@15.3.5
│ │ └── js-yaml@4.1.1 deduped
│ ├─┬ eslint@9.39.4
│ │ └─┬ @eslint/eslintrc@3.3.5
│ │   └── js-yaml@4.1.1 deduped
│ ├── js-yaml@4.1.1
│ ├─┬ lockfile-lint@5.0.0
│ │ ├─┬ cosmiconfig@9.0.1
│ │ │ └── js-yaml@4.1.1 deduped
│ │ └─┬ lockfile-lint-api@5.9.2
│ │   └─┬ @yarnpkg/parsers@3.0.3
│ │     └── js-yaml@4.1.1 deduped invalid: "^3.10.0" from node_modules/@yarnpkg/parsers
│ └─┬ openapi-typescript@7.13.0
│   └─┬ @redocly/openapi-core@1.34.7
│     └── js-yaml@4.1.1 deduped
├─┬ @kumahq/gherkin-web@0.1.0 -> ./packages/gherkin-web
│ └── js-yaml@4.1.1 deduped
└─┬ @kumahq/kuma-gui@2.14.0 -> ./packages/kuma-gui
  └── js-yaml@4.1.1 deduped

After

@kumahq/kuma-gui-monorepo@0.1.0
├─┬ @kumahq/config@1.0.0 -> ./packages/config
│ ├─┬ @apidevtools/json-schema-ref-parser@15.3.5
│ │ └── js-yaml@4.2.0 deduped
│ ├─┬ eslint@9.39.4
│ │ └─┬ @eslint/eslintrc@3.3.5
│ │   └── js-yaml@4.2.0 deduped
│ ├── js-yaml@4.2.0
│ ├─┬ lockfile-lint@5.0.0
│ │ ├─┬ cosmiconfig@9.0.1
│ │ │ └── js-yaml@4.2.0 deduped
│ │ └─┬ lockfile-lint-api@5.9.2
│ │   └─┬ @yarnpkg/parsers@3.0.3
│ │     └── js-yaml@3.14.2
│ └─┬ openapi-typescript@7.13.0
│   └─┬ @redocly/openapi-core@1.34.7
│     └── js-yaml@4.2.0 deduped
├─┬ @kumahq/gherkin-web@0.1.0 -> ./packages/gherkin-web
│ └── js-yaml@4.2.0 deduped
└─┬ @kumahq/kuma-gui@2.14.0 -> ./packages/kuma-gui
  └── js-yaml@4.2.0 deduped

@renovate renovate Bot changed the title fix(deps): update dependency js-yaml to v4.2.0 [security] fix(deps): update dependency js-yaml [security] Jul 2, 2026
@renovate
renovate Bot force-pushed the renovate/npm-js-yaml-vulnerability branch from 68073b4 to 99e9087 Compare July 2, 2026 10:20
@renovate renovate Bot changed the title fix(deps): update dependency js-yaml [security] fix(deps): update dependency js-yaml to ^4.2.0 [security] Jul 3, 2026
@renovate
renovate Bot force-pushed the renovate/npm-js-yaml-vulnerability branch 4 times, most recently from 470cc0b to 6c1c3b4 Compare July 3, 2026 09:23
@renovate renovate Bot changed the title fix(deps): update dependency js-yaml to ^4.2.0 [security] fix(deps): update dependency js-yaml [security] Jul 3, 2026
@renovate
renovate Bot force-pushed the renovate/npm-js-yaml-vulnerability branch from 6c1c3b4 to 864c786 Compare July 3, 2026 09:47
@renovate renovate Bot changed the title fix(deps): update dependency js-yaml [security] fix(deps): update dependency js-yaml to ^4.2.0 [security] Jul 3, 2026
@renovate renovate Bot changed the title fix(deps): update dependency js-yaml to ^4.2.0 [security] fix(deps): update dependency js-yaml [security] Jul 3, 2026
@renovate
renovate Bot force-pushed the renovate/npm-js-yaml-vulnerability branch 2 times, most recently from 4d20334 to 997d691 Compare July 3, 2026 12:24
@renovate renovate Bot changed the title fix(deps): update dependency js-yaml [security] fix(deps): update dependency js-yaml to ^4.2.0 [security] Jul 3, 2026
@renovate
renovate Bot force-pushed the renovate/npm-js-yaml-vulnerability branch from 997d691 to ff65a2d Compare July 3, 2026 16:25
@renovate renovate Bot changed the title fix(deps): update dependency js-yaml to ^4.2.0 [security] fix(deps): update dependency js-yaml [security] Jul 3, 2026
@renovate renovate Bot changed the title fix(deps): update dependency js-yaml [security] fix(deps): update dependency js-yaml to ^4.2.0 [security] Jul 6, 2026
@renovate
renovate Bot force-pushed the renovate/npm-js-yaml-vulnerability branch 2 times, most recently from c61f5c6 to 8280401 Compare July 6, 2026 08:48
@renovate renovate Bot changed the title fix(deps): update dependency js-yaml to ^4.2.0 [security] fix(deps): update dependency js-yaml [security] Jul 6, 2026
@renovate
renovate Bot force-pushed the renovate/npm-js-yaml-vulnerability branch from 8280401 to d0d263f Compare July 6, 2026 08:50
@renovate
renovate Bot force-pushed the renovate/npm-js-yaml-vulnerability branch from 2688ba4 to c88822c Compare July 8, 2026 12:27
@renovate renovate Bot changed the title fix(deps): update dependency js-yaml to ^4.2.0 [security] fix(deps): update dependency js-yaml [security] Jul 8, 2026
@renovate
renovate Bot force-pushed the renovate/npm-js-yaml-vulnerability branch from c88822c to b0653fd Compare July 9, 2026 09:21
@renovate renovate Bot changed the title fix(deps): update dependency js-yaml [security] fix(deps): update dependency js-yaml to ^4.3.0 [security] Jul 9, 2026
@renovate
renovate Bot force-pushed the renovate/npm-js-yaml-vulnerability branch from b0653fd to bec8450 Compare July 9, 2026 12:30
@renovate renovate Bot changed the title fix(deps): update dependency js-yaml to ^4.3.0 [security] fix(deps): update dependency js-yaml [security] Jul 9, 2026
@renovate
renovate Bot force-pushed the renovate/npm-js-yaml-vulnerability branch from bec8450 to 0fc1af0 Compare July 9, 2026 16:14
@renovate renovate Bot changed the title fix(deps): update dependency js-yaml [security] fix(deps): update dependency js-yaml to ^4.3.0 [security] Jul 9, 2026
@renovate
renovate Bot force-pushed the renovate/npm-js-yaml-vulnerability branch from 0fc1af0 to cee5638 Compare July 9, 2026 18:55
@renovate renovate Bot changed the title fix(deps): update dependency js-yaml to ^4.3.0 [security] fix(deps): update dependency js-yaml [security] Jul 9, 2026
@renovate
renovate Bot force-pushed the renovate/npm-js-yaml-vulnerability branch from cee5638 to 6384825 Compare July 10, 2026 08:33
@renovate renovate Bot changed the title fix(deps): update dependency js-yaml [security] fix(deps): update dependency js-yaml to ^4.3.0 [security] Jul 10, 2026
@renovate
renovate Bot force-pushed the renovate/npm-js-yaml-vulnerability branch from 6384825 to aeb91c0 Compare July 10, 2026 09:08
@renovate renovate Bot changed the title fix(deps): update dependency js-yaml to ^4.3.0 [security] fix(deps): update dependency js-yaml [security] Jul 10, 2026
@renovate
renovate Bot force-pushed the renovate/npm-js-yaml-vulnerability branch from aeb91c0 to 18e9e2b Compare July 12, 2026 15:10
@renovate renovate Bot changed the title fix(deps): update dependency js-yaml [security] fix(deps): update dependency js-yaml to ^4.3.0 [security] Jul 12, 2026
@renovate renovate Bot changed the title fix(deps): update dependency js-yaml to ^4.3.0 [security] fix(deps): update dependency js-yaml [security] Jul 12, 2026
@renovate
renovate Bot force-pushed the renovate/npm-js-yaml-vulnerability branch 2 times, most recently from 226e791 to 2424931 Compare July 13, 2026 11:32
@renovate renovate Bot changed the title fix(deps): update dependency js-yaml [security] fix(deps): update dependency js-yaml to ^4.3.0 [security] Jul 13, 2026
@renovate
renovate Bot force-pushed the renovate/npm-js-yaml-vulnerability branch from 2424931 to 9b177f7 Compare July 13, 2026 12:58
@renovate renovate Bot changed the title fix(deps): update dependency js-yaml to ^4.3.0 [security] fix(deps): update dependency js-yaml [security] Jul 13, 2026
@renovate
renovate Bot force-pushed the renovate/npm-js-yaml-vulnerability branch from 9b177f7 to b6d5e05 Compare July 13, 2026 16:48
@renovate renovate Bot changed the title fix(deps): update dependency js-yaml [security] fix(deps): update dependency js-yaml to ^4.3.0 [security] Jul 13, 2026
@renovate renovate Bot changed the title fix(deps): update dependency js-yaml to ^4.3.0 [security] fix(deps): update dependency js-yaml [security] Jul 13, 2026
@renovate
renovate Bot force-pushed the renovate/npm-js-yaml-vulnerability branch from b6d5e05 to fbd8680 Compare July 13, 2026 21:45
@renovate renovate Bot changed the title fix(deps): update dependency js-yaml [security] fix(deps): update dependency js-yaml to ^4.3.0 [security] Jul 14, 2026
@renovate
renovate Bot force-pushed the renovate/npm-js-yaml-vulnerability branch from fbd8680 to 5d6d7da Compare July 14, 2026 11:25
@renovate renovate Bot changed the title fix(deps): update dependency js-yaml to ^4.3.0 [security] fix(deps): update dependency js-yaml [security] Jul 14, 2026
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file renovate-bot

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant