CVE-2026-92954
vm2 3.10.0 through 3.11.7 Denial of Service via Host Promise
vm2 is a sandbox library for running untrusted JavaScript in Node.js. In versions >= 3.10.0 and <= 3.11.7, Promises returned from the host realm into the sandbox are not marked as handled at the bridge boundary; only Promises created inside the sandbox are wrapped with a rejection-swallowing handler (lib/setup-sandbox.js), and the bridge only installs host-side rejection sanitizers when sandbox code calls .then/.catch/.finally. As a result, code running in the sandbox can invoke a host function that returns a rejected Promise (for example events.once() exposed via the NodeVM events builtin, or any embedder-provided Promise-returning API) and simply ignore the return value, leaving the host Promise unhandled so that Node.js's default unhandled-rejection behavior terminates the host process. This is an incomplete fix of GHSA-hw58-p9xv-2mjh. The issue is fixed in version 3.11.8.
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
What each source reports
CVE List Score used
9.2
vm2 3.10.0 through 3.11.7 Denial of Service via Host Promise
vm2 is a sandbox library for running untrusted JavaScript in Node.js. In versions >= 3.10.0 and <= 3.11.7, Promises returned from the host realm into the sandbox are not marked as handled at the bridge boundary; only Promises created inside the sandbox are wrapped with a rejection-swallowing handler (lib/setup-sandbox.js), and the bridge only installs host-side rejection sanitizers when sandbox code calls .then/.catch/.finally. As a result, code running in the sandbox can invoke a host function that returns a rejected Promise (for example events.once() exposed via the NodeVM events builtin, or any embedder-provided Promise-returning API) and simply ignore the return value, leaving the host Promise unhandled so that Node.js's default unhandled-rejection behavior terminates the host process. This is an incomplete fix of GHSA-hw58-p9xv-2mjh. The issue is fixed in version 3.11.8.
- Record
CVE-2026-92954- CVSS 4.0
- 9.2 Critical
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:H - CVSS 3.1
- 8.6 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:N/A:H - Weakness
- CWE-248
- Updated
- 2026-11-02
EUVDEUVD-2026-81603
9.2
vm2 is a sandbox library for running untrusted JavaScript in Node.js. In versions >= 3.10.0 and <= 3.11.7, Promises returned from the host realm into the sandbox are not marked as handled at the bridge boundary; only Promises created inside the sandbox are wrapped with a rejection-swallowing handler (lib/setup-sandbox.js), and the bridge only installs host-side rejection sanitizers when sandbox code calls .then/.catch/.finally. As a result, code running in the sandbox can invoke a host function that returns a rejected Promise (for example events.once() exposed via the NodeVM events builtin, or any embedder-provided Promise-returning API) and simply ignore the return value, leaving the host Promise unhandled so that Node.js's default unhandled-rejection behavior terminates the host process. This is an incomplete fix of GHSA-hw58-p9xv-2mjh. The issue is fixed in version 3.11.8.
- Record
EUVD-2026-81603- CVSS 4.0
- 9.2 Critical
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:H - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-gjq8-xm47-88rc
9.2
vm2: Host-returned Promise rejection can bypass vm2's unhandled-rejection hardening and terminate the host process
Summary
vm2 current head (v3.11.5, commit 7a1f5100b96f48d34e0fe104ab37c0acc5944f92) can still be used to terminate the host Node.js process when sandbox code calls a host-realm function that returns a rejected host Promise and then ignores the returned value.
This is an incomplete-fix variant of the GHSA-hw58-p9xv-2mjh unhandled rejection hardening. The localPromise constructor now catches and consumes sandbox-created unhandled rejections, but host Promises returned across the bridge are not marked handled at the bridge boundary. If the sandbox does not attach .catch() or .then(..., onRejected), Node's default unhandled rejection behavior terminates the host process.
Technical Details
lib/setup-sandbox.js hardens sandbox-created Promises by wrapping the executor and attaching a benign swallow tail:
apply(globalPromisePrototypeThen, this, [undefined, localPromiseSwallow]);
That only applies to localPromise instances created inside the sandbox.
Host-returned Promises cross the membrane through the bridge apply path. The bridge wraps callbacks when sandbox code later calls .then, .catch, or .finally on a host Promise:
bridge.setHostPromiseSanitizers(e => handleException(from(e)), from);
However, if sandbox code ignores the returned host Promise, no host-side rejection handler is attached. The original host Promise remains unhandled and Node terminates the host process under the default unhandled-rejection behavior.
NodeVM provides an in-repository example of this primitive through the special events builtin wrapper. lib/builtin.js passes host EventEmitter.once into the sandbox:
once: EventEmitter.once,
Then lib/events.js re-exports it:
if (host.once) module.exports.once = host.once;
Calling events.once(ee, 'message') and then emitting error on ee returns a rejected host Promise through that wrapper. If ignored by sandbox code, it terminates the host process.
Impact
An attacker who can run code in a vm2 sandbox can terminate the host Node.js process when the embedder exposes a host Promise-returning API, or when a NodeVM permits the events builtin.
For web services, queues, notebook workers, plugin hosts, and multi-tenant code execution systems, a single small request can terminate the worker process. Restart policies do not fully mitigate the issue because the payload can be replayed after each restart.
Affected Package/Versions
Confirmed affected on Node.js v25.8.0:
v3.10.0v3.10.1v3.10.2v3.10.3v3.10.4v3.10.5v3.11.0v3.11.1v3.11.2v3.11.3v3.11.4v3.11.5/ current head7a1f5100b96f48d34e0fe104ab37c0acc5944f92
The final PoV was also reproduced on current head with Node.js v16.20.2, v18.20.8, v20.20.2, v22.22.3, v24.16.0, and v25.9.0 using npx node@<major>. The local workstation default Node.js v25.8.0 also reproduces.
Configuration Required
The general VM PoV requires an embedder-exposed host function that can return a rejected host Promise:
const vm = new VM({
sandbox: {
hostReject: () => Promise.reject(new Error('host-boom')),
},
});
The NodeVM variant requires events in the builtin allowlist:
new NodeVM({ require: { external: false, builtin: ['events'] } });
events.once() is exposed by vm2's special events builtin wrapper. Node's official API documents events.once() as returning a Promise that rejects when the watched emitter emits error while waiting for another event.
Controls
- If sandbox code attaches
.catch(() => {})to the returned host Promise, the process survives. - If sandbox code creates and ignores a sandbox-native rejected Promise, the process survives on current head. This confirms the
GHSA-hw58localPromise hardening is active. - If sandbox code attaches
.catch(() => {})to theevents.once()Promise, theNodeVMprocess survives. - If
NodeVMdoes not allow the…
- Record
GHSA-gjq8-xm47-88rc- CVSS 4.0
- 9.2 Critical
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:H - CVSS 3.1
- 8.6 High
CVSS: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-mgj2-jqjq-q8gg
9.2
Duplicate Advisory: vm2: Host-returned Promise rejection can bypass vm2's unhandled-rejection hardening and terminate the host process
Duplicate Advisory
This advisory has been withdrawn because it is a duplicate of GHSA-gjq8-xm47-88rc. This link is maintained to preserve external references.
Original Description
vm2 is a sandbox library for running untrusted JavaScript in Node.js. In versions >= 3.10.0 and <= 3.11.7, Promises returned from the host realm into the sandbox are not marked as handled at the bridge boundary; only Promises created inside the sandbox are wrapped with a rejection-swallowing handler (lib/setup-sandbox.js), and the bridge only installs host-side rejection sanitizers when sandbox code calls .then/.catch/.finally. As a result, code running in the sandbox can invoke a host function that returns a rejected Promise (for example events.once() exposed via the NodeVM events builtin, or any embedder-provided Promise-returning API) and simply ignore the return value, leaving the host Promise unhandled so that Node.js's default unhandled-rejection behavior terminates the host process. This is an incomplete fix of GHSA-hw58-p9xv-2mjh. The issue is fixed in version 3.11.8.
- Record
GHSA-mgj2-jqjq-q8gg- CVSS 4.0
- 9.2 Critical
CVSS:4.0/AV:N/AC:L/AT:N/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
- 8.6 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:N/A:H - Weakness
- CWE-248
- Updated
- 2026-11-02
NVD
9.2
vm2 is a sandbox library for running untrusted JavaScript in Node.js. In versions >= 3.10.0 and <= 3.11.7, Promises returned from the host realm into the sandbox are not marked as handled at the bridge boundary; only Promises created inside the sandbox are wrapped with a rejection-swallowing handler (lib/setup-sandbox.js), and the bridge only installs host-side rejection sanitizers when sandbox code calls .then/.catch/.finally. As a result, code running in the sandbox can invoke a host function that returns a rejected Promise (for example events.once() exposed via the NodeVM events builtin, or any embedder-provided Promise-returning API) and simply ignore the return value, leaving the host Promise unhandled so that Node.js's default unhandled-rejection behavior terminates the host process. This is an incomplete fix of GHSA-hw58-p9xv-2mjh. The issue is fixed in version 3.11.8.
- Record
CVE-2026-92954- CVSS 4.0
- 9.2 Critical
CVSS:4.0/AV:N/AC:L/AT:N/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
- 8.6 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:N/A:H - Weakness
- CWE-248
- Updated
- 2026-11-02
OSV
9.2
vm2 3.10.0 through 3.11.7 Denial of Service via Host Promise
vm2 is a sandbox library for running untrusted JavaScript in Node.js. In versions >= 3.10.0 and <= 3.11.7, Promises returned from the host realm into the sandbox are not marked as handled at the bridge boundary; only Promises created inside the sandbox are wrapped with a rejection-swallowing handler (lib/setup-sandbox.js), and the bridge only installs host-side rejection sanitizers when sandbox code calls .then/.catch/.finally. As a result, code running in the sandbox can invoke a host function that returns a rejected Promise (for example events.once() exposed via the NodeVM events builtin, or any embedder-provided Promise-returning API) and simply ignore the return value, leaving the host Promise unhandled so that Node.js's default unhandled-rejection behavior terminates the host process. This is an incomplete fix of GHSA-hw58-p9xv-2mjh. The issue is fixed in version 3.11.8.
- Record
CVE-2026-92954- CVSS 4.0
- 9.2 Critical
CVSS:4.0/AV:N/AC:L/AT:N/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-gjq8-xm47-88rc
9.2
vm2: Host-returned Promise rejection can bypass vm2's unhandled-rejection hardening and terminate the host process
Summary
vm2 current head (v3.11.5, commit 7a1f5100b96f48d34e0fe104ab37c0acc5944f92) can still be used to terminate the host Node.js process when sandbox code calls a host-realm function that returns a rejected host Promise and then ignores the returned value.
This is an incomplete-fix variant of the GHSA-hw58-p9xv-2mjh unhandled rejection hardening. The localPromise constructor now catches and consumes sandbox-created unhandled rejections, but host Promises returned across the bridge are not marked handled at the bridge boundary. If the sandbox does not attach .catch() or .then(..., onRejected), Node's default unhandled rejection behavior terminates the host process.
Technical Details
lib/setup-sandbox.js hardens sandbox-created Promises by wrapping the executor and attaching a benign swallow tail:
apply(globalPromisePrototypeThen, this, [undefined, localPromiseSwallow]);
That only applies to localPromise instances created inside the sandbox.
Host-returned Promises cross the membrane through the bridge apply path. The bridge wraps callbacks when sandbox code later calls .then, .catch, or .finally on a host Promise:
bridge.setHostPromiseSanitizers(e => handleException(from(e)), from);
However, if sandbox code ignores the returned host Promise, no host-side rejection handler is attached. The original host Promise remains unhandled and Node terminates the host process under the default unhandled-rejection behavior.
NodeVM provides an in-repository example of this primitive through the special events builtin wrapper. lib/builtin.js passes host EventEmitter.once into the sandbox:
once: EventEmitter.once,
Then lib/events.js re-exports it:
if (host.once) module.exports.once = host.once;
Calling events.once(ee, 'message') and then emitting error on ee returns a rejected host Promise through that wrapper. If ignored by sandbox code, it terminates the host process.
Impact
An attacker who can run code in a vm2 sandbox can terminate the host Node.js process when the embedder exposes a host Promise-returning API, or when a NodeVM permits the events builtin.
For web services, queues, notebook workers, plugin hosts, and multi-tenant code execution systems, a single small request can terminate the worker process. Restart policies do not fully mitigate the issue because the payload can be replayed after each restart.
Affected Package/Versions
Confirmed affected on Node.js v25.8.0:
v3.10.0v3.10.1v3.10.2v3.10.3v3.10.4v3.10.5v3.11.0v3.11.1v3.11.2v3.11.3v3.11.4v3.11.5/ current head7a1f5100b96f48d34e0fe104ab37c0acc5944f92
The final PoV was also reproduced on current head with Node.js v16.20.2, v18.20.8, v20.20.2, v22.22.3, v24.16.0, and v25.9.0 using npx node@<major>. The local workstation default Node.js v25.8.0 also reproduces.
Configuration Required
The general VM PoV requires an embedder-exposed host function that can return a rejected host Promise:
const vm = new VM({
sandbox: {
hostReject: () => Promise.reject(new Error('host-boom')),
},
});
The NodeVM variant requires events in the builtin allowlist:
new NodeVM({ require: { external: false, builtin: ['events'] } });
events.once() is exposed by vm2's special events builtin wrapper. Node's official API documents events.once() as returning a Promise that rejects when the watched emitter emits error while waiting for another event.
Controls
- If sandbox code attaches
.catch(() => {})to the returned host Promise, the process survives. - If sandbox code creates and ignores a sandbox-native rejected Promise, the process survives on current head. This confirms the
GHSA-hw58localPromise hardening is active. - If sandbox code attaches
.catch(() => {})to theevents.once()Promise, theNodeVMprocess survives. - If
NodeVMdoes not allow the…
- Record
GHSA-gjq8-xm47-88rc- CVSS 4.0
- 9.2 Critical
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:H - CVSS 3.1
- 8.6 High
CVSS: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-mgj2-jqjq-q8gg
9.2
Duplicate Advisory: vm2: Host-returned Promise rejection can bypass vm2's unhandled-rejection hardening and terminate the host process
Duplicate Advisory
This advisory has been withdrawn because it is a duplicate of GHSA-gjq8-xm47-88rc. This link is maintained to preserve external references.
Original Description
vm2 is a sandbox library for running untrusted JavaScript in Node.js. In versions >= 3.10.0 and <= 3.11.7, Promises returned from the host realm into the sandbox are not marked as handled at the bridge boundary; only Promises created inside the sandbox are wrapped with a rejection-swallowing handler (lib/setup-sandbox.js), and the bridge only installs host-side rejection sanitizers when sandbox code calls .then/.catch/.finally. As a result, code running in the sandbox can invoke a host function that returns a rejected Promise (for example events.once() exposed via the NodeVM events builtin, or any embedder-provided Promise-returning API) and simply ignore the return value, leaving the host Promise unhandled so that Node.js's default unhandled-rejection behavior terminates the host process. This is an incomplete fix of GHSA-hw58-p9xv-2mjh. The issue is fixed in version 3.11.8.
- Record
GHSA-mgj2-jqjq-q8gg- CVSS 4.0
- 9.2 Critical
CVSS:4.0/AV:N/AC:L/AT:N/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
- 8.6 High
CVSS:3.1/AV:N/AC:L/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-92954 No score
CVE-2026-92954 in vm2 - Patched by Root
Root has patched CVE-2026-92954 in the vm2 package for Root:npm. Multiple fixed versions available.
- Record
ROOT-APP-NPM-CVE-2026-92954- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
vm2npm |
3.10.0 to 3.11.7 | 3.11.8 |
vm2TuxCare:npm From an advisory covering 8 CVEs |
3.11.7-tuxcare.0 up to 3.11.7-tuxcare.1, plus listed versions 3.11.7 |
3.11.7-tuxcare.1 |
vm2TuxCare:npm From an advisory covering 3 CVEs |
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 |
vm2TuxCare:npm From an advisory covering 4 CVEs |
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 |
vm2npm |
3.10.0 up to 3.11.8 | 3.11.8 |
vm2Root:npm |
before 3.11.6-aikido.1 | 3.11.6-aikido.1 |
@rootio/vm2Root:npm |
before 3.11.6-root.io.1 | 3.11.6-root.io.1 |
History
| Recorded | Changed | Sources |
|---|---|---|
| affected, facts | ||
| affected | ||
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-92954 is a critical vulnerability (CVSS 9.2) in Patriksimek Vm2, published September 17, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.49%, the 42nd percentile. Fixed in vm2 3.11.8.
References
github.com/patriksimek/vm2/security/advisories/GHSA-gjq8-xm47-88rc
vulncheck.com/advisories/vm2-3.10.0-through-3.11.5-denial-of-service-via-host-promise
nvd.nist.gov/vuln/detail/CVE-2026-92954
github.com/patriksimek/vm2/commit/5bb37f8b3f0498675a71cfa4df2b408d8ef7d4fb
github.com/patriksimek/vm2/releases/tag/v3.11.8
github.com/advisories/GHSA-gjq8-xm47-88rc
github.com/advisories/GHSA-mgj2-jqjq-q8gg
github.com/CVEProject/cvelistV5/tree/main/cves/2026/92xxx/CVE-2026-92954.json
github.com/patriksimek/vm2
Left out here: the rest of 2 source descriptions. The JSON record has them.