Skip to content

Update dependency js-yaml to v4.3.2 [SECURITY] - #30614

Closed
tryghost-renovate[bot] wants to merge 1 commit into
mainfrom
renovate/npm-js-yaml-vulnerability
Closed

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

Conversation

@tryghost-renovate

Copy link
Copy Markdown
Contributor

This PR contains the following updates:

Package Change Age Confidence
js-yaml 4.3.0 → 4.3.2 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.js → require('../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).


js-yaml: maxTotalMergeKeys does not limit CPU use for empty merge sources

CVE-2026-84375 / GHSA-2883-xcg3-v3hh

More information

Details

Summary

maxTotalMergeKeys does not count empty mappings. An attacker can repeatedly merge a large sequence of them and consume significant CPU without reaching the configured limit.

Example
arr: &arr [{}, {}, {}, ...] # N empty mappings
targets:
  - <<: *arr                # repeated K times

For every target, the loader iterates all N elements of arr. This results in O(N * K) work while totalMergeKeys remains unchanged.

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

const n = 20000

const src =
  'arr: &arr [' + '{},'.repeat(n).slice(0, -1) + ']\n' +
  'targets:\n' +
  '  - <<: *arr\n'.repeat(n)

const started = performance.now()

load(src, { schema: YAML11_SCHEMA })

console.log(`${(performance.now() - started).toFixed(1)} ms`)

Observed results:

N YAML size Time
800 ~13 KB ~20 ms
3200 ~50 KB ~180 ms
20000 ~500 KB ~13 s
Impact

An attacker can submit a relatively small YAML document that causes prolonged CPU consumption despite the default maxTotalMergeKeys limit.

Fix

Count each merge-source mapping as one budget unit, in addition to counting its keys.

Difference with v5

In v3 & v4, merge is enabled by default. So, the severity score is higher.

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)

v4.3.2

Compare Source

v4.3.1

Compare Source


Configuration

