VYPR
Moderate severityNVD Advisory· Published Nov 13, 2025· Updated Jan 29, 2026

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

CVE-2025-64718

Description

js-yaml is a JavaScript YAML parser and dumper. In js-yaml before 4.1.1 and 3.14.2, 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. The problem is patched in js-yaml 4.1.1 and 3.14.2. Users 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).

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

js-yaml before 4.1.1 and 3.14.2 allows prototype pollution via the YAML merge (<<) operator, enabling attackers to modify object prototypes.

Vulnerability

Overview

CVE-2025-64718 is a prototype pollution vulnerability in js-yaml, a popular JavaScript YAML parser and dumper. The flaw exists in versions before 4.1.1 and 3.14.2, specifically in how the YAML merge operator (<<) handles keys during mapping. When parsing untrusted YAML documents, an attacker can inject a key named __proto__ to pollute the prototype of the resulting object, thereby modifying default properties across the application [1][3].

Exploitation

The exploit is triggered by crafting a YAML document that uses the merge operator to set properties on __proto__. No authentication or special privileges are required beyond the ability to submit a YAML document to the parser. Any application using js-yaml to parse untrusted input—such as configuration files, API payloads, or user uploads—is vulnerable. The attack vector is local or remote depending on how the parser is integrated, but the prerequisite is always that the attacker can supply YAML content [2][4].

Impact

Successful prototype pollution can lead to a wide range of security impacts, including denial of service, property injection, and potentially arbitrary code execution if the polluted properties affect security-critical logic. In Node.js environments, this could bypass runtime protections or alter the behavior of dependencies that rely on object prototype checks [2][4].

Mitigation

The issue is patched in js-yaml version 4.1.1 and 3.14.2 [3][4]. Users are strongly advised to update immediately. As a server-side workaround, running Node.js with the --disable-proto=delete flag can mitigate the pollution vector, though this is not a complete fix. Deno users are protected by default due to built-in prototype pollution protections [1][2].

AI Insight generated on May 19, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
js-yamlnpm
>= 4.0.0, < 4.1.14.1.1
js-yamlnpm
< 3.14.23.14.2

Affected products

1

Patches

2
5278870a1745

fix prototype pollution in merge (<<) (#731)

https://github.com/nodeca/js-yamlMarc HassanNov 14, 2025via ghsa
2 files changed · +41 2
  • lib/js-yaml/loader.js+18 2 modified
    @@ -121,6 +121,22 @@ function charFromCodepoint(c) {
       );
     }
     
    +// set a property of a literal object, while protecting against prototype pollution,
    +// see https://github.com/nodeca/js-yaml/issues/164 for more details
    +function setProperty(object, key, value) {
    +  // used for this specific key only because Object.defineProperty is slow
    +  if (key === '__proto__') {
    +    Object.defineProperty(object, key, {
    +      configurable: true,
    +      enumerable: true,
    +      writable: true,
    +      value: value
    +    });
    +  } else {
    +    object[key] = value;
    +  }
    +}
    +
     var simpleEscapeCheck = new Array(256); // integer, for fast access
     var simpleEscapeMap = new Array(256);
     for (var i = 0; i < 256; i++) {
    @@ -278,7 +294,7 @@ function mergeMappings(state, destination, source, overridableKeys) {
         key = sourceKeys[index];
     
         if (!_hasOwnProperty.call(destination, key)) {
    -      destination[key] = source[key];
    +      setProperty(destination, key, source[key]);
           overridableKeys[key] = true;
         }
       }
    @@ -334,7 +350,7 @@ function storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valu
           state.position = startPos || state.position;
           throwError(state, 'duplicated mapping key');
         }
    -    _result[keyNode] = valueNode;
    +    setProperty(_result, keyNode, valueNode);
         delete overridableKeys[keyNode];
       }
     
    
  • test/issues/0164.js+23 0 added
    @@ -0,0 +1,23 @@
    +'use strict';
    +
    +
    +var assert = require('assert');
    +var yaml = require('../../');
    +
    +
    +test('should define __proto__ as a value (not invoke setter)', function () {
    +  var object = yaml.load('{ __proto__: {polluted: bar} }');
    +
    +  assert.strictEqual(({}).hasOwnProperty.call(yaml.load('{}'), '__proto__'), false);
    +  assert.strictEqual(({}).hasOwnProperty.call(object, '__proto__'), true);
    +  assert(!object.polluted);
    +});
    +
    +
    +test('should merge __proto__ as a value with << operator', function () {
    +  var object = yaml.load('\npayload: &ref\n  polluted: bar\n\nfoo:\n  <<:\n    __proto__: *ref\n  ');
    +
    +  assert.strictEqual(({}).hasOwnProperty.call(yaml.load('{}'), '__proto__'), false);
    +  assert.strictEqual(({}).hasOwnProperty.call(object.foo, '__proto__'), true);
    +  assert(!object.foo.polluted);
    +});
    
