Injection

JSONPath Injection in Node.js (Express) [Mar 2026] [CVE-2026-22729]

[Updated March 2026] Updated CVE-2026-22729

Overview

JSONPath injection vulnerabilities occur when an application constructs JSONPath queries by directly concatenating user-supplied input into the query string. This allows authenticated users to manipulate the query logic, potentially bypassing access controls and reading documents they should not see. The real-world CVE reference CVE-2026-22729 describes a JSONPath injection vulnerability in Spring AI's AbstractFilterExpressionConverter, where crafted filter expressions lead to unauthorized data access by injecting arbitrary JSONPath predicates. Although this CVE targets a Java project, the underlying pattern is applicable to Node.js (Express) apps that extend or mimic such filter-building behavior. In multi-tenant or metadata-driven filtering scenarios, unescaped user input can alter the semantics of the JSONPath query, enabling attackers to escape intended restrictions and access restricted documents. This guide uses that CVE as a reference point to illustrate how similar weaknesses manifest in Node.js ecosystems and outlines concrete Node.js (Express) remediation steps to prevent these injections.

Affected Versions

N/A (Java Spring AI CVE) / Node.js implementations not tied to a specific version in the provided CVE

Code Fix Example

Node.js (Express) API Security Remediation
Vulnerable:
const express = require('express');
const jsonpath = require('jsonpath');
const app = express();

// Example in-memory document store
const docStore = {
  documents: [
    { id: 1, owner: 'alice', metadata: { tag: 'private' } },
    { id: 2, owner: 'bob', metadata: { tag: 'public' } }
  ]
};

app.get('/docs', (req, res) => {
  const owner = req.query.owner; // user-controlled input
  // Vulnerable: user input is embedded directly into JSONPath expression
  const pathExpr = "$.documents[?(@.owner == '" + owner + "')]";
  const results = jsonpath.query(docStore, pathExpr);
  res.json(results);
});

app.listen(3000, () => console.log('Server started'));

Fixed (safer approach):
const express = require('express');
const jsonpath = require('jsonpath');
const app = express();

const docStore = {
  documents: [
    { id: 1, owner: 'alice', metadata: { tag: 'private' } },
    { id: 2, owner: 'bob', metadata: { tag: 'public' } }
  ]
};

app.get('/docs', (req, res) => {
  const owner = req.query.owner; // user input
  // Safe approach: avoid embedding user input into JSONPath. Retrieve candidates then filter.
  const candidates = jsonpath.query(docStore, '$.documents');
  const filtered = candidates.filter(d => d.owner === owner);
  res.json(filtered);
});

app.listen(3000, () => console.log('Server started'));

CVE References

Choose which optional cookies to allow. You can change this any time.