📅 Schedule: (in timezone Etc/UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • Only on Sunday and Saturday (* * * * 0,6)
    • Between 11:00 PM and 11:59 PM, Monday through Friday (* 23 * * 1-5)
    • Between 12:00 AM and 05:59 AM, Monday through Saturday (* 0-5 * * 1-6)

🚦 Automerge: Enabled.

♻ 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 has been generated by Mend Renovate.

@tryghost-renovate tryghost-renovate Bot added dependencies Pull requests that update a dependency file security labels Sep 8, 2026
@tryghost-renovate

Copy link
Copy Markdown
Contributor Author

⚠️ Artifact update problem

Renovate failed to update artifacts related to this branch. You probably do not want to merge this PR as-is.

♻ Renovate will retry this branch, including artifacts, only when one of the following happens:

  • any of the package files in this branch needs updating, or
  • the branch becomes conflicted, or
  • you click the rebase/retry checkbox if found above, or
  • you rename this PR's title to start with "rebase!" to trigger it manually

The artifact failure details are included below:

File name: undefined
Post-upgrade command 'pnpm install --no-frozen-lockfile --filter @internal/scripts --prod --ignore-scripts' has not been added to the allowed list in allowedCommands
File name: undefined
Post-upgrade command 'node scripts/generate-changeset.js' has not been added to the allowed list in allowedCommands

@tryghost-renovate tryghost-renovate Bot changed the title Update dependency js-yaml to v4.3.2 [SECURITY] Update dependency js-yaml to v4.3.2 [SECURITY] - autoclosed Sep 9, 2026
@tryghost-renovate tryghost-renovate Bot closed this Sep 9, 2026
@tryghost-renovate
tryghost-renovate Bot deleted the renovate/npm-js-yaml-vulnerability branch September 9, 2026 01:15
@tryghost-renovate tryghost-renovate Bot changed the title Update dependency js-yaml to v4.3.2 [SECURITY] - autoclosed Update dependency js-yaml to v4.3.2 [SECURITY] Sep 9, 2026
@tryghost-renovate tryghost-renovate Bot reopened this Sep 9, 2026
@tryghost-renovate
tryghost-renovate Bot force-pushed the renovate/npm-js-yaml-vulnerability branch 2 times, most recently from 4281aca to 339f674 Compare September 9, 2026 01:38
@tryghost-renovate tryghost-renovate Bot changed the title Update dependency js-yaml to v4.3.2 [SECURITY] Update dependency js-yaml to v4.3.2 [SECURITY] - autoclosed Sep 9, 2026
@tryghost-renovate tryghost-renovate Bot closed this Sep 9, 2026
@tryghost-renovate tryghost-renovate Bot changed the title Update dependency js-yaml to v4.3.2 [SECURITY] - autoclosed Update dependency js-yaml to v4.3.2 [SECURITY] Sep 9, 2026
@tryghost-renovate tryghost-renovate Bot reopened this Sep 9, 2026
@tryghost-renovate
tryghost-renovate Bot force-pushed the renovate/npm-js-yaml-vulnerability branch 2 times, most recently from 339f674 to d36b0cb Compare September 9, 2026 02:36
@tryghost-renovate tryghost-renovate Bot changed the title Update dependency js-yaml to v4.3.2 [SECURITY] Update dependency js-yaml to v4.3.2 [SECURITY] - autoclosed Sep 9, 2026
@tryghost-renovate tryghost-renovate Bot closed this Sep 9, 2026
@tryghost-renovate tryghost-renovate Bot changed the title Update dependency js-yaml to v4.3.2 [SECURITY] - autoclosed Update dependency js-yaml to v4.3.2 [SECURITY] Sep 9, 2026
@tryghost-renovate tryghost-renovate Bot reopened this Sep 9, 2026
@tryghost-renovate
tryghost-renovate Bot force-pushed the renovate/npm-js-yaml-vulnerability branch 2 times, most recently from d36b0cb to e04cccd Compare September 9, 2026 03:33
@tryghost-renovate tryghost-renovate Bot changed the title Update dependency js-yaml to v4.3.2 [SECURITY] Update dependency js-yaml to v4.3.2 [SECURITY] - autoclosed Sep 9, 2026
@tryghost-renovate tryghost-renovate Bot closed this Sep 9, 2026
@tryghost-renovate tryghost-renovate Bot changed the title Update dependency js-yaml to v4.3.2 [SECURITY] - autoclosed Update dependency js-yaml to v4.3.2 [SECURITY] Sep 9, 2026
@tryghost-renovate tryghost-renovate Bot reopened this Sep 9, 2026
@tryghost-renovate
tryghost-renovate Bot force-pushed the renovate/npm-js-yaml-vulnerability branch 2 times, most recently from e04cccd to 676a6ac Compare September 9, 2026 04:32
@tryghost-renovate tryghost-renovate Bot changed the title Update dependency js-yaml to v4.3.2 [SECURITY] Update dependency js-yaml to v4.3.2 [SECURITY] - autoclosed Sep 9, 2026
@tryghost-renovate tryghost-renovate Bot closed this Sep 9, 2026
@tryghost-renovate tryghost-renovate Bot reopened this Sep 10, 2026
@tryghost-renovate
tryghost-renovate Bot force-pushed the renovate/npm-js-yaml-vulnerability branch 2 times, most recently from 1968be8 to 7d90d92 Compare September 10, 2026 02:37
@tryghost-renovate tryghost-renovate Bot changed the title Update dependency js-yaml to v4.3.2 [SECURITY] Update dependency js-yaml to v4.3.2 [SECURITY] - autoclosed Sep 10, 2026
@tryghost-renovate tryghost-renovate Bot changed the title Update dependency js-yaml to v4.3.2 [SECURITY] - autoclosed Update dependency js-yaml to v4.3.2 [SECURITY] Sep 10, 2026
@tryghost-renovate tryghost-renovate Bot reopened this Sep 10, 2026
@tryghost-renovate
tryghost-renovate Bot force-pushed the renovate/npm-js-yaml-vulnerability branch 2 times, most recently from 7d90d92 to 5d213f5 Compare September 10, 2026 03:33
@tryghost-renovate tryghost-renovate Bot changed the title Update dependency js-yaml to v4.3.2 [SECURITY] Update dependency js-yaml to v4.3.2 [SECURITY] - autoclosed Sep 10, 2026
@tryghost-renovate tryghost-renovate Bot changed the title Update dependency js-yaml to v4.3.2 [SECURITY] - autoclosed Update dependency js-yaml to v4.3.2 [SECURITY] Sep 10, 2026
@tryghost-renovate tryghost-renovate Bot reopened this Sep 10, 2026
@tryghost-renovate
tryghost-renovate Bot force-pushed the renovate/npm-js-yaml-vulnerability branch 2 times, most recently from 5d213f5 to 1120896 Compare September 10, 2026 04:32
@tryghost-renovate tryghost-renovate Bot changed the title Update dependency js-yaml to v4.3.2 [SECURITY] Update dependency js-yaml to v4.3.2 [SECURITY] - autoclosed Sep 10, 2026
@tryghost-renovate tryghost-renovate Bot changed the title Update dependency js-yaml to v4.3.2 [SECURITY] - autoclosed Update dependency js-yaml to v4.3.2 [SECURITY] Sep 11, 2026
@tryghost-renovate tryghost-renovate Bot reopened this Sep 11, 2026
@tryghost-renovate
tryghost-renovate Bot force-pushed the renovate/npm-js-yaml-vulnerability branch from 1120896 to 44cecc6 Compare September 11, 2026 01:00
@tryghost-renovate tryghost-renovate Bot changed the title Update dependency js-yaml to v4.3.2 [SECURITY] Update dependency js-yaml to v4.3.2 [SECURITY] - autoclosed Sep 11, 2026
@tryghost-renovate tryghost-renovate Bot changed the title Update dependency js-yaml to v4.3.2 [SECURITY] - autoclosed Update dependency js-yaml to v4.3.2 [SECURITY] Sep 11, 2026
@tryghost-renovate tryghost-renovate Bot reopened this Sep 11, 2026
@tryghost-renovate
tryghost-renovate Bot force-pushed the renovate/npm-js-yaml-vulnerability branch 2 times, most recently from 44cecc6 to 6f7a66d Compare September 11, 2026 01:36
@tryghost-renovate tryghost-renovate Bot changed the title Update dependency js-yaml to v4.3.2 [SECURITY] Update dependency js-yaml to v4.3.2 [SECURITY] - autoclosed Sep 11, 2026
@tryghost-renovate

Copy link
Copy Markdown
Contributor Author

Renovate Ignore Notification

Because you closed this PR without merging, Renovate will ignore this update (4.3.2). You will get a PR once a newer version is released. To ignore this dependency forever, add it to the ignoreDeps array of your Renovate config.

If you accidentally closed this PR, or if you changed your mind: rename this PR to get a fresh replacement PR.

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 security

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants