VYPR
Critical severityNVD Advisory· Published May 15, 2023· Updated Jan 22, 2025

Sandbox Escape

CVE-2023-32314

Description

vm2 is a sandbox that can run untrusted code with Node's built-in modules. A sandbox escape vulnerability exists in vm2 for versions up to and including 3.9.17. It abuses an unexpected creation of a host object based on the specification of Proxy. As a result a threat actor can bypass the sandbox protections to gain remote code execution rights on the host running the sandbox. This vulnerability was patched in the release of version 3.9.18 of vm2. Users are advised to upgrade. There are no known workarounds for this vulnerability.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

A sandbox escape in vm2 versions ≤3.9.17 allows remote code execution by exploiting unexpected host object creation via Proxy.

CVE-2023-32314 is a sandbox escape vulnerability in vm2, a Node.js sandbox for running untrusted code. The flaw, present in all versions up to and including 3.9.17, abuses the specification of the ECMAScript Proxy object. Specifically, when the [[Call]] internal method of a Proxy is invoked, the argument list is converted to an array using CreateArrayFromList, which creates a native host array. This unintended host object can then be used to escape the sandbox and access the host's Function constructor [1][2][4].

Exploitation

To exploit the vulnerability, an attacker provides untrusted code to the VM.run() method. The provided proof-of-concept (PoC) constructs an Error whose name property's toString method is a Proxy. Inside the Proxy's apply trap, the args parameter—now a host array—allows access to args.constructor.constructor, which yields the host's Function constructor. From there, the attacker can execute arbitrary system commands by invoking process.mainModule.require('child_process').execSync [4]. No authentication or special privileges are required beyond the ability to submit code to the vm2 sandbox.

Impact

Successful exploitation grants the attacker remote code execution (RCE) on the host running the vm2 sandbox, with the privileges of the Node.js process. This completely bypasses the intended sandbox isolation, allowing data exfiltration, system compromise, or further lateral movement within the host environment [1][2].

Remediation

The vulnerability is patched in vm2 version 3.9.18. The fix introduces makeSafeHandlerArgs to wrap handler arguments in a safe array, preventing the leak of host objects through Proxy traps. Users are strongly advised to upgrade immediately, as no known workarounds exist. The project also cautions that in-process sandboxing is inherently challenging and recommends defense-in-depth or more robust isolation mechanisms such as separate processes or containers [1][3].

AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
vm2npm
< 3.9.183.9.18

Affected products

2

Patches

1
d88105f99752

Ensure host array does not leak through proxy

https://github.com/patriksimek/vm2XmiliaHMay 13, 2023via ghsa
1 file changed · +58 0
  • lib/setup-sandbox.js+58 0 modified
    @@ -21,6 +21,7 @@ const {
     const {
     	getPrototypeOf: localReflectGetPrototypeOf,
     	apply: localReflectApply,
    +	construct: localReflectConstruct,
     	deleteProperty: localReflectDeleteProperty,
     	has: localReflectHas,
     	defineProperty: localReflectDefineProperty,
    @@ -432,6 +433,63 @@ if (AsyncGeneratorFunction) {
     	overrideWithProxy(AsyncGeneratorFunction.prototype, 'constructor', AsyncGeneratorFunction, makeCheckFunction(true, true));
     }
     
    +function makeSafeHandlerArgs(args) {
    +	const sArgs = ensureThis(args);
    +	if (sArgs === args) return args;
    +	const a = [];
    +	for (let i=0; i < sArgs.length; i++) {
    +		localReflectDefineProperty(a, i, {
    +			__proto__: null,
    +			value: sArgs[i],
    +			enumerable: true,
    +			configurable: true,
    +			writable: true
    +		});
    +	}
    +	return a;
    +}
    +
    +const makeSafeArgs = Object.freeze({
    +	__proto__: null,
    +	apply(target, thiz, args) {
    +		return localReflectApply(target, thiz, makeSafeHandlerArgs(args));
    +	},
    +	construct(target, args, newTarget) {
    +		return localReflectConstruct(target, makeSafeHandlerArgs(args), newTarget);
    +	}
    +});
    +
    +const proxyHandlerHandler = Object.freeze({
    +	__proto__: null,
    +	get(target, name, receiver) {
    +		const value = target.handler[name];
    +		if (typeof value !== 'function') return value;
    +		return new LocalProxy(value, makeSafeArgs);
    +	}
    +});
    +
    +function wrapProxyHandler(args) {
    +	if (args.length < 2) return args;
    +	const handler = args[1];
    +	args[1] = new LocalProxy({__proto__: null, handler}, proxyHandlerHandler);
    +	return args;
    +}
    +
    +const proxyHandler = Object.freeze({
    +	__proto__: null,
    +	apply(target, thiz, args) {
    +		return localReflectApply(target, thiz, wrapProxyHandler(args));
    +	},
    +	construct(target, args, newTarget) {
    +		return localReflectConstruct(target, wrapProxyHandler(args), newTarget);
    +	}
    +});
    +
    +const proxiedProxy = new LocalProxy(LocalProxy, proxyHandler);
    +
    +overrideWithProxy(LocalProxy, 'revocable', LocalProxy.revocable, proxyHandler);
    +
    +global.Proxy = proxiedProxy;
     global.Function = proxiedFunction;
     global.eval = new LocalProxy(localEval, EvalHandler);
     
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

6

News mentions

0

No linked articles in our index yet.