npm / vm2
vm2
What changed in vm2 3, from its official release notes, upgrade guides and advisories. Sources checked 2026-10-18.
38 breaking116 security1 deprecations2 new APIs and options1 behavior and defaults6 fixes and other
See which of these apply to your code, ranked, in your agent:
npx @unstale/cli initvm2 3164 changes
Breaking changes 38
Host views that do not own their whole backing store are delivered bounded, preventing sandbox access to unrelated host buffers; their buffer and parent are exact-size copies and byteOffset and offset read as 0.
Custom resolver answers are now authorized by boundary-matched paths; {module, path} answers must name a package inside path, preventing sibling-package authorization.
In NodeVM, crypto.setFips is replaced with a throwing stub so guest code cannot change the FIPS mode of the host process; getFips() and the rest of crypto are unchanged.
NodeVM no longer allows child_process through require.builtin, whether requested by wildcard or by name; embedders needing it can re-expose it through require.mock.
A sloppy-mode host function called with a nullish receiver now sees undefined instead of the host global, preventing access to the host realm through this.
With
allowAsync: false, assimilating Promise static methods andArray.fromAsyncnow throw in the sandbox, and the native Promise base is not constructable from sandbox code.Raw host
__proto__getters and prototype-reading APIs can no longer be delivered to sandbox code to climb host prototype chains.The sandbox util builtin is now a vetted allowlist; host-introspection and host-mutation members are no longer forwarded, including through the deprecated sys alias.
Denying a builtin family now also denies its subpath siblings; explicitly list a subpath if it must remain available.
Sandbox-supplied paths can no longer use the OpenSSL ENGINE loader to execute a native library in the host process.
FinalizationRegistry is no longer a sandbox global by default because cleanup callbacks are not bounded by timeout.
Host frames are redacted from errors caught in the sandbox; messages are preserved, while absolute host paths and Node, file, and wasm frames are removed.
The real shared host HTTP agent is no longer exposed to sandbox code, preventing access to host request options and sockets.
The sandbox can no longer load native SQLite extensions into the host process through DatabaseSync.
The test builtin family, including subpaths, is denied and refused on explicit request because its run API can spawn a host process.
Truthy nesting configuration with a non-config
requirevalue now throws at construction instead of producing an unrestricted nested resolver.External allowlist checks no longer admit substring-sharing package names or permitted subpaths containing
..segments.External allowlist authorization no longer treats prefix-sharing sibling packages as allowlisted, including scoped package names.
Requiring
vm2from disk underrequire.externalcan no longer construct an unrestricted nested NodeVM.FinalizationRegistry cleanup callbacks can run outside timeout enforcement, so they can no longer be exposed by default.
Sandbox code can no longer replace the host thread's process-wide default CA trust store.
Frozen host objects no longer expose accessor setters through descriptor-reading paths; getter reads remain available.
The CLI now confines requires to the target script's directory and loads them inside the sandbox; scripts needing host modules should be run with node directly.
WeakRef is no longer a sandbox global by default; it can be re-exposed through the sandbox option.
Streaming WebAssembly APIs are removed from the sandbox because their Promises could expose host rejections; non-streaming WebAssembly APIs are unaffected.
Finite limits now also cover Buffer.concat, Buffer.from, Buffer.copyBytesFrom, ArrayBuffer, SharedArrayBuffer, TypedArray, and WebAssembly.Memory allocations. The default Infinity is unaffected.
NodeVM builtin: ['*'] no longer exposes os or dns, including node:os, node:dns, and dns/promises. Re-introduce a safe subset via require.mock or require.override.
Host errors reach sandbox catch blocks as sandbox-realm errors; primitive diagnostics and subclass instanceof behavior are preserved, while non-primitive properties and the host prototype chain are removed.
Sandbox-installed Array prototype setters or join overrides can no longer observe bridge-internal stack-trace state.
The builtin denylist bypass through process and inspector/promises is fixed; explicitly listing the named unsafe builtins now throws at load time.
The builtin allowlist no longer surfaces process-wide observability modules that could expose host process state.
A truthy nesting value without an explicit require config object now makes construction throw; drop nesting or provide a require config object.
Constructing a NodeVM with
{ nesting: true, require: false }now throws VMError, preventing the contradictory configuration from enabling sandbox-to-host RCE.Custom fs adapters used with require.root must implement realpathSync, or realpath() for a fully custom FileSystem class; otherwise NodeVM construction now throws a VMError.
Adds trace_events to the dangerous-builtins denylist after a Proxy<Array> category triggered a C++ assertion that aborted the host process.
Adds wasi to the denylist because its experimental syscall surface is too broad for default '*' exposure.
Blocks all code-executing constructors from crossing the bridge through property descriptors.
Blocks access to the Function constructor through getOwnPropertyDescriptor.
Security 116
Host promises delivered to the sandbox are marked handled on every route, so ignored promises no longer trigger host unhandledRejection; sandbox code can still observe rejections through its sanitized .catch.
Sandbox-initiated then, catch, and finally calls on exposed host promises now use a genuine host Promise for the result capability, preventing host settlement values from escaping into the sandbox.
vm2 contains a sandbox escape vulnerability
Bun support is experimental and compatibility is partial; JavaScriptCore has not been audited against vm2's bridge, so do not use vm2 on Bun to isolate untrusted code.
Error-carrier cycles no longer re-embed raw host proxies in rebuilt errors arrays delivered to sandbox catch code.
The default VM now protects binary-data and iterator intrinsic prototypes from host-state corruption through a host Buffer proto-walk.
vm2:
allowAsync: falsecan be bypassed through Promise thenable assimilation in VM and NodeVMvm2: Default VM can mutate host TypedArray and ArrayBuffer intrinsics after the host-prototype pollution fix
vm2: Host-returned Promise rejection can bypass vm2's unhandled-rejection hardening and terminate the host process
vm2: Sandbox Escape (NodeVM)
vm2 sandbox escape to host RCE via revisited host-wrapped AggregateError bypassing Error sanitization cycle short-circuit
vm2: util.getCallSites() bypasses GHSA-v27g-jcqj-v8rw host-frame redaction, leaks host call stack
Buffer creation no longer gives sandbox code access to Node's shared allocation pool, preventing disclosure or corruption of neighboring host buffers.
Wildcard builtin expansion now applies deny tokens using canonical names, so a
node:-prefixed deny token blocks its corresponding builtin.The apply-trap gate now handles indirection through call and apply, preventing raw host Promise rejections from reaching sandbox code.
Promise then and catch wrappers are installed in a way that protects against Node 26's native fast path exposing host Promise reactions to sandbox code.
vm2 allows a sandboxed plugin to execute native code through
node:sqlitevm2 CLI provides no sandbox isolation - host-realm require() is reachable from sandboxed scripts
vm2 crypto builtin loads attacker native code through setEngine
vm2 Custom Module Resolver Can Bypass the External Package Allowlist by Loading a Colliding Host Package
vm2 exposes host HTTPS credentials and TLS traffic through globalAgent
vm2: External module allowlist uses a raw prefix test, so a prefix-sharing sibling package is treated as allowlisted
vm2: GHSA-m283-3h24-438v fix bypass leads to host RCE via call/apply indirection
vm2: Incomplete nodejs.* symbol filtering lets sandbox override host WebStream state checks
vm2 leaks absolute host filesystem paths to sandbox code via error stack formatting
vm2: NodeVM builtin allowlist bypass via node:test.run() execArgv allows sandbox escape
vm2: NodeVM builtin denylist bypass via fs/promises despite -fs, allowing host filesystem writes
vm2 NodeVM can replace the host process TLS trust store
vm2: NodeVM nesting guard accepts array-shaped require and permits host RCE
vm2: NodeVM node:-prefixed negative builtin deny bypass exposes child_process
vm2: NodeVM
require.externalwithout an explicitrequire.rootgrants unrestricted host filesystem access and full RCEvm2 sandbox escape on Node.js 26 through a stale PromiseThenLookupChain protector
vm2 sandbox escape via WebAssembly.compileStreaming Promise species bypass
vm2: Sandboxed code can read and write host-realm memory via Node's shared Buffer pool
vm2: timeout Option Bypass via FinalizationRegistry Cleanup Callback (Unbounded Host Event-Loop Block)
vm2: vm.freeze()/vm.readonly() bypass via accessor descriptor
vm2 has Memory Exhaustion DoS via bufferAllocLimit Bypass
VM2 has Missing Error.cause Sanitization that Enables Sandbox Escape to RCE
vm2: NodeVM
builtin: ['*']exposesosanddns— process-wide observability reads AND writes that hijack the host (sibling class of GHSA-9g8x-92q2-p28f)vm2's bufferAllocLimit cap bypassed by Buffer.concat and Buffer.from arrayLike
vm2: Sandbox Breakout Using Dangerous Host Proto Mutators
Promise species hijacking in the swallow-tail is fixed, preventing access to a raw host-realm error.
NodeVM builtin denylist bypass via process and inspector/promises allows host code execution
The builtin wildcard no longer exposes undocumented underscored network builtins despite documented network exclusions.
NodeVM network builtin exclusions bypass via internal _http_client and _http_server
NodeVM observability builtins leak host process and HTTP request data
Prototype mutation through function and Reflect indirection is fixed, preventing host intrinsic prototype chains from being severed.
The bridge set trap now honors the ECMA-262 Receiver, preventing writes through child objects or Reflect.set from leaking onto host objects.
vm2 has a CVE-2023-37903 patch bypass: nesting:true without explicit require still allows full RCE
vm2 has a Sandbox Escape issue
vm2 has a sandbox escape via unblocked cross-realm Symbol.for keys + missing bridge write-trap symbol checks
vm2 is Vulnerable to Sandbox Breakout Through Promise Species
vm2's Bridge Proxy set trap ignores receiver parameter, enabling host object property injection via prototype chain
vm2 sandbox escape via JSPI-backed Promise
.finally()species bypassvm2 setup-sandbox.js violates Defense Invariant #11 in stack-trace formatter
The JSPI host-realm Promise prototype-chain issue is fixed, preventing species hijacking from delivering a raw host-realm rejection to sandbox catch handlers.
Fixes an exception-capture issue involving async generator yield* returns and thenables that could lead to RCE.
vm2 Has a Sandbox Breakout Using Async Generator
Fixes a bridge saved-state leak involving a sandbox-installed Array.prototype[N] setter that could lead to RCE.
Fixes an issue that made internal state reachable through computed-key access on globalThis.
vm2 has access to
VM2_INTERNAL_STATE_DO_NOT_USE_OR_PROGRAM_WILL_FAILvm2 has Sandbox Breakout Through Null Proto Exception
vm2 has sandbox breakout via
neutralizeArraySpeciesBatchvm2 NodeVM
nesting: truebypassesrequire: falseallowing sandbox escape and arbitrary OS command executionCloses an array species self-return sandbox escape that could enable remote code execution.
Prevents host intrinsic prototype pollution via bridge write traps.
Addresses host-heap denial of service from unbounded Buffer.alloc requests; bufferAllocLimit can cap individual requests.
Closes a sandbox escape involving symbol extraction from host objects across realms.
Closes a sandbox escape involving a trap method on a leaked handler with a forged target.
Closes a bypass of the NodeVM builtin allowlist via host-passthrough builtins.
Closes host-process denial of service from unhandled rejections caused by Promise executor throws; async rejection paths still require a host-side handler.
Closes a sandbox escape involving Promise structural leaks and SuppressedError or AggregateError sanitisation.
Closes a sandbox escape involving host Promise fulfillment callbacks and sanitiser-callback null-prototype unwrapping.
Adds realpath() to the DefaultFileSystem and VMFileSystem contracts so require.root boundary checks can canonicalize candidate paths before checking the prefix.
Canonicalizes candidate paths with realpath before the root prefix check, closing a symlink bypass that could escape the allowed root.
Embedders running untrusted async code should install a host-side handler because the fix cannot reach some async rejection paths.
vm2 Access to Host Object Enables Sandbox Escape
vm2 has a NodeVM builtin allowlist bypass via
modulebuiltin'sModule._loadthat allows sandbox escapevm2 has a NodeVM require.root bypass via symlink traversal that allows sandbox escape
VM2 Has a Sandbox Escape Issue via SuppressedError
vm2 has a Sandbox Escape via Promise Constructor Unhandled Rejection (Process Crash DoS)
vm2 has a Sandbox Escape Vulnerability
VM2 Has Sandbox Breakout Through Inspect Function
vm2 Host Promise Resolution Preserves Object Identity Across Sandbox Boundary
vm2 is Vulnerable to Host File Path Disclosure via Stack Trace Information Leak
vm2: Mutable Proxies for Host Intrinsic Prototypes Allows Sandbox Escape
vm2's Transformer Fast-Path Bypass Exposes Internal State Variable
vm2 Sandbox Access to Host Buffer.alloc Allows timeout Bypass Resulting in Memory Exhaustion
VM2 Sandbox Breakout Through __lookupGetter__
Blocks the Function constructor from crossing the bridge regardless of access path.
Blocks extraction of the Function constructor through nested property descriptors.
Blocks a host Function constructor leak through a direct handler.get() call.
Prevents proxy unwrapping that could expose the Function constructor through Object.entries.
Sanitizes SuppressedError sub-errors to prevent sandbox escape.
Prevents sandbox escape through doPreventExtensions exposure in util.inspect.
Prevents sandbox escape through getFactory exposure in util.inspect.
VM2 Has a WASM Sandbox Escape
VM2 Has Sandbox Breakout Through Promise Species
Blocks WebAssembly.JSTag to prevent a wasm-level exception catch sandbox escape in Node 25.
Prevents sandbox escape through fromOtherWithContext exposure in util.inspect.
Prevents sandbox escape via Promise static method stealing.
Prevents sandbox escape through proxy handler exposure in util.inspect.
Prevents sandbox escape via a Reflect.construct Promise species bypass.
Prevents a hasOwnProperty override from bypassing Symbol.for protections.
Prevents object key coercion from bypassing Symbol.for protections.
Prevents cross-realm symbol extraction through Object.getOwnPropertySymbols.
Prevents sandbox escape through Promise species manipulation.
Prevents a Symbol.species getter TOCTOU bypass when resetting Promise species.
Eliminates Promise species TOCTOU by unconditionally overriding the constructor.
Prevents sandbox escape via static method stealing from Promise.try.
Prevents cross-realm symbol extraction via the spread operator on bridge proxies.
Prevents sandbox escape via cross-realm symbols.
vm2 has a Sandbox Escape
Fixed a vulnerability that bypassed Promise callback sanitization.
Upstream security fixes were incorporated.
vm2 Sandbox Escape vulnerability
Deprecations 1
Using require.external without require.root now emits a one-time warning; its breadth is unchanged in this release.
New APIs and options 2
Adds a VM and NodeVM option accepting a non-negative number or Infinity to cap individual Buffer.alloc family requests from inside the sandbox; its default is Infinity.
Support for the TypeScript compiler was added.
Behavior and default changes 1
Bun compile, esbuild, pkg, and other single-file bundlers can now ship vm2 because sandbox bootstrap files are embedded in generated lib/sources.js instead of read from disk at runtime.
Fixes and other changes 6
The sandbox Proxy install is wrapped in try/catch so JavaScriptCore throwing on the sealed slot no longer aborts sandbox setup before the first run().
Fixes the .node extension handler key so native addon resolution no longer silently falls through to the default path.
Restores underlying-value output when inspecting sandbox results on Node 26+, instead of rendering nested Proxy wrappers.
Restores array iteration methods on frozen host arrays used inside the sandbox.
Allows Object.setPrototypeOf on sandbox-local objects.
Promise handlers use Reflect.apply instead of .call().