From bd3fc7c78e604099b2c64ca00434fa6a6b63899d Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 21 Jul 2026 13:26:30 +0800
Subject: [PATCH] chore: bump up js-yaml version to v4.3.0 [SECURITY] (#15298)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This PR contains the following updates:
| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [js-yaml](https://redirect.github.com/nodeca/js-yaml) | [`4.2.0` →
`4.3.0`](https://renovatebot.com/diffs/npm/js-yaml/4.2.0/4.3.0) |

|

|
---
### JS-YAML: Quadratic-complexity DoS in merge key handling via repeated
aliases
[CVE-2026-53550](https://nvd.nist.gov/vuln/detail/CVE-2026-53550) /
[GHSA-h67p-54hq-rp68](https://redirect.github.com/advisories/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
-
[https://github.com/nodeca/js-yaml/security/advisories/GHSA-h67p-54hq-rp68](https://redirect.github.com/nodeca/js-yaml/security/advisories/GHSA-h67p-54hq-rp68)
-
[https://nvd.nist.gov/vuln/detail/CVE-2026-53550](https://nvd.nist.gov/vuln/detail/CVE-2026-53550)
-
[https://github.com/advisories/GHSA-h67p-54hq-rp68](https://redirect.github.com/advisories/GHSA-h67p-54hq-rp68)
This data is provided by the [GitHub Advisory
Database](https://redirect.github.com/advisories/GHSA-h67p-54hq-rp68)
([CC-BY
4.0](https://redirect.github.com/github/advisory-database/blob/main/LICENSE.md)).
---
### js-yaml: YAML merge-key chains can force quadratic CPU consumption
[CVE-2026-59869](https://nvd.nist.gov/vuln/detail/CVE-2026-59869) /
[GHSA-52cp-r559-cp3m](https://redirect.github.com/advisories/GHSA-52cp-r559-cp3m)
More information
#### Details
##### Impact
js-yaml can spend quadratic CPU time parsing a document whose size grows
only linearly. The issue is triggered by a chain of mappings where each
mapping merges the previous one:
```yaml
a0: &a0 { k0: 0 }
a1: &a1 { <<: *a0, k1: 1 }
a2: &a2 { <<: *a1, k2: 2 }
a3: &a3 { <<: *a2, k3: 3 }
...
b: *aN
```
For each new mapping, the loader has to enumerate the keys inherited
from the previous mapping. With N chained mappings, this results in
roughly 1 + 2 + ... + N merged-key visits, i.e., O(N^2) work for O(N)
input size.
##### PoC
From N = 4000 delay become > 1s (doc size < 100K)
```js
import { performance } from 'node:perf_hooks'
import { Buffer } from 'node:buffer'
import { load, YAML11_SCHEMA } from 'js-yaml'
const n = Number(process.argv[2] || 4000)
function makeMergeChain (count) {
const lines = ['a0: &a0 { k0: 0 }']
for (let i = 1; i < count; i++) {
lines.push(`a${i}: &a${i} { <<: *a${i - 1}, k${i}: ${i} }`)
}
lines.push(`b: *a${count - 1}`)
return `${lines.join('\n')}\n`
}
const source = makeMergeChain(n)
console.log(source.split('\n').slice(0, 8).join('\n'))
console.log('...')
console.log(source.split('\n').slice(-4).join('\n'))
console.log()
console.log(`N: ${n}`)
console.log(`YAML size: ${Buffer.byteLength(source)} bytes`)
const started = performance.now()
const result = load(source, { schema: YAML11_SCHEMA })
const elapsed = performance.now() - started
console.log(`parse time: ${elapsed.toFixed(1)} ms`)
console.log(`top-level keys: ${Object.keys(result).length}`)
console.log(`b keys: ${Object.keys(result.b).length}`)
```
##### Patches
Fix released. The most robust protection is to limit the total number of
merged keys per parse call. This should close all past and future edge
cases with merge. The default 10K-key limit should be okay in most
cases.
#### 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
-
[https://github.com/nodeca/js-yaml/security/advisories/GHSA-52cp-r559-cp3m](https://redirect.github.com/nodeca/js-yaml/security/advisories/GHSA-52cp-r559-cp3m)
-
[https://nvd.nist.gov/vuln/detail/CVE-2026-59869](https://nvd.nist.gov/vuln/detail/CVE-2026-59869)
-
[https://github.com/nodeca/js-yaml/commit/24f13e79ee1343a7e30bd6f6c9d9cdbf0ac9b2b7](https://redirect.github.com/nodeca/js-yaml/commit/24f13e79ee1343a7e30bd6f6c9d9cdbf0ac9b2b7)
-
[https://github.com/nodeca/js-yaml/commit/59423c6f8cdc78742ac00e25a4dd39ef16b702e4](https://redirect.github.com/nodeca/js-yaml/commit/59423c6f8cdc78742ac00e25a4dd39ef16b702e4)
-
[https://github.com/nodeca/js-yaml/releases/tag/3.15.0](https://redirect.github.com/nodeca/js-yaml/releases/tag/3.15.0)
-
[https://github.com/nodeca/js-yaml/releases/tag/4.3.0](https://redirect.github.com/nodeca/js-yaml/releases/tag/4.3.0)
-
[https://github.com/advisories/GHSA-52cp-r559-cp3m](https://redirect.github.com/advisories/GHSA-52cp-r559-cp3m)
This data is provided by the [GitHub Advisory
Database](https://redirect.github.com/advisories/GHSA-52cp-r559-cp3m)
([CC-BY
4.0](https://redirect.github.com/github/advisory-database/blob/main/LICENSE.md)).
---
### Release Notes
nodeca/js-yaml (js-yaml)
###
[`v4.3.0`](https://redirect.github.com/nodeca/js-yaml/compare/4.2.0...33d05b5d29a8c21360f620f7e1c1706e24522eda)
[Compare
Source](https://redirect.github.com/nodeca/js-yaml/compare/4.2.0...4.3.0)
---
### 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](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/toeverything/AFFiNE).
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
yarn.lock | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/yarn.lock b/yarn.lock
index bf0c0053c7..6b66ca4dee 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -26404,25 +26404,25 @@ __metadata:
linkType: hard
"js-yaml@npm:^3.13.1, js-yaml@npm:^3.14.1":
- version: 3.14.2
- resolution: "js-yaml@npm:3.14.2"
+ version: 3.15.0
+ resolution: "js-yaml@npm:3.15.0"
dependencies:
argparse: "npm:^1.0.7"
esprima: "npm:^4.0.0"
bin:
js-yaml: bin/js-yaml.js
- checksum: 10/172e0b6007b0bf0fc8d2469c94424f7dd765c64a047d2b790831fecef2204a4054eabf4d911eb73ab8c9a3256ab8ba1ee8d655b789bf24bf059c772acc2075a1
+ checksum: 10/2fdf3a1453ed93a8e06d6ca8054c0bec145cf40ab51f305d1071736a03668b95e40f47cfd0239d7d50019b4780a18cdaca3c935def935594c9876964c49f1185
languageName: node
linkType: hard
"js-yaml@npm:^4.2.0":
- version: 4.2.0
- resolution: "js-yaml@npm:4.2.0"
+ version: 4.3.0
+ resolution: "js-yaml@npm:4.3.0"
dependencies:
argparse: "npm:^2.0.1"
bin:
js-yaml: bin/js-yaml.js
- checksum: 10/51de2067a2b44b07ba5206132e56005f8b568ff279bb4d2f645068958c56fa4827d40a6841c983234671fa0a134bf094d0b0717873c2a3d319185297af145a6d
+ checksum: 10/2bcec3a8118d7f744badeb04e14366578d234a736f353d41fe35d2305e4ce2409a8e041d277f07cd6bbc8aaa12128d650a68ce43247072519bede20962d2126f
languageName: node
linkType: hard