Skip to content

Update dependency js-yaml@3 to v4 [SECURITY] - #244

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

Update dependency js-yaml@3 to v4 [SECURITY]#244
renovate[bot] wants to merge 1 commit into
mainfrom
renovate/npm-js-yaml3-vulnerability

Conversation

@renovate

@renovate renovate Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

This PR contains the following updates:

Package Change Age Confidence
js-yaml@3 ^3.15.0^4.3.1 age confidence

JS-YAML: Quadratic CPU consumption in !!omap resolution (3.x and 4.x) — CVE-2026-59870 fix not backported

GHSA-5p4m-2wfm-xmqj

More information

Details

Quadratic CPU consumption in !!omap resolution (js-yaml 3.x and 4.x)
Summary

resolveYamlOmap() enforces key uniqueness for !!omap sequences with a linear
scan (objectKeys.indexOf(...)) inside the per-element loop, making resolution
O(n²) in the number of entries. A modestly sized YAML document therefore
consumes disproportionate CPU inside yaml.load(), giving a denial of service
against any consumer that parses untrusted YAML.

!!omap is registered in the default schema
(lib/schema/default.jsrequire('../type/omap')), so a plain
yaml.load(untrustedInput) with no options is affected — no custom schema or
non-default configuration is required.

This is the same weakness as CVE-2026-59870 / GHSA-724g-mxrg-4qvm, which was
fixed in the 5.x line in 5.2.1. That fix was never backported: both currently
maintained legacy lines still carry the original implementation.

Affected versions
Line Latest tested Status
3.x 3.15.0 Affected — objectKeys.indexOf(pairKey) at lib/type/omap.js:29
4.x 4.3.0 Affected — objectKeys.indexOf(pairKey) at lib/type/omap.js:30
5.x 5.2.2 Not affected — fixed in 5.2.1 (uses a Set)

Both figures are the newest release of each line at the time of writing, so
this is not a "you are on an old version" issue.

Details

lib/type/omap.js (js-yaml 4.3.0):

if (objectKeys.indexOf(pairKey) === -1) objectKeys.push(pairKey)
else return false

objectKeys grows by one element per entry, and Array.prototype.indexOf is a
linear scan, so resolving an n-entry !!omap performs roughly
1 + 2 + … + n comparisons — quadratic in n. The work happens synchronously
inside yaml.load(), blocking the event loop for its whole duration.

The 5.x line already solves exactly this by tracking seen keys in a Set
(src/tag/sequence/omap.ts):

if (carrier.seen.has(key)) return 'duplicate key in ordered map'
carrier.seen.add(key)
Proof of concept
// poc.js  —  node poc.js
const yaml = require('js-yaml');
const doc = n => '!!omap\n' + Array.from({length: n}, (_, i) => `- k${i}: ${i}`).join('\n') + '\n';

for (const n of [10000, 20000, 40000, 80000]) {
  const d = doc(n), t = Date.now();
  yaml.load(d);                      // default schema, no options
  console.log(`n=${n} bytes=${d.length} load=${Date.now() - t}ms`);
}
Measured (node v20.20.2, default heap, no flags)

js-yaml 4.3.0

n=10000  bytes=137787   load=54ms
n=20000  bytes=297787   load=169ms
n=40000  bytes=617787   load=646ms
n=80000  bytes=1257787  load=2607ms

js-yaml 3.15.0

n=10000  bytes=137787   load=53ms
n=20000  bytes=297787   load=166ms
n=40000  bytes=617787   load=641ms
n=80000  bytes=1257787  load=2567ms

Runtime grows by a factor of ~4 for each doubling of n, which is the
signature of O(n²) (linear growth would be ~2×).

Scaling further: a 2.48 MB document with 150,000 entries blocked
yaml.load() for 10.8 seconds.

Impact

Any service that parses attacker-influenced YAML with js-yaml 3.x or 4.x can be
stalled with a small input. Because the loop is synchronous, a single request
blocks the Node.js event loop and stalls every other request in the process —
so the amplification is per-process, not just per-request.

Suggested severity: consistent with CVE-2026-59870 (the same weakness in
5.x), i.e. Availability-only impact, network attack vector, no privileges or
user interaction required.

Suggested fix

Mirror the 5.x fix — replace the linear scan with a Set:

// lib/type/omap.js
const seen = new Set()
// ...
if (seen.has(pairKey)) return false
seen.add(pairKey)

This preserves the existing duplicate-key rejection semantics exactly while
making resolution O(n). A maxOmapLength-style cap would also work, but the
Set matches what 5.x already ships and requires no new option.

References
  • CVE-2026-59870 / GHSA-724g-mxrg-4qvm — same weakness in 5.0.0–5.2.0, fixed in 5.2.1
  • lib/type/omap.js (3.x, 4.x) — the affected resolver
  • lib/schema/default.js — registers !!omap in the default schema
Discovery

Found by an automated static-analysis and executed-proof-of-concept scanner run
against js-yaml 4.2.0, then manually verified against 3.15.0 and 4.3.0 by
executing the proof of concept above. All timings in this report were measured
on the current releases of each line, not on the version originally scanned.

Severity

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

References

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


Release Notes

nodeca/js-yaml (js-yaml@3)

v4.3.1

Compare Source

v4.3.0

Compare Source

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

Security
  • Fix prototype pollution issue in yaml merge (<<) operator.

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 in docs for details of 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.15.1

