Skip to content

Update dependency js-yaml to v4 [SECURITY]#5801

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

Update dependency js-yaml to v4 [SECURITY]#5801
renovate[bot] wants to merge 1 commit into
masterfrom
renovate/npm-js-yaml-vulnerability

Conversation

@renovate

@renovate renovate Bot commented Mar 17, 2026

Copy link
Copy Markdown
Contributor

This PR contains the following updates:

Package Change Age Confidence
js-yaml 3.13.14.2.0 age confidence

Warning

Some dependencies could not be looked up. Check the Dependency Dashboard for more information.


js-yaml has prototype pollution in merge (<<)

CVE-2025-64718 / GHSA-mh29-5h37-fv8m

More information

Details

Impact

In js-yaml 4.1.0, 4.0.0, and 3.14.1 and below, it's possible for an attacker to modify the prototype of the result of a parsed yaml document via prototype pollution (__proto__). All users who parse untrusted yaml documents may be impacted.

Patches

Problem is patched in js-yaml 4.1.1 and 3.14.2.

Workarounds

You can protect against this kind of attack on the server by using node --disable-proto=delete or deno (in Deno, pollution protection is on by default).

References

https://cheatsheetseries.owasp.org/cheatsheets/Prototype_Pollution_Prevention_Cheat_Sheet.html

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:L/A:N

References

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


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 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).

v4.1.1

Compare Source

v4.1.0

Compare Source

Added
  • Types are now exported as yaml.types.XXX.
  • Every type now has options property with original arguments kept as they were
    (see yaml.types.int.options as an example).
Changed
  • Schema.extend() now keeps old type order in case of conflicts
    (e.g. Schema.extend([ a, b, c ]).extend([ b, a, d ]) is now ordered as abcd instead of cbad).

v4.0.0

Compare Source

Changed
  • Check migration guide to see details for all breaking changes.
  • Breaking: "unsafe" tags !!js/function, !!js/regexp, !!js/undefined are
    moved to js-yaml-js-types package.
  • Breaking: removed safe* functions. Use load, loadAll, dump
    instead which are all now safe by default.
  • yaml.DEFAULT_SAFE_SCHEMA and yaml.DEFAULT_FULL_SCHEMA are removed, use
    yaml.DEFAULT_SCHEMA instead.
  • yaml.Schema.create(schema, tags) is removed, use schema.extend(tags) instead.
  • !!binary now always mapped to Uint8Array on load.
  • Reduced nesting of /lib folder.
  • Parse numbers according to YAML 1.2 instead of YAML 1.1 (01234 is now decimal,
    0o1234 is octal, 1:23 is parsed as string instead of base60).
  • dump() no longer quotes :, [, ], (, ) except when necessary, #​470, #​557.
  • Line and column in exceptions are now formatted as (X:Y) instead of
    at line X, column Y (also present in compact format), #​332.
  • Code snippet created in exceptions now contains multiple lines with line numbers.
  • dump() now serializes undefined as null in collections and removes keys with
    undefined in mappings, #​571.
  • dump() with skipInvalid=true now serializes invalid items in collections as null.
  • Custom tags starting with ! are now dumped as !tag instead of !<!tag>, #​576.
  • Custom tags starting with tag:yaml.org,2002: are now shorthanded using !!, #​258.
Added
  • Added .mjs (es modules) support.
  • Added quotingType and forceQuotes options for dumper to configure
    string literal style, #​290, #​529.
  • Added styles: { '!!null': 'empty' } option for dumper
    (serializes { foo: null } as "foo: "), #​570.
  • Added replacer option (similar to option in JSON.stringify), #​339.
  • Custom Tag can now handle all tags or multiple tags with the same prefix, #​385.
