CVE-2026-92952
vm2 3.11.4 through 3.11.6 Sandbox Symbol Filtering Bypass
vm2 versions 3.11.4 through 3.11.6 incompletely filter Node.js registered internal symbols across the sandbox boundary. The extraction filters in lib/setup-sandbox.js and the cross-realm symbol checks and write traps in lib/bridge.js use a fixed list of known dangerous registered symbols that omits nodejs.stream.disturbed and nodejs.stream.errored, which are exposed on host WebStream prototypes on newer Node.js releases (validated on Node.js v25.8.0). When the embedder exposes a host WebStream object and the host stream/web module to the sandbox, sandbox code can obtain the real host symbols via Object.getOwnPropertySymbols(streamWeb.ReadableStream.prototype) and use them as write keys on host stream objects, corrupting host-visible stream state — for example making stream.Readable.isDisturbed() return false for an already-consumed stream. This can bypass host logic that relies on Node's public stream-state helpers to enforce one-shot body consumption, reject errored streams, or decide whether a stream is safe to hand to another component. It is not a host code-execution primitive in the reported proof of vulnerability. This is an incomplete fix for the earlier nodejs.* symbol filtering issue. Fixed in vm2 3.11.7.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- High
- Privileges needed
- None
- User interaction
- None
What an attacker can affect
- Confidentiality
- None
- Integrity
- High
- Availability
- None
Exploit likelihood
What each source reports
CVE List Score used
8.9
vm2 3.11.4 through 3.11.6 Sandbox Symbol Filtering Bypass
vm2 versions 3.11.4 through 3.11.6 incompletely filter Node.js registered internal symbols across the sandbox boundary. The extraction filters in lib/setup-sandbox.js and the cross-realm symbol checks and write traps in lib/bridge.js use a fixed list of known dangerous registered symbols that omits nodejs.stream.disturbed and nodejs.stream.errored, which are exposed on host WebStream prototypes on newer Node.js releases (validated on Node.js v25.8.0). When the embedder exposes a host WebStream object and the host stream/web module to the sandbox, sandbox code can obtain the real host symbols via Object.getOwnPropertySymbols(streamWeb.ReadableStream.prototype) and use them as write keys on host stream objects, corrupting host-visible stream state — for example making stream.Readable.isDisturbed() return false for an already-consumed stream. This can bypass host logic that relies on Node's public stream-state helpers to enforce one-shot body consumption, reject errored streams, or decide whether a stream is safe to hand to another component. It is not a host code-execution primitive in the reported proof of vulnerability. This is an incomplete fix for the earlier nodejs.* symbol filtering issue. Fixed in vm2 3.11.7.
- Record
CVE-2026-92952- CVSS 4.0
- 8.9 High
CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:H/SA:N - CVSS 3.1
- 6.8 Medium
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:N/I:H/A:N - Weakness
- CWE-669
- Updated
- 2026-11-02
EUVDEUVD-2026-81601
8.9
vm2 versions 3.11.4 through 3.11.6 incompletely filter Node.js registered internal symbols across the sandbox boundary. The extraction filters in lib/setup-sandbox.js and the cross-realm symbol checks and write traps in lib/bridge.js use a fixed list of known dangerous registered symbols that omits nodejs.stream.disturbed and nodejs.stream.errored, which are exposed on host WebStream prototypes on newer Node.js releases (validated on Node.js v25.8.0). When the embedder exposes a host WebStream object and the host stream/web module to the sandbox, sandbox code can obtain the real host symbols via Object.getOwnPropertySymbols(streamWeb.ReadableStream.prototype) and use them as write keys on host stream objects, corrupting host-visible stream state — for example making stream.Readable.isDisturbed() return false for an already-consumed stream. This can bypass host logic that relies on Node's public stream-state helpers to enforce one-shot body consumption, reject errored streams, or decide whether a stream is safe to hand to another component. It is not a host code-execution primitive in the reported proof of vulnerability. This is an incomplete fix for the earlier nodejs.* symbol filtering issue. Fixed in vm2 3.11.7.
- Record
EUVD-2026-81601- CVSS 4.0
- 8.9 High
CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:H/SA:N - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-hmpr-c9rf-qcrf
8.9
Duplicate Advisory: Incomplete nodejs.* symbol filtering lets sandbox override host WebStream state checks
Duplicate Advisory
This advisory has been withdrawn because it is a duplicate of GHSA-jf8q-945g-9q4c. This link is maintained to preserve external references.
Original Description
vm2 versions 3.11.4 through 3.11.6 incompletely filter Node.js registered internal symbols across the sandbox boundary. The extraction filters in lib/setup-sandbox.js and the cross-realm symbol checks and write traps in lib/bridge.js use a fixed list of known dangerous registered symbols that omits nodejs.stream.disturbed and nodejs.stream.errored, which are exposed on host WebStream prototypes on newer Node.js releases (validated on Node.js v25.8.0). When the embedder exposes a host WebStream object and the host stream/web module to the sandbox, sandbox code can obtain the real host symbols via Object.getOwnPropertySymbols(streamWeb.ReadableStream.prototype) and use them as write keys on host stream objects, corrupting host-visible stream state — for example making stream.Readable.isDisturbed() return false for an already-consumed stream. This can bypass host logic that relies on Node's public stream-state helpers to enforce one-shot body consumption, reject errored streams, or decide whether a stream is safe to hand to another component. It is not a host code-execution primitive in the reported proof of vulnerability. This is an incomplete fix for the earlier nodejs.* symbol filtering issue. Fixed in vm2 3.11.7.
- Record
GHSA-hmpr-c9rf-qcrf- CVSS 4.0
- 8.9 High
CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:H/SA:N/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 Medium
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:N/I:H/A:N - Weakness
- CWE-669
- Updated
- 2026-11-02
GitHub AdvisoriesGHSA-jf8q-945g-9q4c
6.8
vm2: Incomplete nodejs.* symbol filtering lets sandbox override host WebStream state checks
Summary
vm2 current head (v3.11.5, commit 7a1f5100b96f48d34e0fe104ab37c0acc5944f92) still exposes registered Node.js internal symbols from host WebStream prototypes to sandbox code.
The prior nodejs.* symbol hardening blocks Symbol.for('nodejs.<name>') at the source, but the extraction filters and bridge write traps still enumerate a fixed set of known registered symbols. On Node.js v25.8.0, stream/web exposes two additional registered symbols:
nodejs.stream.disturbednodejs.stream.errored
Sandbox code can extract those real host symbols with Object.getOwnPropertySymbols(streamWeb.ReadableStream.prototype) and then use them as write keys on host objects. On a real host ReadableStream, an attacker can make stream.Readable.isDisturbed(stream) return false after the stream has already been read.
Technical Details
lib/setup-sandbox.js correctly blocks future nodejs.* keys at the Symbol.for() source:
if (apply(localStringStartsWith, keyStr, ['nodejs.'])) {
...
return fresh;
}
However, the extraction filters are still driven by a fixed realDangerousSymbols list. That list does not include nodejs.stream.disturbed or nodejs.stream.errored, so Object.getOwnPropertySymbols() and related paths can still return those real host symbols.
lib/bridge.js has the same fixed-list problem in isDangerousCrossRealmSymbol() and in the host-result scrub list. Because the two new symbols are not recognized, the set and defineProperty traps allow sandbox-originated writes using those keys.
Current-head source references:
lib/setup-sandbox.js:180-196deniesSymbol.for('nodejs.*')by namespace.lib/setup-sandbox.js:214-230uses a fixedrealDangerousSymbolslist for extraction filtering; the two reported symbols are absent.lib/bridge.js:187-199uses a fixedisDangerousCrossRealmSymbol()list; the two reported symbols are absent.lib/bridge.js:1499-1509treats the write trap as the last line of defense, but it only rejects keys recognized by that fixed list.
Impact
Sandbox code can corrupt host-visible WebStream state checks for host WebStream objects that cross into the sandbox. In the validated PoV, a stream that the host has already consumed is made to appear undisturbed to stream.Readable.isDisturbed().
This can bypass host logic that relies on Node's public stream-state helpers to enforce one-shot body consumption, reject errored streams, or decide whether a host WebStream is safe to hand to another component.
This is not a host-code-execution primitive in the current PoV. The report is an incomplete-fix / guard-coverage gap in the same symbol-boundary family as the prior nodejs.* symbol advisory.
Affected Package/Versions
Confirmed affected on Node.js v25.8.0:
v3.11.4v3.11.5- current head
7a1f5100b96f48d34e0fe104ab37c0acc5944f92
v3.11.3 is also affected, but it predates the broader nodejs.* symbol fix. For this incomplete-fix report, the suggested affected range is >= 3.11.4, <= 3.11.5 on Node.js versions where these stream symbols exist.
No patched version is known.
Configuration Required
The PoV uses a VM where the embedder exposes a host WebStream object and the host stream/web module object to sandbox code:
const vm = new VM({ sandbox: { rs, streamWeb } });
This matches the same trust boundary as the earlier cross-realm symbol-write class: sandbox code must not be able to obtain registered Node.js internal symbols and write them back onto host objects.
The PoV is local-only. It does not require network access, a public target, NodeVM builtin access, process, filesystem access, or child-process access.
Local Proof of Concept
Run from the oss-zero-day-harness directory:
node submission-bundle/vm2-pov-test-incomplete-nodejs-stream-symbol-filter/pov-nodejs-stream-symbol-incomplete-fix.js
The PoV:
- The host creates a
ReadableStream. - The host reads one chunk…
- Record
GHSA-jf8q-945g-9q4c- CVSS 3.1
- 6.8 Medium
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:N/I:H/A:N - Weakness
- CWE-669
- Updated
- 2026-11-02
NVD
8.9
vm2 versions 3.11.4 through 3.11.6 incompletely filter Node.js registered internal symbols across the sandbox boundary. The extraction filters in lib/setup-sandbox.js and the cross-realm symbol checks and write traps in lib/bridge.js use a fixed list of known dangerous registered symbols that omits nodejs.stream.disturbed and nodejs.stream.errored, which are exposed on host WebStream prototypes on newer Node.js releases (validated on Node.js v25.8.0). When the embedder exposes a host WebStream object and the host stream/web module to the sandbox, sandbox code can obtain the real host symbols via Object.getOwnPropertySymbols(streamWeb.ReadableStream.prototype) and use them as write keys on host stream objects, corrupting host-visible stream state — for example making stream.Readable.isDisturbed() return false for an already-consumed stream. This can bypass host logic that relies on Node's public stream-state helpers to enforce one-shot body consumption, reject errored streams, or decide whether a stream is safe to hand to another component. It is not a host code-execution primitive in the reported proof of vulnerability. This is an incomplete fix for the earlier nodejs.* symbol filtering issue. Fixed in vm2 3.11.7.
- Record
CVE-2026-92952- CVSS 4.0
- 8.9 High
CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:H/SA:N/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 Medium
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:N/I:H/A:N - Weakness
- CWE-669
- Updated
- 2026-11-02
OSV
8.9
vm2 3.11.4 through 3.11.6 Sandbox Symbol Filtering Bypass
vm2 versions 3.11.4 through 3.11.6 incompletely filter Node.js registered internal symbols across the sandbox boundary. The extraction filters in lib/setup-sandbox.js and the cross-realm symbol checks and write traps in lib/bridge.js use a fixed list of known dangerous registered symbols that omits nodejs.stream.disturbed and nodejs.stream.errored, which are exposed on host WebStream prototypes on newer Node.js releases (validated on Node.js v25.8.0). When the embedder exposes a host WebStream object and the host stream/web module to the sandbox, sandbox code can obtain the real host symbols via Object.getOwnPropertySymbols(streamWeb.ReadableStream.prototype) and use them as write keys on host stream objects, corrupting host-visible stream state — for example making stream.Readable.isDisturbed() return false for an already-consumed stream. This can bypass host logic that relies on Node's public stream-state helpers to enforce one-shot body consumption, reject errored streams, or decide whether a stream is safe to hand to another component. It is not a host code-execution primitive in the reported proof of vulnerability. This is an incomplete fix for the earlier nodejs.* symbol filtering issue. Fixed in vm2 3.11.7.
- Record
CVE-2026-92952- CVSS 4.0
- 8.9 High
CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:H/SA:N - Weakness
- CWE-669
- Updated
- 2026-11-02
OSVGHSA-hmpr-c9rf-qcrf
8.9
Duplicate Advisory: Incomplete nodejs.* symbol filtering lets sandbox override host WebStream state checks
Duplicate Advisory
This advisory has been withdrawn because it is a duplicate of GHSA-jf8q-945g-9q4c. This link is maintained to preserve external references.
Original Description
vm2 versions 3.11.4 through 3.11.6 incompletely filter Node.js registered internal symbols across the sandbox boundary. The extraction filters in lib/setup-sandbox.js and the cross-realm symbol checks and write traps in lib/bridge.js use a fixed list of known dangerous registered symbols that omits nodejs.stream.disturbed and nodejs.stream.errored, which are exposed on host WebStream prototypes on newer Node.js releases (validated on Node.js v25.8.0). When the embedder exposes a host WebStream object and the host stream/web module to the sandbox, sandbox code can obtain the real host symbols via Object.getOwnPropertySymbols(streamWeb.ReadableStream.prototype) and use them as write keys on host stream objects, corrupting host-visible stream state — for example making stream.Readable.isDisturbed() return false for an already-consumed stream. This can bypass host logic that relies on Node's public stream-state helpers to enforce one-shot body consumption, reject errored streams, or decide whether a stream is safe to hand to another component. It is not a host code-execution primitive in the reported proof of vulnerability. This is an incomplete fix for the earlier nodejs.* symbol filtering issue. Fixed in vm2 3.11.7.
- Record
GHSA-hmpr-c9rf-qcrf- CVSS 4.0
- 8.9 High
CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:H/SA:N/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 Medium
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:N/I:H/A:N - Weakness
- CWE-669
- Updated
- 2026-11-02
OSVGHSA-jf8q-945g-9q4c
6.8
vm2: Incomplete nodejs.* symbol filtering lets sandbox override host WebStream state checks
Summary
vm2 current head (v3.11.5, commit 7a1f5100b96f48d34e0fe104ab37c0acc5944f92) still exposes registered Node.js internal symbols from host WebStream prototypes to sandbox code.
The prior nodejs.* symbol hardening blocks Symbol.for('nodejs.<name>') at the source, but the extraction filters and bridge write traps still enumerate a fixed set of known registered symbols. On Node.js v25.8.0, stream/web exposes two additional registered symbols:
nodejs.stream.disturbednodejs.stream.errored
Sandbox code can extract those real host symbols with Object.getOwnPropertySymbols(streamWeb.ReadableStream.prototype) and then use them as write keys on host objects. On a real host ReadableStream, an attacker can make stream.Readable.isDisturbed(stream) return false after the stream has already been read.
Technical Details
lib/setup-sandbox.js correctly blocks future nodejs.* keys at the Symbol.for() source:
if (apply(localStringStartsWith, keyStr, ['nodejs.'])) {
...
return fresh;
}
However, the extraction filters are still driven by a fixed realDangerousSymbols list. That list does not include nodejs.stream.disturbed or nodejs.stream.errored, so Object.getOwnPropertySymbols() and related paths can still return those real host symbols.
lib/bridge.js has the same fixed-list problem in isDangerousCrossRealmSymbol() and in the host-result scrub list. Because the two new symbols are not recognized, the set and defineProperty traps allow sandbox-originated writes using those keys.
Current-head source references:
lib/setup-sandbox.js:180-196deniesSymbol.for('nodejs.*')by namespace.lib/setup-sandbox.js:214-230uses a fixedrealDangerousSymbolslist for extraction filtering; the two reported symbols are absent.lib/bridge.js:187-199uses a fixedisDangerousCrossRealmSymbol()list; the two reported symbols are absent.lib/bridge.js:1499-1509treats the write trap as the last line of defense, but it only rejects keys recognized by that fixed list.
Impact
Sandbox code can corrupt host-visible WebStream state checks for host WebStream objects that cross into the sandbox. In the validated PoV, a stream that the host has already consumed is made to appear undisturbed to stream.Readable.isDisturbed().
This can bypass host logic that relies on Node's public stream-state helpers to enforce one-shot body consumption, reject errored streams, or decide whether a host WebStream is safe to hand to another component.
This is not a host-code-execution primitive in the current PoV. The report is an incomplete-fix / guard-coverage gap in the same symbol-boundary family as the prior nodejs.* symbol advisory.
Affected Package/Versions
Confirmed affected on Node.js v25.8.0:
v3.11.4v3.11.5- current head
7a1f5100b96f48d34e0fe104ab37c0acc5944f92
v3.11.3 is also affected, but it predates the broader nodejs.* symbol fix. For this incomplete-fix report, the suggested affected range is >= 3.11.4, <= 3.11.5 on Node.js versions where these stream symbols exist.
No patched version is known.
Configuration Required
The PoV uses a VM where the embedder exposes a host WebStream object and the host stream/web module object to sandbox code:
const vm = new VM({ sandbox: { rs, streamWeb } });
This matches the same trust boundary as the earlier cross-realm symbol-write class: sandbox code must not be able to obtain registered Node.js internal symbols and write them back onto host objects.
The PoV is local-only. It does not require network access, a public target, NodeVM builtin access, process, filesystem access, or child-process access.
Local Proof of Concept
Run from the oss-zero-day-harness directory:
node submission-bundle/vm2-pov-test-incomplete-nodejs-stream-symbol-filter/pov-nodejs-stream-symbol-incomplete-fix.js
The PoV:
- The host creates a
ReadableStream. - The host reads one chunk…
- Record
GHSA-jf8q-945g-9q4c- CVSS 3.1
- 6.8 Medium
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:N/I:H/A:N - Weakness
- CWE-669
- Updated
- 2026-11-02
OSVCLSA-2026-1790888247 No score
TuxCare security update for vm2 (15 CVEs)
TuxCare rebuilt vm2 to address 15 CVEs. Fixed in 3.11.5-tuxcare.3.
- Record
CLSA-2026-1790888247- Updated
- 2026-11-02
Affected products
Affected packages
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-92952 is a high vulnerability (CVSS 8.9) 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.46%, the 40th percentile. Fixed in vm2 3.11.7.
References
github.com/patriksimek/vm2/security/advisories/GHSA-jf8q-945g-9q4c
vulncheck.com/advisories/vm2-3.11.4-through-3.11.6-sandbox-symbol-filtering-bypass
nvd.nist.gov/vuln/detail/CVE-2026-92952
github.com/advisories/GHSA-hmpr-c9rf-qcrf
github.com/patriksimek/vm2/commit/a45444d5abbdfa59055528f584df5f21cc7c42da
github.com/patriksimek/vm2/releases/tag/v3.11.7
github.com/advisories/GHSA-jf8q-945g-9q4c
github.com/CVEProject/cvelistV5/tree/main/cves/2026/92xxx/CVE-2026-92952.json
github.com/patriksimek/vm2
Left out here: the rest of 2 source descriptions. The JSON record has them.