js-yaml (npm)
Registry: npm Weekly Downloads: ~130,000,000 (as of 2026-04-12) Repository: https://github.com/nodeca/js-yaml Security Contact: GitHub Security Advisory (private reporting enabled) Current Status: audit-ingested (finding disputed)
Audit History
| Date | Auditor | Scope | Methodology | Findings | Source | |------|---------|-------|-------------|----------|--------| | 2026-04-12 | @travis-burmaster | full-source (loader, dumper, all types, schema) | hybrid (manual review + PoC) | 6 findings reviewed; highest-severity alias-expansion DoS claim disputed by maintainer as downstream serialization behavior rather than package vulnerability | oss-security-kb |
Audit scope: js-yaml 4.1.1, 3867 lines across 24 files. Loader (1733 lines), dumper (965 lines), all 13 type handlers, schema system. Commit f8e56bd (nodeca/js-yaml main branch, 2026-04-12).
Findings
Disputed Finding
D1: Alias Expansion / Serialization Amplification (maintainer-disputed as package vulnerability)
Severity: Under review / disputed
Status: Maintainer response says this is downstream JSON.stringify behavior, not a js-yaml parser vulnerability
A 308-byte YAML payload was observed to produce 269 million characters when the resulting structure was serialized (JSON.stringify), approximately 873,513x amplification. The maintainer response on issue #742 argues the parser is returning the requested structure and that the blow-up is being attributed to downstream serialization rather than a package security defect.
PoC:
a: &a ['lol','lol','lol','lol','lol','lol','lol','lol','lol']
b: &b [*a,*a,*a,*a,*a,*a,*a,*a,*a]
c: &c [*b,*b,*b,*b,*b,*b,*b,*b,*b]
d: &d [*c,*c,*c,*c,*c,*c,*c,*c,*c]
e: &e [*d,*d,*d,*d,*d,*d,*d,*d,*d]
f: &f [*e,*e,*e,*e,*e,*e,*e,*e,*e]
g: &g [*f,*f,*f,*f,*f,*f,*f,*f,*f]
h: &h [*g,*g,*g,*g,*g,*g,*g,*g,*g]
Verified: 308 bytes input, 4ms parse, 269MB on stringify, 873,513x amplification.
Missing protections: no maxAliasCount, no nesting depth limit, no expanded size limit, no input length limit. Code acknowledges risk at loader.js:330 but only mitigates for mapping keys.
Impact: At minimum, this is an operational safety / dangerous-defaults concern for applications that parse attacker-controlled YAML and then serialize or traverse the expanded structure. Whether it should be classified as a package vulnerability is currently disputed by the maintainer.
Medium Severity
M1: Implicit Type Coercion on Untrusted Input
Scalars like yes, no, on, off, true, false, null, ~ silently coerce to native JS types under the default schema. Applications must use FAILSAFE_SCHEMA to prevent this.
Code: loader.js:1498-1508
M2: Binary Type OOM -- No Size Limit
constructYamlBinary (type/binary.js:35) decodes base64 with no size limit. Intermediate JS array uses 8+ bytes per byte. A 1GB base64 input could consume several GB of heap.
Code: type/binary.js:35
M3: json:true Disables Duplicate Key Detection
When json: true, the duplicate key check (loader.js:368) is skipped. An attacker can craft YAML with a benign first value and a malicious duplicate that silently overwrites it.
Code: loader.js:368-375
Low Severity
L1: Anchor Name Collision Silently Overwrites
Two nodes with the same anchor name: second silently replaces first. Subsequent aliases resolve to the last-defined anchor.
Code: loader.js:1472
L2: Key Coercion Collapses Distinct Types
null/~ both become string "null", 0x7B/123 both become "123". Different YAML keys can collide after coercion.
Code: loader.js:353
Confirmed Safe
| Area | Status |
|------|--------|
| __proto__ prototype pollution | Mitigated via defineProperty (loader.js:127) |
| constructor.prototype global pollution | Not exploitable (clobbers own property only) |
| Merge key (<<) bypass | Not vulnerable (setProperty guard applies) |
| All regex patterns (6 tested) | No catastrophic backtracking (ReDoS-safe) |
| Dangerous YAML tags (!!js/function, !!js/regexp) | Removed in v4 default schema |
| Cross-document contamination | Not possible (anchorMap reset per document) |
| Tag injection via string values | Not possible (tags parsed by dedicated syntax) |
| toString-based code execution in keys | Blocked (loader.js:348) |
Known Vulnerabilities
| CVE / Issue | Severity | Description | Fixed in | Source |
|-------------|----------|-------------|----------|--------|
| CVE-2013-4660 | Critical | Arbitrary code execution via !!js/function tag | 3.0.0 (removed dangerous types) | osv.dev |
| REPORTED / DISPUTED: Alias expansion amplification | Under review | Alias expansion can lead to extreme downstream serialization amplification; maintainer disputes that this is a package vulnerability | disputed | This audit + upstream issue #742 |
Recommendations for Developers
- Never parse untrusted YAML without size limits -- validate input length before calling
yaml.load() - Use
FAILSAFE_SCHEMAfor untrusted input to prevent implicit type coercion - Be cautious serializing or recursively traversing expanded alias structures
- Monitor memory usage in services that parse YAML from external sources
- Treat the alias-expansion issue as disputed until upstream accepts it as a package vulnerability or a stronger parser-level exhaustion case is demonstrated
Related Pages
- [[npm/index]]
- [[npm/express]]
Last updated: 2026-04-12 | Sources: 6 (upstream repository, npm registry, source code audit of js-yaml 4.1.1, CVE databases, PoC verification, upstream issue #742 maintainer response) Auditor contact: @travis-burmaster