Compare Source


Configuration

📅 Schedule: (in timezone 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 requested a review from mishushakov as a code owner August 10, 2026 17:25
@cla-bot cla-bot Bot added the cla-signed label Aug 10, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 602644ce8e

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread pnpm-lock.yaml Outdated
dependencies:
graceful-fs: 4.2.11
js-yaml: 3.15.0
js-yaml: 5.2.3

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Do not put js-yaml 5 under read-yaml-file 1

This replacement leaves read-yaml-file@1.1.0 installed but gives it js-yaml@5.2.3. That read-yaml-file line is the old @manypkg/get-packages YAML reader used by the changesets stack in this lockfile, and it depends on js-yaml 3's safeLoad API; js-yaml >=4 removed that API, so any @changesets/read/@manypkg path that reads pnpm-workspace.yaml will throw at runtime. Please upgrade/override read-yaml-file to a js-yaml-5-compatible release, or keep this transitive edge on a compatible js-yaml version.

Useful? React with 👍 / 👎.

@renovate
renovate Bot force-pushed the renovate/npm-js-yaml3-vulnerability branch from 602644c to bd9d7e5 Compare August 10, 2026 17:40
@renovate renovate Bot changed the title Update dependency js-yaml@3 to v5 [SECURITY] Update dependency js-yaml@3 to v4 [SECURITY] Aug 10, 2026
@renovate renovate Bot changed the title Update dependency js-yaml@3 to v4 [SECURITY] Update dependency js-yaml@3 to v5 [SECURITY] Aug 11, 2026
@renovate
renovate Bot force-pushed the renovate/npm-js-yaml3-vulnerability branch 2 times, most recently from e1221ad to e618f18 Compare August 12, 2026 04:34
@renovate renovate Bot changed the title Update dependency js-yaml@3 to v5 [SECURITY] Update dependency js-yaml@3 to v4 [SECURITY] Aug 12, 2026
@renovate
renovate Bot force-pushed the renovate/npm-js-yaml3-vulnerability branch from e618f18 to bd2bc42 Compare August 12, 2026 12:36
@renovate renovate Bot changed the title Update dependency js-yaml@3 to v4 [SECURITY] Update dependency js-yaml@3 to v5 [SECURITY] Aug 12, 2026
@renovate
renovate Bot force-pushed the renovate/npm-js-yaml3-vulnerability branch from bd2bc42 to 2a86ef6 Compare August 12, 2026 22:53
@renovate renovate Bot changed the title Update dependency js-yaml@3 to v5 [SECURITY] Update dependency js-yaml@3 to v4 [SECURITY] Aug 12, 2026
@renovate
renovate Bot force-pushed the renovate/npm-js-yaml3-vulnerability branch from 2a86ef6 to 0e54d88 Compare August 14, 2026 17:54
@renovate renovate Bot changed the title Update dependency js-yaml@3 to v4 [SECURITY] Update dependency js-yaml@3 to v5 [SECURITY] Aug 14, 2026
@renovate renovate Bot changed the title Update dependency js-yaml@3 to v5 [SECURITY] Update dependency js-yaml@3 to v4 [SECURITY] Aug 15, 2026
@renovate
renovate Bot force-pushed the renovate/npm-js-yaml3-vulnerability branch from 0e54d88 to ef0a647 Compare August 15, 2026 00:45
@renovate renovate Bot changed the title Update dependency js-yaml@3 to v4 [SECURITY] Update dependency js-yaml@3 to v5 [SECURITY] Aug 17, 2026
@renovate
renovate Bot force-pushed the renovate/npm-js-yaml3-vulnerability branch from ef0a647 to 5ddded4 Compare August 17, 2026 07:11
@renovate renovate Bot changed the title Update dependency js-yaml@3 to v5 [SECURITY] Update dependency js-yaml@3 to v4 [SECURITY] Aug 17, 2026
@renovate
renovate Bot force-pushed the renovate/npm-js-yaml3-vulnerability branch from 5ddded4 to 82e1d38 Compare August 17, 2026 12:36
@renovate renovate Bot changed the title Update dependency js-yaml@3 to v4 [SECURITY] Update dependency js-yaml@3 to v5 [SECURITY] Aug 17, 2026
@renovate
renovate Bot force-pushed the renovate/npm-js-yaml3-vulnerability branch from 82e1d38 to 8e09247 Compare August 17, 2026 13:24
@renovate renovate Bot changed the title Update dependency js-yaml@3 to v5 [SECURITY] Update dependency js-yaml@3 to v4 [SECURITY] Aug 17, 2026
@renovate
renovate Bot force-pushed the renovate/npm-js-yaml3-vulnerability branch from 8e09247 to b02d71e Compare August 17, 2026 13:32
@renovate renovate Bot changed the title Update dependency js-yaml@3 to v4 [SECURITY] Update dependency js-yaml@3 to v5 [SECURITY] Aug 17, 2026
@renovate
renovate Bot force-pushed the renovate/npm-js-yaml3-vulnerability branch from b02d71e to 8152143 Compare August 17, 2026 13:57
@renovate renovate Bot changed the title Update dependency js-yaml@3 to v5 [SECURITY] Update dependency js-yaml@3 to v4 [SECURITY] Aug 17, 2026
@renovate
renovate Bot force-pushed the renovate/npm-js-yaml3-vulnerability branch from 8152143 to eb8b119 Compare August 17, 2026 16:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants