VYPR
Critical severity9.8NVD Advisory· Published Feb 9, 2026· Updated Apr 29, 2026

CVE-2026-1615

CVE-2026-1615

Description

Versions of the package jsonpath before 1.3.0 are vulnerable to Arbitrary Code Injection via unsafe evaluation of user-supplied JSON Path expressions. The library relies on the static-eval module to process JSON Path input, which is not designed to handle untrusted data safely. An attacker can exploit this vulnerability by supplying a malicious JSON Path expression that, when evaluated, executes arbitrary JavaScript code, leading to Remote Code Execution in Node.js environments or Cross-site Scripting (XSS) in browser contexts. This affects all methods that evaluate JSON Paths against objects, including .query, .nodes, .paths, .value, .parent, and .apply.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
jsonpathnpm
< 1.3.01.3.0

Affected products

1

Patches

2
b61111f07ac1

Merge pull request #197 from dfop02/fix-CVE-2026-1615

https://github.com/dchester/jsonpathDavid ChesterMar 5, 2026via ghsa
2 files changed · +338 2
  • lib/handlers.js+151 2 modified
    @@ -3,6 +3,152 @@ var slice = require('./slice');
     var _evaluate = require('static-eval');
     var _uniq = require('underscore').uniq;
     
    +// Property names that must never be accessible in expressions.
    +// Mitigates prototype pollution and constructor escape attacks.
    +var UNSAFE_PROPERTY_NAMES = Object.create(null);
    +
    +/* jshint -W069: true */
    +UNSAFE_PROPERTY_NAMES['constructor'] = true;
    +UNSAFE_PROPERTY_NAMES['__proto__'] = true;
    +UNSAFE_PROPERTY_NAMES['prototype'] = true;
    +/* jshint -W069: false */
    +
    +function isUnsafePropertyName(name) {
    +  return typeof name === 'string' && UNSAFE_PROPERTY_NAMES[name] === true;
    +}
    +
    +function isSafeAst(ast) {
    +  if (!ast || typeof ast !== 'object') return false;
    +
    +  function walk(node) {
    +    if (!node || typeof node !== 'object' || !node.type) {
    +      return false;
    +    }
    +
    +    switch (node.type) {
    +
    +      // ===== SAFE TERMINALS =====
    +
    +      case 'Literal':
    +        return true;
    +
    +      case 'Identifier':
    +        // Only allow the special scope identifier
    +        return node.name === '@';
    +
    +
    +      // ===== PROPERTY ACCESS =====
    +
    +      case 'MemberExpression': {
    +        if (!walk(node.object)) {
    +          return false;
    +        }
    +
    +        // Non-computed: obj.property
    +        if (!node.computed && node.property.type === 'Identifier') {
    +          if (isUnsafePropertyName(node.property.name)) {
    +            return false;
    +          }
    +          return true;
    +        }
    +
    +        // Computed: obj["property"]
    +        if (node.computed) {
    +          if (!walk(node.property)) {
    +            return false;
    +          }
    +
    +          if (
    +            node.property.type === 'Literal' &&
    +            isUnsafePropertyName(String(node.property.value))
    +          ) {
    +            return false;
    +          }
    +
    +          return true;
    +        }
    +
    +        return false;
    +      }
    +
    +
    +      // ===== EXPRESSIONS =====
    +
    +      case 'UnaryExpression':
    +        return walk(node.argument);
    +
    +      case 'BinaryExpression':
    +      case 'LogicalExpression':
    +        return walk(node.left) && walk(node.right);
    +
    +      case 'ConditionalExpression':
    +        return (
    +          walk(node.test) &&
    +          walk(node.consequent) &&
    +          walk(node.alternate)
    +        );
    +
    +      case 'ArrayExpression':
    +        for (var i = 0; i < node.elements.length; i++) {
    +          if (!walk(node.elements[i])) {
    +            return false;
    +          }
    +        }
    +        return true;
    +
    +      case 'ObjectExpression':
    +        for (var j = 0; j < node.properties.length; j++) {
    +          var prop = node.properties[j];
    +
    +          // Reject unsafe keys
    +          if (
    +            prop.key &&
    +            (
    +              (prop.key.type === 'Identifier' &&
    +               isUnsafePropertyName(prop.key.name)) ||
    +              (prop.key.type === 'Literal' &&
    +               isUnsafePropertyName(String(prop.key.value)))
    +            )
    +          ) {
    +            return false;
    +          }
    +
    +          if (!walk(prop.value)) {
    +            return false;
    +          }
    +        }
    +        return true;
    +
    +
    +      // ===== EXPLICITLY REJECT DANGEROUS TYPES =====
    +      // Security: do not rely on default deny; list each code-execution / escape vector.
    +
    +      case 'CallExpression':
    +      case 'NewExpression':
    +      case 'FunctionExpression':
    +      case 'ArrowFunctionExpression':
    +      case 'ThisExpression':
    +      case 'AssignmentExpression':
    +      case 'UpdateExpression':
    +      case 'SequenceExpression':
    +      case 'TemplateLiteral':
    +      case 'TemplateElement':
    +      case 'TaggedTemplateExpression':
    +      case 'ReturnStatement':
    +      case 'ExpressionStatement':
    +        return false;
    +
    +
    +      // ===== DEFAULT DENY =====
    +
    +      default:
    +        return false;
    +    }
    +  }
    +
    +  return walk(ast);
    +}
    +
     var Handlers = function() {
       return this.initialize.apply(this, arguments);
     }
    @@ -239,8 +385,11 @@ function _traverse(passable) {
       }
     }
     
    -function evaluate() {
    -  try { return _evaluate.apply(this, arguments) }
    +function evaluate(ast, scope) {
    +  if (!isSafeAst(ast)) {
    +    throw new Error('Unsafe expression: script and filter expressions may only access the current node (@) with safe property names');
    +  }
    +  try { return _evaluate(ast, scope) }
       catch (e) { }
     }
     
    
  • test/security.js+187 0 modified
    @@ -48,4 +48,191 @@ suite('security', function() {
         }, /Unsafe key/);
         assert.equal(({}).polluted, undefined);
       });
    +
    +  suite('CVE-2026-1615: blocks code injection in filter/script expressions', function() {
    +    var data = { a: {}, b: [1, 2, 3] };
    +
    +    test('rejects constructor access in filter expression', function() {
    +      assert.throws(function() {
    +        jp.query(data, '$[?(@.constructor)]');
    +      }, /Unsafe expression/);
    +    });
    +
    +    test('rejects constructor.constructor in filter expression', function() {
    +      assert.throws(function() {
    +        jp.query(data, '$[?(@.constructor.constructor)]');
    +      }, /Unsafe expression/);
    +    });
    +
    +    test('rejects chained constructor.constructor call: @.foo["constructor"]["constructor"](...)()', function() {
    +      assert.throws(function() {
    +        jp.query(data, '$[?(@.foo["constructor"]["constructor"]("return process")())]');
    +      }, /Unsafe expression/);
    +    });
    +
    +    test('rejects __proto__ access in filter expression', function() {
    +      assert.throws(function() {
    +        jp.query(data, '$[?(@.__proto__)]');
    +      }, /Unsafe expression/);
    +    });
    +
    +    test('rejects function call in filter expression', function() {
    +      assert.throws(function() {
    +        jp.query(data, '$[?(process.exit(1))]');
    +      }, /Unsafe expression/);
    +    });
    +
    +    test('rejects constructor access in script expression', function() {
    +      var scriptData = { a: [1, 2, 3] };
    +      assert.throws(function() {
    +        jp.query(scriptData, '$[(@.constructor)]');
    +      }, /Unsafe expression/);
    +    });
    +
    +    test('allows safe filter expressions', function() {
    +      var storeData = { store: { book: [ { price: 5 }, { price: 15 } ] } };
    +      var results = jp.query(storeData, '$..book[?(@.price<10)]');
    +      assert.deepEqual(results, [ { price: 5 } ]);
    +    });
    +
    +    test('allows safe script expressions', function() {
    +      var bookData = { book: [ { id: 1 }, { id: 2 }, { id: 3 } ] };
    +      var results = jp.nodes(bookData, '$..book[(@.length-1)]');
    +      assert.deepEqual(results[0].value, { id: 3 });
    +    });
    +
    +    test('rejects bracket notation constructor: @["constructor"]', function() {
    +      assert.throws(function() { jp.query(data, '$[?(@["constructor"])]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects bracket notation __proto__: @["__proto__"]', function() {
    +      assert.throws(function() { jp.query(data, '$[?(@["__proto__"])]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects bracket notation prototype: @["prototype"]', function() {
    +      assert.throws(function() { jp.query(data, '$[?(@["prototype"])]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects ObjectExpression with unsafe key: { "__proto__": @ }', function() {
    +      assert.throws(function() { jp.query(data, '$[?({ "__proto__": @ })]'); }, /Unsafe expression|Unexpected token/);
    +    });
    +
    +    test('rejects ObjectExpression with unsafe key: { "constructor": @ }', function() {
    +      assert.throws(function() { jp.query(data, '$[?({ "constructor": @ })]'); }, /Unsafe expression|Unexpected token/);
    +    });
    +
    +    test('rejects ObjectExpression with unsafe key: { "prototype": @ }', function() {
    +      assert.throws(function() { jp.query(data, '$[?({ "prototype": @ })]'); }, /Unsafe expression|Unexpected token/);
    +    });
    +
    +    test('rejects unicode escape constructor in bracket: @["\\u0063onstructor"]', function() {
    +      assert.throws(function() { jp.query(data, '$[?(@["\\u0063onstructor"])]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects unicode escape __proto__ in bracket', function() {
    +      var path = '$[?(@["\\u005f\\u005fproto\\u005f\\u005f"])]';
    +      assert.throws(function() { jp.query(data, path); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects IIFE: (function(){return 1})()', function() {
    +      assert.throws(function() { jp.query(data, '$[?((function(){return 1})())]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects direct function call: process.exit(1)', function() {
    +      assert.throws(function() { jp.query(data, '$[?(process.exit(1))]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects require() call', function() {
    +      assert.throws(function() { jp.query(data, '$[?(require("fs"))]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects eval() call', function() {
    +      assert.throws(function() { jp.query(data, '$[?(eval("1"))]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects globalThis / global identifier', function() {
    +      assert.throws(function() { jp.query(data, '$[?(globalThis)]'); }, /Unsafe expression/);
    +      assert.throws(function() { jp.query(data, '$[?(global)]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects NewExpression: new Function("return 1")()', function() {
    +      assert.throws(function() { jp.query(data, '$[?(new Function("return 1")())]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects JSFuck-style: [] ["filter"]["constructor"]', function() {
    +      assert.throws(function() { jp.query(data, '$[?([]["filter"]["constructor"])]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects JSFuck-style constructor call (no @)', function() {
    +      assert.throws(function() { jp.query(data, '$[?([]["filter"]["constructor"]("return 1")())]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects sequence expression: (1, process.exit)(1)', function() {
    +      assert.throws(function() { jp.query(data, '$[?((1, process.exit)(1))]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects method call on @: @.valueOf()', function() {
    +      assert.throws(function() { jp.query(data, '$[?(@.valueOf())]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects method call: @.toString()', function() {
    +      assert.throws(function() { jp.query(data, '$[?(@.toString())]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects template literal in computed: @[`constructor`]', function() {
    +      assert.throws(function() { jp.query(data, '$[?(@[`constructor`])]'); }, /Unsafe expression|Unexpected token|ILLEGAL/);
    +    });
    +
    +    test('rejects tagged template (code execution vector)', function() {
    +      assert.throws(function() { jp.query(data, '$[?(String.raw`x`)]'); }, /Unsafe expression|Unexpected token|ILLEGAL/);
    +    });
    +
    +    test('rejects ArrowFunctionExpression', function() {
    +      assert.throws(function() { jp.query(data, '$[?((()=>1)())]'); }, /Unsafe expression|Unexpected token/);
    +    });
    +
    +    test('rejects ThisExpression (this)', function() {
    +      assert.throws(function() { jp.query(data, '$[?(this)]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects script expression with constructor', function() {
    +      assert.throws(function() { jp.query(data, '$[(@.constructor)]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects script expression with call', function() {
    +      assert.throws(function() { jp.query(data, '$[((function(){return 0})())]'); }, /Unsafe expression/);
    +    });
    +
    +    test('allows @.length (no call)', function() {
    +      var r = jp.query(data, '$[?(@.length)]');
    +      assert.ok(Array.isArray(r));
    +    });
    +
    +    test('allows bracket with safe key: @["length"]', function() {
    +      var r = jp.query(data, '$[?(@["length"])]');
    +      assert.ok(Array.isArray(r));
    +    });
    +
    +    test('allows @["@class"] (existing test pattern)', function() {
    +      var d = { DIV: [{ '@class': 'value', val: 5 }] };
    +      var r = jp.query(d, '$..DIV[?(@["@class"]=="value")]');
    +      assert.deepEqual(r, d.DIV);
    +    });
    +
    +    test('rejects prototype access in filter', function() {
    +      assert.throws(function() { jp.query(data, '$[?(@.prototype)]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects comma/sequence that could hide call', function() {
    +      assert.throws(function() { jp.query(data, '$[?((0, eval)("1"))]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects AssignmentExpression', function() {
    +      assert.throws(function() { jp.query(data, '$[?((x=1)==1)]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects UpdateExpression (++, --)', function() {
    +      assert.throws(function() { jp.query(data, '$[?(@.x++)]'); }, /Unsafe expression/);
    +    });
    +  });
     });
    
491e2e01de2f

Attempt to fix CVE-2026-1615 vulnerability

https://github.com/dchester/jsonpathDiogo FernandesFeb 19, 2026via ghsa
2 files changed · +338 2
  • lib/handlers.js+151 2 modified
    @@ -3,6 +3,152 @@ var slice = require('./slice');
     var _evaluate = require('static-eval');
     var _uniq = require('underscore').uniq;
     
    +// Property names that must never be accessible in expressions.
    +// Mitigates prototype pollution and constructor escape attacks.
    +var UNSAFE_PROPERTY_NAMES = Object.create(null);
    +
    +/* jshint -W069: true */
    +UNSAFE_PROPERTY_NAMES['constructor'] = true;
    +UNSAFE_PROPERTY_NAMES['__proto__'] = true;
    +UNSAFE_PROPERTY_NAMES['prototype'] = true;
    +/* jshint -W069: false */
    +
    +function isUnsafePropertyName(name) {
    +  return typeof name === 'string' && UNSAFE_PROPERTY_NAMES[name] === true;
    +}
    +
    +function isSafeAst(ast) {
    +  if (!ast || typeof ast !== 'object') return false;
    +
    +  function walk(node) {
    +    if (!node || typeof node !== 'object' || !node.type) {
    +      return false;
    +    }
    +
    +    switch (node.type) {
    +
    +      // ===== SAFE TERMINALS =====
    +
    +      case 'Literal':
    +        return true;
    +
    +      case 'Identifier':
    +        // Only allow the special scope identifier
    +        return node.name === '@';
    +
    +
    +      // ===== PROPERTY ACCESS =====
    +
    +      case 'MemberExpression': {
    +        if (!walk(node.object)) {
    +          return false;
    +        }
    +
    +        // Non-computed: obj.property
    +        if (!node.computed && node.property.type === 'Identifier') {
    +          if (isUnsafePropertyName(node.property.name)) {
    +            return false;
    +          }
    +          return true;
    +        }
    +
    +        // Computed: obj["property"]
    +        if (node.computed) {
    +          if (!walk(node.property)) {
    +            return false;
    +          }
    +
    +          if (
    +            node.property.type === 'Literal' &&
    +            isUnsafePropertyName(String(node.property.value))
    +          ) {
    +            return false;
    +          }
    +
    +          return true;
    +        }
    +
    +        return false;
    +      }
    +
    +
    +      // ===== EXPRESSIONS =====
    +
    +      case 'UnaryExpression':
    +        return walk(node.argument);
    +
    +      case 'BinaryExpression':
    +      case 'LogicalExpression':
    +        return walk(node.left) && walk(node.right);
    +
    +      case 'ConditionalExpression':
    +        return (
    +          walk(node.test) &&
    +          walk(node.consequent) &&
    +          walk(node.alternate)
    +        );
    +
    +      case 'ArrayExpression':
    +        for (var i = 0; i < node.elements.length; i++) {
    +          if (!walk(node.elements[i])) {
    +            return false;
    +          }
    +        }
    +        return true;
    +
    +      case 'ObjectExpression':
    +        for (var j = 0; j < node.properties.length; j++) {
    +          var prop = node.properties[j];
    +
    +          // Reject unsafe keys
    +          if (
    +            prop.key &&
    +            (
    +              (prop.key.type === 'Identifier' &&
    +               isUnsafePropertyName(prop.key.name)) ||
    +              (prop.key.type === 'Literal' &&
    +               isUnsafePropertyName(String(prop.key.value)))
    +            )
    +          ) {
    +            return false;
    +          }
    +
    +          if (!walk(prop.value)) {
    +            return false;
    +          }
    +        }
    +        return true;
    +
    +
    +      // ===== EXPLICITLY REJECT DANGEROUS TYPES =====
    +      // Security: do not rely on default deny; list each code-execution / escape vector.
    +
    +      case 'CallExpression':
    +      case 'NewExpression':
    +      case 'FunctionExpression':
    +      case 'ArrowFunctionExpression':
    +      case 'ThisExpression':
    +      case 'AssignmentExpression':
    +      case 'UpdateExpression':
    +      case 'SequenceExpression':
    +      case 'TemplateLiteral':
    +      case 'TemplateElement':
    +      case 'TaggedTemplateExpression':
    +      case 'ReturnStatement':
    +      case 'ExpressionStatement':
    +        return false;
    +
    +
    +      // ===== DEFAULT DENY =====
    +
    +      default:
    +        return false;
    +    }
    +  }
    +
    +  return walk(ast);
    +}
    +
     var Handlers = function() {
       return this.initialize.apply(this, arguments);
     }
    @@ -239,8 +385,11 @@ function _traverse(passable) {
       }
     }
     
    -function evaluate() {
    -  try { return _evaluate.apply(this, arguments) }
    +function evaluate(ast, scope) {
    +  if (!isSafeAst(ast)) {
    +    throw new Error('Unsafe expression: script and filter expressions may only access the current node (@) with safe property names');
    +  }
    +  try { return _evaluate(ast, scope) }
       catch (e) { }
     }
     
    
  • test/security.js+187 0 modified
    @@ -48,4 +48,191 @@ suite('security', function() {
         }, /Unsafe key/);
         assert.equal(({}).polluted, undefined);
       });
    +
    +  suite('CVE-2026-1615: blocks code injection in filter/script expressions', function() {
    +    var data = { a: {}, b: [1, 2, 3] };
    +
    +    test('rejects constructor access in filter expression', function() {
    +      assert.throws(function() {
    +        jp.query(data, '$[?(@.constructor)]');
    +      }, /Unsafe expression/);
    +    });
    +
    +    test('rejects constructor.constructor in filter expression', function() {
    +      assert.throws(function() {
    +        jp.query(data, '$[?(@.constructor.constructor)]');
    +      }, /Unsafe expression/);
    +    });
    +
    +    test('rejects chained constructor.constructor call: @.foo["constructor"]["constructor"](...)()', function() {
    +      assert.throws(function() {
    +        jp.query(data, '$[?(@.foo["constructor"]["constructor"]("return process")())]');
    +      }, /Unsafe expression/);
    +    });
    +
    +    test('rejects __proto__ access in filter expression', function() {
    +      assert.throws(function() {
    +        jp.query(data, '$[?(@.__proto__)]');
    +      }, /Unsafe expression/);
    +    });
    +
    +    test('rejects function call in filter expression', function() {
    +      assert.throws(function() {
    +        jp.query(data, '$[?(process.exit(1))]');
    +      }, /Unsafe expression/);
    +    });
    +
    +    test('rejects constructor access in script expression', function() {
    +      var scriptData = { a: [1, 2, 3] };
    +      assert.throws(function() {
    +        jp.query(scriptData, '$[(@.constructor)]');
    +      }, /Unsafe expression/);
    +    });
    +
    +    test('allows safe filter expressions', function() {
    +      var storeData = { store: { book: [ { price: 5 }, { price: 15 } ] } };
    +      var results = jp.query(storeData, '$..book[?(@.price<10)]');
    +      assert.deepEqual(results, [ { price: 5 } ]);
    +    });
    +
    +    test('allows safe script expressions', function() {
    +      var bookData = { book: [ { id: 1 }, { id: 2 }, { id: 3 } ] };
    +      var results = jp.nodes(bookData, '$..book[(@.length-1)]');
    +      assert.deepEqual(results[0].value, { id: 3 });
    +    });
    +
    +    test('rejects bracket notation constructor: @["constructor"]', function() {
    +      assert.throws(function() { jp.query(data, '$[?(@["constructor"])]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects bracket notation __proto__: @["__proto__"]', function() {
    +      assert.throws(function() { jp.query(data, '$[?(@["__proto__"])]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects bracket notation prototype: @["prototype"]', function() {
    +      assert.throws(function() { jp.query(data, '$[?(@["prototype"])]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects ObjectExpression with unsafe key: { "__proto__": @ }', function() {
    +      assert.throws(function() { jp.query(data, '$[?({ "__proto__": @ })]'); }, /Unsafe expression|Unexpected token/);
    +    });
    +
    +    test('rejects ObjectExpression with unsafe key: { "constructor": @ }', function() {
    +      assert.throws(function() { jp.query(data, '$[?({ "constructor": @ })]'); }, /Unsafe expression|Unexpected token/);
    +    });
    +
    +    test('rejects ObjectExpression with unsafe key: { "prototype": @ }', function() {
    +      assert.throws(function() { jp.query(data, '$[?({ "prototype": @ })]'); }, /Unsafe expression|Unexpected token/);
    +    });
    +
    +    test('rejects unicode escape constructor in bracket: @["\\u0063onstructor"]', function() {
    +      assert.throws(function() { jp.query(data, '$[?(@["\\u0063onstructor"])]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects unicode escape __proto__ in bracket', function() {
    +      var path = '$[?(@["\\u005f\\u005fproto\\u005f\\u005f"])]';
    +      assert.throws(function() { jp.query(data, path); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects IIFE: (function(){return 1})()', function() {
    +      assert.throws(function() { jp.query(data, '$[?((function(){return 1})())]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects direct function call: process.exit(1)', function() {
    +      assert.throws(function() { jp.query(data, '$[?(process.exit(1))]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects require() call', function() {
    +      assert.throws(function() { jp.query(data, '$[?(require("fs"))]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects eval() call', function() {
    +      assert.throws(function() { jp.query(data, '$[?(eval("1"))]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects globalThis / global identifier', function() {
    +      assert.throws(function() { jp.query(data, '$[?(globalThis)]'); }, /Unsafe expression/);
    +      assert.throws(function() { jp.query(data, '$[?(global)]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects NewExpression: new Function("return 1")()', function() {
    +      assert.throws(function() { jp.query(data, '$[?(new Function("return 1")())]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects JSFuck-style: [] ["filter"]["constructor"]', function() {
    +      assert.throws(function() { jp.query(data, '$[?([]["filter"]["constructor"])]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects JSFuck-style constructor call (no @)', function() {
    +      assert.throws(function() { jp.query(data, '$[?([]["filter"]["constructor"]("return 1")())]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects sequence expression: (1, process.exit)(1)', function() {
    +      assert.throws(function() { jp.query(data, '$[?((1, process.exit)(1))]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects method call on @: @.valueOf()', function() {
    +      assert.throws(function() { jp.query(data, '$[?(@.valueOf())]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects method call: @.toString()', function() {
    +      assert.throws(function() { jp.query(data, '$[?(@.toString())]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects template literal in computed: @[`constructor`]', function() {
    +      assert.throws(function() { jp.query(data, '$[?(@[`constructor`])]'); }, /Unsafe expression|Unexpected token|ILLEGAL/);
    +    });
    +
    +    test('rejects tagged template (code execution vector)', function() {
    +      assert.throws(function() { jp.query(data, '$[?(String.raw`x`)]'); }, /Unsafe expression|Unexpected token|ILLEGAL/);
    +    });
    +
    +    test('rejects ArrowFunctionExpression', function() {
    +      assert.throws(function() { jp.query(data, '$[?((()=>1)())]'); }, /Unsafe expression|Unexpected token/);
    +    });
    +
    +    test('rejects ThisExpression (this)', function() {
    +      assert.throws(function() { jp.query(data, '$[?(this)]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects script expression with constructor', function() {
    +      assert.throws(function() { jp.query(data, '$[(@.constructor)]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects script expression with call', function() {
    +      assert.throws(function() { jp.query(data, '$[((function(){return 0})())]'); }, /Unsafe expression/);
    +    });
    +
    +    test('allows @.length (no call)', function() {
    +      var r = jp.query(data, '$[?(@.length)]');
    +      assert.ok(Array.isArray(r));
    +    });
    +
    +    test('allows bracket with safe key: @["length"]', function() {
    +      var r = jp.query(data, '$[?(@["length"])]');
    +      assert.ok(Array.isArray(r));
    +    });
    +
    +    test('allows @["@class"] (existing test pattern)', function() {
    +      var d = { DIV: [{ '@class': 'value', val: 5 }] };
    +      var r = jp.query(d, '$..DIV[?(@["@class"]=="value")]');
    +      assert.deepEqual(r, d.DIV);
    +    });
    +
    +    test('rejects prototype access in filter', function() {
    +      assert.throws(function() { jp.query(data, '$[?(@.prototype)]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects comma/sequence that could hide call', function() {
    +      assert.throws(function() { jp.query(data, '$[?((0, eval)("1"))]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects AssignmentExpression', function() {
    +      assert.throws(function() { jp.query(data, '$[?((x=1)==1)]'); }, /Unsafe expression/);
    +    });
    +
    +    test('rejects UpdateExpression (++, --)', function() {
    +      assert.throws(function() { jp.query(data, '$[?(@.x++)]'); }, /Unsafe expression/);
    +    });
    +  });
     });
    

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

9

News mentions

0

No linked articles in our index yet.