Am I vulnerable?
SandboxJS (@nyariv/sandboxjs) is a JavaScript library applications use to evaluate untrusted JavaScript expressions safely — it shows up in formula and template engines, low-code/no-code logic builders, online code editors, and serverless or automation runtimes. If your application hands user-supplied JavaScript to this library, any version at or below 0.9.5 lets that code break out of the sandbox and run on the host.
Affected versions
| Product |
Vulnerable range |
@nyariv/sandboxjs (npm) |
<= 0.9.5 |
Fixed in 0.9.6.
Diagnostic commands
All read-only. Run from your project root:
- Direct dependency:
npm ls @nyariv/sandboxjs. Vulnerable if the resolved version is ≤ 0.9.5.
- Including transitive dependencies:
npm list --all 2>/dev/null | grep sandboxjs. Any line showing @nyariv/sandboxjs@<=0.9.5 is in scope — the library is frequently pulled in indirectly, so don't stop at your top-level package.json.
- Lockfile audit:
grep -n "@nyariv/sandboxjs" package-lock.json to see every resolved version pinned in your build.
- Installed manifest:
grep -r "\"version\"" node_modules/@nyariv/sandboxjs/package.json. Confirms what's actually on disk.
Functionally, you are vulnerable if a version ≤ 0.9.5 is present and your application evaluates input that an untrusted user can influence. A sandbox that only ever runs first-party, static expressions is lower risk — but the safe assumption for any internet-facing evaluator is that the input is attacker-controlled.
Vulnerability
This is a sandbox escape (NVD classifies it as CWE-94, Improper Control of Generation of Code) carrying a CVSS v3.1 base score of 10.0 (AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H). The scope-change flag and the absence of any privilege or interaction requirement are what push it to a perfect score: code running inside the sandbox crosses a trust boundary into the host with no authentication.
The root cause is a property-access leak. SandboxJS failed to restrict sandboxed code from reading the caller, callee, and arguments properties on functions. Per the vendor advisory and corroborating analysis from Cyber Security News, sandboxed code could walk Function.caller to recover an internal runtime callback (the executor's LispType.Call handler). That handler accepted an attacker-supplied parameters object without verifying it actually originated from the executor. By forging inputs to the recovered callback, an attacker reconstructs a reference to the host's genuine Function constructor — and from there evaluates arbitrary JavaScript in the host context. Cryptika's writeup notes the published proof-of-concept demonstrates follow-on execution through Node's built-in child_process module, i.e., spawning OS commands.
A public proof-of-concept has been available since disclosure on 2026-05-28. No exploit code is reproduced here.
Threat model
Who would exploit this: The lowest-friction operators are opportunistic criminals and commodity-malware crews, because exploitation only requires getting crafted JavaScript evaluated by a vulnerable sandbox — a capability any application with a formula editor, template engine, low-code logic builder, or serverless runtime already hands to its users. With a public PoC and CVSS 10.0, targeted criminals and initial-access brokers scanning SaaS platforms and internal tooling are realistic follow-ons. State-aligned actors may use it situationally against high-value developer-tooling targets, but the broad, internet-exposed deployment shape favors mass opportunistic abuse.
What they're after:
- Initial foothold / host code execution in the Node.js process
- Credential and secret theft (env vars, API keys, cloud metadata/IAM tokens)
- Data exfiltration (database connections, tenant data in multi-tenant SaaS)
- Lateral movement into internal networks reachable from the host
- Cryptomining and resource abuse on compromised runtimes
- Persistence and supply-chain pivoting through developer/automation platforms
Attack chain: The attacker submits crafted JavaScript to any application feature that evaluates user-supplied logic inside the SandboxJS sandbox — a formula field, template, or automation step. The payload abuses the improperly restricted Function.caller to recover an exposed internal runtime callback and invokes it with malicious parameters, breaking out of the sandbox. This yields arbitrary host code execution inside the Node.js process, with no authentication or user interaction required.
Blast radius: Code execution in the host process exposes everything that process can reach — environment variables and embedded secrets, cloud instance metadata and the IAM credentials it returns, live database and cache connection strings, and any internal services the host can route to. In multi-tenant SaaS, a single escape can expose other tenants' data and shared platform credentials, turning one tenant's input into a platform-wide compromise.
Mitigation
Patch
Upgrade @nyariv/sandboxjs to 0.9.6 or later — this is the only complete fix. The patch blocks sandboxed access to the caller, callee, and arguments properties, closing the path used to recover the internal callback.
Upgrade the dependency to the fixed release:
npm install @nyariv/sandboxjs@^0.9.6
Configuration mitigation
Pin the patched version in package.json so rebuilds and transitive resolutions can't regress:
{
"dependencies": {
"@nyariv/sandboxjs": "^0.9.6"
}
}
If the library is pulled in transitively, override the resolved version using your package manager's override mechanism (npm overrides, Yarn resolutions, pnpm overrides) and rebuild your lockfile.
Compensating controls
If you cannot patch immediately:
- Treat sandbox input as untrusted RCE input. Gate the evaluation feature behind authentication and rate limits; disable it entirely for anonymous or low-trust users until patched.
- Drop the host process's privileges. Run the Node.js service as a non-root, unprivileged user, in a container with a read-only root filesystem and no outbound network egress beyond what it needs. This limits what a successful escape can reach.
- Strip secrets from the process environment. Move credentials to a runtime secrets broker the app fetches narrowly, rather than leaving cloud/IAM tokens and DB strings in env vars where escaped code can read them in one call.
- Block egress and child-process spawning. Apply seccomp/AppArmor profiles or a container runtime policy that prevents the Node process from spawning shells, and restrict outbound connections — the published PoC pivots through
child_process.
Detection (starter rules — validate before deploying)
These rules are AI-generated starter content. Test against your own telemetry and tune falsepositives before deploying to production.
Network and log signals
- Node.js application process (
node) spawning unexpected child processes such as /bin/sh, /bin/bash, cmd.exe, powershell.exe, or curl/wget shortly after evaluating a user-supplied expression — the classic post-escape command-execution stage.
- Inbound HTTP request bodies, query strings, or app logs containing sandbox-escape gadget strings:
Function.caller, .caller.caller, constructor.constructor, this.constructor.constructor, or references to process.mainModule / require( arriving at template/formula/expression-evaluation endpoints.
- Unexpected outbound connections (reverse shell, C2 beacon, exfil) originating from the Node.js application PID that normally only serves inbound traffic — especially to raw IPs or non-standard ports immediately after an evaluation.
- New or unexpected file writes by the
node process outside its working directory (/tmp, /dev/shm, the webroot), indicating dropped payloads.
- Spikes in 5xx errors, process restarts, or crash/OOM events on services known to embed
@nyariv/sandboxjs, correlated with malformed or oversized expression inputs — consistent with PoC fuzzing.
- WAF/proxy logs showing reflection primitives URL-encoded or JSON-escaped (
constructor%2Econstructor, .caller) to evade naive keyword filters on evaluator endpoints.
YARA
rule CVE_2026_43898_sandboxjs_escape_starter {
meta:
author = "CVE Brief"
description = "Starter rule: detects @nyariv/sandboxjs sandbox-escape gadget strings (Function.caller / constructor.constructor) in payloads, logs, or stored expressions for CVE-2026-43898"
reference = "CVE-2026-43898"
warning = "AI-generated starter rule — validate in your environment before deploying"
strings:
$pkg = "@nyariv/sandboxjs" ascii
$g1 = "Function.caller" ascii nocase
$g2 = ".caller.caller" ascii nocase
$g3 = "constructor.constructor" ascii nocase
$g4 = "this.constructor.constructor" ascii nocase
$g5 = "caller.constructor" ascii nocase
condition:
$pkg or 2 of ($g*)
}
Sigma
title: Node.js Application Spawning Suspicious Child Process (Possible SandboxJS Escape CVE-2026-43898)
id: 7f3a1c9e-2b4d-4e6a-9c81-0d5f8a2b6c31
status: experimental
description: >
Detects a Node.js application process unexpectedly spawning a shell or command
interpreter, which may indicate a sandbox escape via @nyariv/sandboxjs
(CVE-2026-43898) abusing Function.caller to run arbitrary host code. Replace
the id before production use and tune ParentImage to your app paths.
author: CVE Brief
date: 2026/05/29
references:
- https://nvd.nist.gov/vuln/detail/CVE-2026-43898
logsource:
category: process_creation
detection:
selection_parent:
ParentImage|endswith:
- '/node'
- '\node.exe'
selection_child:
Image|endswith:
- '/sh'
- '/bash'
- '/dash'
- '\cmd.exe'
- '\powershell.exe'
- '/curl'
- '/wget'
condition: selection_parent and selection_child
falsepositives:
- Build tooling, npm lifecycle scripts, or CI pipelines where the Node app legitimately shells out
- Applications that intentionally invoke child_process (e.g., job runners, serverless wrappers)
- Health-check or deploy scripts spawned by the same node process
level: high
Rule notes
The YARA rule keys on the package name plus reflective-escape gadgets (Function.caller, constructor.constructor) — a single gadget string is benign in legitimate JS, so it requires two or more gadgets, or the package name, to fire. The Sigma rule is behavioral (node spawning a shell or network tool) rather than exploit-specific, so it catches the post-escape command-execution stage but will also match legitimate child_process usage; tune ParentImage to your specific application binaries and replace the placeholder id before deploying. Neither rule detects a sandbox escape that stays purely in-process (e.g., reading secrets without spawning a child) — pair them with the log signals above.
References