CVE-2023-32314: Insufficient Information (NVD-CWE-noinfo)
value: 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.
CWE description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
CVSS v3 base score: 10
Published: 2023-05-15T20:15Z
Repository: https://github.com/patriksimek/vm2
Language: JavaScript
Files changed: lib/setup-sandbox.js
Commit date: 2023-05-13 21:15:04 +0200
Commit message: Ensure host array does not leak through proxy

Diff: diff --git a/lib/setup-sandbox.js b/lib/setup-sandbox.js
index 71afa52..fbfacc4 100644
--- a/lib/setup-sandbox.js
+++ b/lib/setup-sandbox.js
@@ -19,10 +19,11 @@ const {
 } = localObject;
 
 const {
 	getPrototypeOf: localReflectGetPrototypeOf,
 	apply: localReflectApply,
+	construct: localReflectConstruct,
 	deleteProperty: localReflectDeleteProperty,
 	has: localReflectHas,
 	defineProperty: localReflectDefineProperty,
 	setPrototypeOf: localReflectSetPrototypeOf,
 	getOwnPropertyDescriptor: localReflectGetOwnPropertyDescriptor
@@ -430,10 +431,67 @@ if (AsyncFunction) {
 if (AsyncGeneratorFunction) {
 	if (!localReflectSetPrototypeOf(AsyncGeneratorFunction, proxiedFunction)) throw localUnexpected();
 	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);
 
 /*
  * Promise sanitization

Fixed code: 	construct: localReflectConstruct,
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;