383665ff4248

fix prototype pollution in merge (<<)

https://github.com/nodeca/js-yamlAlex KocharinNov 11, 2025via ghsa
3 files changed · +41 14
  • CHANGELOG.md+5 0 modified
    @@ -6,6 +6,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
     and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
     
     
    +## [4.1.1] - 2025-11-12
    +### Security
    +- Fix prototype pollution issue in yaml merge (<<) operator.
    +
    +
     ## [4.1.0] - 2021-04-15
     ### Added
     - Types are now exported as `yaml.types.XXX`.
    
  • lib/loader.js+18 12 modified
    @@ -120,6 +120,22 @@ function charFromCodepoint(c) {
       );
     }
     
    +// set a property of a literal object, while protecting against prototype pollution,
    +// see https://github.com/nodeca/js-yaml/issues/164 for more details
    +function setProperty(object, key, value) {
    +  // used for this specific key only because Object.defineProperty is slow
    +  if (key === '__proto__') {
    +    Object.defineProperty(object, key, {
    +      configurable: true,
    +      enumerable: true,
    +      writable: true,
    +      value,
    +    });
    +  } else {
    +    object[key] = value;
    +  }
    +}
    +
     var simpleEscapeCheck = new Array(256); // integer, for fast access
     var simpleEscapeMap = new Array(256);
     for (var i = 0; i < 256; i++) {
    @@ -298,7 +314,7 @@ function mergeMappings(state, destination, source, overridableKeys) {
         key = sourceKeys[index];
     
         if (!_hasOwnProperty.call(destination, key)) {
    -      destination[key] = source[key];
    +      setProperty(destination, key, source[key]);
           overridableKeys[key] = true;
         }
       }
    @@ -358,17 +374,7 @@ function storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valu
           throwError(state, 'duplicated mapping key');
         }
     
    -    // used for this specific key only because Object.defineProperty is slow
    -    if (keyNode === '__proto__') {
    -      Object.defineProperty(_result, keyNode, {
    -        configurable: true,
    -        enumerable: true,
    -        writable: true,
    -        value: valueNode
    -      });
    -    } else {
    -      _result[keyNode] = valueNode;
    -    }
    +    setProperty(_result, keyNode, valueNode);
         delete overridableKeys[keyNode];
       }
     
    
  • test/issues/0164.js+18 2 modified
    @@ -6,9 +6,25 @@ const yaml = require('../../');
     
     
     it('should define __proto__ as a value (not invoke setter)', function () {
    -  let object = yaml.load('{ __proto__: {foo: bar} }');
    +  let object = yaml.load('{ __proto__: {polluted: bar} }');
     
       assert.strictEqual(({}).hasOwnProperty.call(yaml.load('{}'), '__proto__'), false);
       assert.strictEqual(({}).hasOwnProperty.call(object, '__proto__'), true);
    -  assert(!object.foo);
    +  assert(!object.polluted);
    +});
    +
    +
    +it('should merge __proto__ as a value with << operator', function () {
    +  let object = yaml.load(`
    +payload: &ref
    +  polluted: bar
    +
    +foo:
    +  <<:
    +    __proto__: *ref
    +  `);
    +
    +  assert.strictEqual(({}).hasOwnProperty.call(yaml.load('{}'), '__proto__'), false);
    +  assert.strictEqual(({}).hasOwnProperty.call(object.foo, '__proto__'), true);
    +  assert(!object.foo.polluted);
     });
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

6

News mentions

0

No linked articles in our index yet.