Fixed
  • Astral characters are no longer encoded by dump(), #​587.
  • "duplicate mapping key" exception now points at the correct column, #​452.
  • Extra commas in flow collections (e.g. [foo,,bar]) now throw an exception
    instead of producing null, #​321.
  • __proto__ key no longer overrides object prototype, #​164.
  • Removed bower.json.
  • Tags are now url-decoded in load() and url-encoded in dump()
    (previously usage of custom non-ascii tags may have led to invalid YAML that can't be parsed).
  • Anchors now work correctly with empty nodes, #​301.
  • Fix incorrect parsing of invalid block mapping syntax, #​418.
  • Throw an error if block sequence/mapping indent contains a tab, #​80.

v3.14.2

Compare Source

Security
  • Backported v4.1.1 fix to v3

v3.14.1

Compare Source

Security
  • Fix possible code execution in (already unsafe) .load() (in &anchor).

v3.14.0

Compare Source

Changed
  • Support safe/loadAll(input, options) variant of call.
  • CI: drop outdated nodejs versions.
  • Dev deps bump.
Fixed
  • Quote = in plain scalars #​519.
  • Check the node type for !<?> tag in case user manually specifies it.
  • Verify that there are no null-bytes in input.
  • Fix wrong quote position when writing condensed flow, #​526.

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.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • 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 the renovate PR automatically generated by renovate label Mar 17, 2026
@michelinewu michelinewu added the dependencies Pull requests that update a dependency file label Mar 17, 2026
@renovate renovate Bot changed the title Update dependency js-yaml to v4 [SECURITY] Update dependency js-yaml to v4 [SECURITY] - autoclosed Mar 27, 2026
@renovate renovate Bot closed this Mar 27, 2026
@renovate renovate Bot deleted the renovate/npm-js-yaml-vulnerability branch March 27, 2026 00:57
@renovate renovate Bot changed the title Update dependency js-yaml to v4 [SECURITY] - autoclosed Update dependency js-yaml to v4 [SECURITY] Mar 30, 2026
@renovate renovate Bot reopened this Mar 30, 2026
@renovate renovate Bot force-pushed the renovate/npm-js-yaml-vulnerability branch 3 times, most recently from f3fa1cd to fcc2b19 Compare April 1, 2026 17:03
@renovate renovate Bot changed the title Update dependency js-yaml to v4 [SECURITY] chore(deps): update dependency js-yaml to v4 [security] Apr 2, 2026
@renovate renovate Bot changed the title chore(deps): update dependency js-yaml to v4 [security] Update dependency js-yaml to v4 [SECURITY] Apr 8, 2026
@renovate renovate Bot force-pushed the renovate/npm-js-yaml-vulnerability branch from fcc2b19 to f4584d9 Compare April 8, 2026 20:45
@renovate renovate Bot changed the title Update dependency js-yaml to v4 [SECURITY] Update dependency js-yaml to v4 [SECURITY] - autoclosed Apr 27, 2026
@renovate renovate Bot closed this Apr 27, 2026
@renovate renovate Bot changed the title Update dependency js-yaml to v4 [SECURITY] - autoclosed Update dependency js-yaml to v4 [SECURITY] Apr 27, 2026
@renovate renovate Bot reopened this Apr 27, 2026
@renovate renovate Bot force-pushed the renovate/npm-js-yaml-vulnerability branch 2 times, most recently from f4584d9 to b9902d5 Compare April 27, 2026 19:03
@renovate renovate Bot changed the title Update dependency js-yaml to v4 [SECURITY] Update dependency js-yaml to v4 [SECURITY] - autoclosed Apr 27, 2026
@renovate renovate Bot closed this Apr 27, 2026
@renovate renovate Bot changed the title Update dependency js-yaml to v4 [SECURITY] - autoclosed Update dependency js-yaml to v4 [SECURITY] Apr 27, 2026
@renovate renovate Bot reopened this Apr 27, 2026
@renovate renovate Bot force-pushed the renovate/npm-js-yaml-vulnerability branch 2 times, most recently from b9902d5 to 58504cd Compare April 27, 2026 21:07
@renovate renovate Bot force-pushed the renovate/npm-js-yaml-vulnerability branch from 58504cd to 4d87f5f Compare May 12, 2026 10:52
@renovate renovate Bot changed the title Update dependency js-yaml to v4 [SECURITY] Update dependency js-yaml to v3.14.2 [SECURITY] May 14, 2026
@renovate renovate Bot force-pushed the renovate/npm-js-yaml-vulnerability branch from 4d87f5f to 3b3bd7e Compare May 14, 2026 22:18
@bundlemon

bundlemon Bot commented May 14, 2026

Copy link
Copy Markdown

BundleMon

Unchanged files (4)
Status Path Size Limits
renderer.(hash).js
7.79MB -
vendors~renderer.(hash).js
4.67MB -
updater.js
115.29KB -
guest-api.js
40.23KB -

No change in files bundle size

Final result: ✅

View report in BundleMon website ➡️


Current branch size history | Target branch size history

@renovate renovate Bot force-pushed the renovate/npm-js-yaml-vulnerability branch from 3b3bd7e to ef93630 Compare May 28, 2026 17:11
@renovate renovate Bot force-pushed the renovate/npm-js-yaml-vulnerability branch from ef93630 to c9fd7c1 Compare June 11, 2026 17:08
@renovate renovate Bot force-pushed the renovate/npm-js-yaml-vulnerability branch from c9fd7c1 to dc201d8 Compare June 16, 2026 16:50
@renovate renovate Bot changed the title Update dependency js-yaml to v3.14.2 [SECURITY] Update dependency js-yaml to v4 [SECURITY] Jun 16, 2026
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 PR automatically generated by renovate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant