CVE-2023-30547: Insufficient Information (NVD-CWE-noinfo)
value: vm2 is a sandbox that can run untrusted code with whitelisted Node's built-in modules. There exists a vulnerability in exception sanitization of vm2 for versions up to 3.9.16, allowing attackers to raise an unsanitized host exception inside `handleException()` which can be used to escape the sandbox and run arbitrary code in host context. This vulnerability was patched in the release of version `3.9.17` of `vm2`. There are no known workarounds for this vulnerability. Users are advised to upgrade.
CWE description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
CVSS v3 base score: 10
Published: 2023-04-17T22:15Z
Repository: https://github.com/patriksimek/vm2
Language: JavaScript
Files changed: lib/setup-sandbox.js
Commit date: 2023-04-12 10:27:04 +0200
Commit message: Handle host errors captured in Promises

Diff: diff --git a/lib/setup-sandbox.js b/lib/setup-sandbox.js
index 539ce04..71afa52 100644
--- a/lib/setup-sandbox.js
+++ b/lib/setup-sandbox.js
@@ -437,27 +437,40 @@ global.eval = new LocalProxy(localEval, EvalHandler);
 
 /*
  * Promise sanitization
  */
 
-if (localPromise && !allowAsync) {
+if (localPromise) {
 
 	const PromisePrototype = localPromise.prototype;
 
-	overrideWithProxy(PromisePrototype, 'then', PromisePrototype.then, AsyncErrorHandler);
-	// This seems not to work, and will produce
-	// UnhandledPromiseRejectionWarning: TypeError: Method Promise.prototype.then called on incompatible receiver [object Object].
-	// This is likely caused since the host.Promise.prototype.then cannot use the VM Proxy object.
-	// Contextify.connect(host.Promise.prototype.then, Promise.prototype.then);
+	if (!allowAsync) {
+
+		overrideWithProxy(PromisePrototype, 'then', PromisePrototype.then, AsyncErrorHandler);
+		// This seems not to work, and will produce
+		// UnhandledPromiseRejectionWarning: TypeError: Method Promise.prototype.then called on incompatible receiver [object Object].
+		// This is likely caused since the host.Promise.prototype.then cannot use the VM Proxy object.
+		// Contextify.connect(host.Promise.prototype.then, Promise.prototype.then);
+
+	} else {
+
+		overrideWithProxy(PromisePrototype, 'then', PromisePrototype.then, {
+			__proto__: null,
+			apply(target, thiz, args) {
+				if (args.length > 1) {
+					const onRejected = args[1];
+					if (typeof onRejected === 'function') {
+						args[1] = function wrapper(error) {
+							error = ensureThis(error);
+							return localReflectApply(onRejected, this, [error]);
+						};
+					}
+				}
+				return localReflectApply(target, thiz, args);
+			}
+		});
 
-	if (PromisePrototype.finally) {
-		overrideWithProxy(PromisePrototype, 'finally', PromisePrototype.finally, AsyncErrorHandler);
-		// Contextify.connect(host.Promise.prototype.finally, Promise.prototype.finally);
-	}
-	if (Promise.prototype.catch) {
-		overrideWithProxy(PromisePrototype, 'catch', PromisePrototype.catch, AsyncErrorHandler);
-		// Contextify.connect(host.Promise.prototype.catch, Promise.prototype.catch);
 	}
 
 }
 
 function readonly(other, mock) {

Vulnerable code: if (localPromise && !allowAsync) {
	overrideWithProxy(PromisePrototype, 'then', PromisePrototype.then, AsyncErrorHandler);
	// This seems not to work, and will produce
	// UnhandledPromiseRejectionWarning: TypeError: Method Promise.prototype.then called on incompatible receiver [object Object].
	// This is likely caused since the host.Promise.prototype.then cannot use the VM Proxy object.
	// Contextify.connect(host.Promise.prototype.then, Promise.prototype.then);
	if (PromisePrototype.finally) {
		overrideWithProxy(PromisePrototype, 'finally', PromisePrototype.finally, AsyncErrorHandler);
		// Contextify.connect(host.Promise.prototype.finally, Promise.prototype.finally);
	}
	if (Promise.prototype.catch) {
		overrideWithProxy(PromisePrototype, 'catch', PromisePrototype.catch, AsyncErrorHandler);
		// Contextify.connect(host.Promise.prototype.catch, Promise.prototype.catch);
Fixed code: if (localPromise) {
	if (!allowAsync) {

		overrideWithProxy(PromisePrototype, 'then', PromisePrototype.then, AsyncErrorHandler);
		// This seems not to work, and will produce
		// UnhandledPromiseRejectionWarning: TypeError: Method Promise.prototype.then called on incompatible receiver [object Object].
		// This is likely caused since the host.Promise.prototype.then cannot use the VM Proxy object.
		// Contextify.connect(host.Promise.prototype.then, Promise.prototype.then);

	} else {

		overrideWithProxy(PromisePrototype, 'then', PromisePrototype.then, {
			__proto__: null,
			apply(target, thiz, args) {
				if (args.length > 1) {
					const onRejected = args[1];
					if (typeof onRejected === 'function') {
						args[1] = function wrapper(error) {
							error = ensureThis(error);
							return localReflectApply(onRejected, this, [error]);
						};
					}
				}
				return localReflectApply(target, thiz, args);
			}
		});