Node.js CVE-2026-34211
MEDIUMSeverity by source
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
Primary rating from GitHub Advisory · only source for this CVE.
CVSS VectorGitHub Advisory
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
Lifecycle Timeline
3Blast Radius
ecosystem impact- 16 npm packages depend on @nyariv/sandboxjs (6 direct, 10 indirect)
Ecosystem-wide dependent count for version 0.8.36.
DescriptionGitHub Advisory
Summary
The @nyariv/sandboxjs parser contains unbounded recursion in the restOfExp function and the lispify/lispifyExpr call chain. An attacker can crash any Node.js process that parses untrusted input by supplying deeply nested expressions (e.g., ~2000 nested parentheses), causing a RangeError: Maximum call stack size exceeded that terminates the process.
Details
The root cause is in src/parser.ts. The restOfExp function (line 443) iterates through expression characters, and when it encounters a closing bracket that doesn't match the expected firstOpening, it recursively calls itself at line 503:
// src/parser.ts:486-505
} else if (closings[char]) {
// ...
if (char === firstOpening) {
done = true;
break;
} else {
const skip = restOfExp(constants, part.substring(i + 1), [], char); // line 503
cache.set(skip.start - 1, skip.end);
i += skip.length + 1;
}
}Each nested bracket ((, [, {) adds a stack frame. There is no depth counter or limit check. The function signature has no depth parameter:
export function restOfExp(
constants: IConstants,
part: CodeString,
tests?: RegExp[],
quote?: string,
firstOpening?: string,
closingsTests?: RegExp[],
details: restDetails = {},
): CodeString {A second unbounded recursive path exists through lispify → lispTypes.get(type) → group handler → lispifyExpr (line 672) → lispify, which processes parenthesized groups recursively with no depth limit.
All public API methods (Sandbox.parse(), Sandbox.compile(), Sandbox.compileAsync(), Sandbox.compileExpression(), Sandbox.compileExpressionAsync()) pass user input directly to parse() with no input validation or depth limiting.
A RangeError: Maximum call stack size exceeded in Node.js is not a catchable exception in the normal sense - it crashes the current execution context and, in a server handling requests synchronously, can crash the entire process.
PoC
# Install the package
npm install @nyariv/sandboxjs
# Create test file
cat > poc.js << 'EOF'
const { default: Sandbox } = require('@nyariv/sandboxjs');
const s = new Sandbox();
// Trigger via nested parentheses
console.log("Testing nested parentheses...");
try {
s.compile('('.repeat(2000) + '1' + ')'.repeat(2000));
console.log("No crash");
} catch(e) {
console.log(`Crash: ${e.constructor.name}: ${e.message}`);
}
// Trigger via nested array brackets
console.log("Testing nested array brackets...");
try {
s.compile('a' + '[0]'.repeat(2000));
console.log("No crash");
} catch(e) {
console.log(`Crash: ${e.constructor.name}: ${e.message}`);
}
EOF
node poc.jsExpected output:
Testing nested parentheses...
Crash: RangeError: Maximum call stack size exceeded
Testing nested array brackets...
Crash: RangeError: Maximum call stack size exceededVerified on Node.js v22 with @nyariv/sandboxjs@0.8.35.
Impact
Any application using @nyariv/sandboxjs to parse untrusted user input is vulnerable to denial of service. Since SandboxJS is explicitly designed to safely execute untrusted JavaScript, its primary use case involves untrusted input - making this a high-impact vulnerability for its intended deployment scenario.
An attacker can crash the host Node.js process with a single crafted input string. In server-side applications, this causes complete service disruption. The attack payload is trivial to construct and requires no authentication.
Recommended Fix
Add a depth parameter to restOfExp and throw a ParseError when a maximum depth is exceeded:
// src/parser.ts - restOfExp function
const MAX_PARSE_DEPTH = 256;
export function restOfExp(
constants: IConstants,
part: CodeString,
tests?: RegExp[],
quote?: string,
firstOpening?: string,
closingsTests?: RegExp[],
details: restDetails = {},
depth: number = 0, // ADD depth parameter
): CodeString {
if (depth > MAX_PARSE_DEPTH) {
throw new ParseError('Expression nesting depth exceeded', part.toString());
}
// ... existing code ...
// At line 503, pass depth + 1:
const skip = restOfExp(constants, part.substring(i + 1), [], char, undefined, undefined, {}, depth + 1);
// At line 480 (template literal), also pass depth + 1:
const skip = restOfExp(constants, part.substring(i + 2), [], '{', undefined, undefined, {}, depth + 1);
}Similarly, add depth tracking to lispify and lispifyExpr:
function lispify(
constants: IConstants,
part: CodeString,
expected?: readonly string[],
lispTree?: Lisp,
topLevel = false,
depth: number = 0, // ADD depth parameter
): Lisp {
if (depth > MAX_PARSE_DEPTH) {
throw new ParseError('Expression nesting depth exceeded', part.toString());
}
// ... pass depth + 1 to recursive lispify/lispifyExpr calls ...
}AnalysisAI
Denial of service in @nyariv/sandboxjs through unbounded recursion in the parser allows remote attackers to crash Node.js processes by submitting deeply nested expressions (approximately 2000 nested parentheses or brackets), triggering a RangeError that terminates the application. All public API methods (Sandbox.parse, Sandbox.compile, Sandbox.compileAsync, Sandbox.compileExpression, Sandbox.compileExpressionAsync) are vulnerable with no input validation or depth limiting. A proof-of-concept demonstrating the crash exists; no public active exploitation has been reported at the time of analysis.
Technical ContextAI
The @nyariv/sandboxjs library is a Node.js package designed to safely parse and execute untrusted JavaScript expressions in a sandboxed environment. The vulnerability stems from two unbounded recursive code paths: (1) the restOfExp function in src/parser.ts (line 503) recursively processes mismatched closing brackets without a depth counter, and (2) the lispify/lispifyExpr call chain (line 672) processes parenthesized groups recursively with no depth limit. Each nested bracket, parenthesis, or array subscript adds a call stack frame. The root cause is classified as CWE-674 (Uncontrolled Recursion). The affected product is the npm package @nyariv/sandboxjs at version 0.8.35 and likely earlier versions. Node.js RangeError exceptions generated from stack overflow are not normally catchable and crash the current execution context; in synchronous server implementations, this cascades to process termination.
RemediationAI
Upgrade @nyariv/sandboxjs to a patched version released by the vendor that implements recursion depth limits. The recommended architectural fix, as documented in the advisory, is to add a depth parameter (with a recommended maximum of 256) to the restOfExp and lispify functions, throwing a ParseError when nesting depth is exceeded. Check the GitHub Security Advisory at https://github.com/advisories/GHSA-8pfc-jjgw-6g26 and the repository at https://github.com/nyariv/SandboxJS for the specific patched version number and release notes. Until a patch is available or applied, organizations should avoid parsing untrusted user input with this library, or implement a custom input validation wrapper that rejects expressions exceeding a safe nesting depth (e.g., 50-100 levels) before passing them to the Sandbox API. For production servers, consider deploying the application in a containerized environment with process restart policies to minimize availability impact from potential crashes.
FortiOS and FortiProxy contain an authentication bypass via the Node.js websocket module allowing unauthenticated remote
Eval injection vulnerability in the internals.batch function in lib/batch.js in the bassmaster plugin before 1.5.2 for t
Flowise version 3.0.5 contains a remote code execution vulnerability in the CustomMCP node. The mcpServerConfig paramete
Node.js 8.5.0 before 8.6.0 allows remote attackers to access unintended files, because a change to ".." handling was inc
An issue was discovered in the node-serialize package 0.0.4 for Node.js. Rated critical severity (CVSS 9.8), this vulner
Directory traversal vulnerability in the st module before 0.2.5 for Node.js allows remote attackers to read arbitrary fi
Multiple SQL injection vulnerabilities in the Manage Accounts page in the AccountManagement.asmx service in the Solarwin
The JS-YAML module before 2.0.5 for Node.js parses input without properly considering the unsafe !!js/function tag, whic
Directory traversal vulnerability in lib/app/index.js in Geddy before 13.0.8 for Node.js allows remote attackers to read
Credential-harvesting malware compromised 84 versions of 42 TanStack npm packages on 2026-05-11 via chained GitHub Actio
Eval injection vulnerability in index.js in the syntax-error package before 1.1.1 for Node.js 0.10.x, as used in IBM Rat
The HTTP server in Node.js 0.10.x before 0.10.21 and 0.8.x before 0.8.26 allows remote attackers to cause a denial of se
Same weakness CWE-674 – Uncontrolled Recursion
View allSame technique Denial Of Service
View allShare
External POC / Exploit Code
Leaving vuln.today
GHSA-8pfc-jjgw-6g26