Moderate severityNVD Advisory· Published Jan 28, 2026· Updated Jan 29, 2026
CVE-2025-61140
CVE-2025-61140
Description
The value function in jsonpath 1.1.1 lib/index.js is vulnerable to Prototype Pollution.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
jsonpathnpm | < 1.2.0 | 1.2.0 |
Affected products
1Patches
19631412641b7CVE-2025-61140: Prevent prototype pollution in JSON path handling
2 files changed · +107 −1
lib/index.js+56 −1 modified@@ -23,6 +23,7 @@ JSONPath.prototype.parent = function(obj, string) { assert.ok(string, "we need a path"); var node = this.nodes(obj, string)[0]; + if (node) this._assert_safe_path_keys(node.path); var key = node.path.pop(); /* jshint unused:false */ return this.value(obj, node.path); } @@ -39,6 +40,7 @@ JSONPath.prototype.apply = function(obj, string, fn) { }); nodes.forEach(function(node) { + this._assert_safe_path_keys(node.path); var key = node.path.pop(); var parent = this.value(obj, this.stringify(node.path)); var val = node.value = fn.call(obj, parent[key]); @@ -56,6 +58,7 @@ JSONPath.prototype.value = function(obj, path, value) { if (arguments.length >= 3) { var node = this.nodes(obj, path).shift(); if (!node) return this._vivify(obj, path, value); + this._assert_safe_path_keys(node.path); var key = node.path.slice(-1).shift(); var parent = this.parent(obj, this.stringify(node.path)); parent[key] = value; @@ -73,13 +76,16 @@ JSONPath.prototype._vivify = function(obj, string, value) { var path = this.parser.parse(string) .map(function(component) { return component.expression.value }); + this._assert_safe_path_keys(path); + var setValue = function(path, value) { var key = path.pop(); var node = self.value(obj, path); if (!node) { setValue(path.concat(), typeof key === 'string' ? {} : []); node = self.value(obj, path); } + self._assert_safe_key(key); node[key] = value; } setValue(path, value); @@ -116,6 +122,7 @@ JSONPath.prototype.nodes = function(obj, string, count) { if (count === 0) return []; var path = this.parser.parse(string); + this._assert_safe_components(path); var handlers = this.handlers; var partials = [ { path: ['$'], value: obj } ]; @@ -206,6 +213,7 @@ JSONPath.prototype._normalize = function(path) { if (component == '$' && index === 0) return; if (typeof component == "string" && component.match("^" + dict.identifier + "$")) { + this._assert_safe_key(component); _path.push({ operation: 'member', @@ -218,13 +226,15 @@ JSONPath.prototype._normalize = function(path) { var type = typeof component == "number" ? 'numeric_literal' : 'string_literal'; + if (type === 'string_literal') this._assert_safe_key(component); + _path.push({ operation: 'subscript', scope: 'child', expression: { value: component, type: type } }); } - }); + }, this); return _path; @@ -236,10 +246,55 @@ JSONPath.prototype._normalize = function(path) { throw new Error("couldn't understand path " + path); } +JSONPath.prototype._assert_safe_key = function(key) { + if (_is_unsafe_key(key)) { + throw new Error("Unsafe key in JSONPath: " + key); + } +} + +JSONPath.prototype._assert_safe_path_keys = function(path) { + if (!path || !path.forEach) return; + path.forEach(function(key) { + if (key === '$') return; + if (typeof key === 'string') this._assert_safe_key(key); + }, this); +} + +JSONPath.prototype._assert_safe_components = function(components) { + var self = this; + if (!components || !components.forEach) return; + + var checkExpression = function(expression) { + if (!expression) return; + if (expression.type === 'identifier' || expression.type === 'string_literal') { + self._assert_safe_key(expression.value); + return; + } + + if (expression.type === 'union' && Array.isArray(expression.value)) { + expression.value.forEach(function(component) { + if (component && component.expression) { + checkExpression(component.expression); + } + }); + } + }; + + components.forEach(function(component) { + if (component && component.expression) { + checkExpression(component.expression); + } + }); +} + function _is_string(obj) { return Object.prototype.toString.call(obj) == '[object String]'; } +function _is_unsafe_key(key) { + return key === '__proto__' || key === 'prototype' || key === 'constructor'; +} + JSONPath.Handlers = Handlers; JSONPath.Parser = Parser;
test/security.js+51 −0 added@@ -0,0 +1,51 @@ +var assert = require('assert'); +var jp = require('../'); + +suite('security', function() { + + var cleanup = function() { + if (Object.prototype.polluted) { + delete Object.prototype.polluted; + } + }; + + teardown(function() { + cleanup(); + }); + + test('blocks prototype pollution via value()', function() { + cleanup(); + var data = {}; + assert.throws(function() { + jp.value(data, '$.__proto__.polluted', 'yes'); + }, /Unsafe key/); + assert.equal(({}).polluted, undefined); + }); + + test('blocks prototype pollution via apply()', function() { + cleanup(); + var data = { safe: { ok: true } }; + assert.throws(function() { + jp.apply(data, '$.__proto__.polluted', function() { return 'yes'; }); + }, /Unsafe key/); + assert.equal(({}).polluted, undefined); + }); + + test('blocks unsafe subscript access', function() { + cleanup(); + var data = {}; + assert.throws(function() { + jp.query(data, '$["__proto__"]["polluted"]'); + }, /Unsafe key/); + assert.equal(({}).polluted, undefined); + }); + + test('blocks unsafe union access', function() { + cleanup(); + var data = { safe: 1 }; + assert.throws(function() { + jp.nodes(data, "$['safe','__proto__']"); + }, /Unsafe key/); + assert.equal(({}).polluted, undefined); + }); +});
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
7- github.com/advisories/GHSA-6c59-mwgh-r2x6ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2025-61140ghsaADVISORY
- gist.github.com/Dremig/8105c189774217222a8ebea3ed4d341dghsaWEB
- github.com/dchester/jsonpath/commit/9631412641b7095f86840a7a45b5b3afc68b0fcbghsaWEB
- github.com/dchester/jsonpath/issues/181ghsaWEB
- github.com/dchester/jsonpath/issues/194ghsaWEB
- github.com/dchester/jsonpath/pull/195ghsaWEB
News mentions
0No linked articles in our index yet.