CVE-2026-92933
mediumPriorität · verfolgen · 23EPSS 0.004 · 30. PerzentilDEUSEPSS · bewertet 2026-10-23
vm2 is a sandbox for running untrusted Node.js code. In versions <= 3.11.7, NodeVM exposes the host `util` module to the sandbox as an unfiltered shallow copy (`Object.assign({}, util)` in `defaultBuiltinLoaderUtil`), and the deprecated `sys` builtin (an alias of host `util`) is exposed through the generic builtin loader. On Node.js >= 22.9 this hands sandboxed code `util.getCallSites()`, a programmatic stack-introspection API that returns the host process's full call stack, including absolute file paths, function names, and line numbers for vm2 bridge internals and the embedding application's entrypoint. This bypasses the host-frame redaction introduced for GHSA-v27g-jcqj-v8rw, which only applies to the `Error.prepareStackTrace` formatting channel. The issue is fixed in vm2 3.11.8.
cvss
Technischer Schweregrad, 0–10. Eine Zeile je Quelle.
Basiswert 0–10 · höher = schwerwiegender · Vektor überfahren zum Auflösen⚠ Quellen uneinig · low–medium · 2.7–6.9
SSVC
Eine Handlungsentscheidung — aus Ausnutzung und Auswirkung.
schwächen
Die CWE-Schwächeklassen, zu denen dies gehört.
betroffene Produkte (3)
Betroffene Produkte und Versionsbereiche.
Advisories (2)
Hersteller- und Ökosystem-Meldungen dazu.
- WID-SEC-W-2026-3071vm2: Mehrere SchwachstellenDeutsch2026-08-27csaf · cert_bundDE
Ein Angreifer kann mehrere Schwachstellen in vm2 ausnutzen, um beliebigen Programmcode mit den Rechten des Dienstes auszuführen, Sicherheitsmaßnahmen zu umgehen, Daten offenzulegen oder zu manipulieren oder einen Denial-of-Service-Zustand auszulösen.
- GHSA-r273-hxvj-fxhpvm2: util.getCallSites() bypasses GHSA-v27g-jcqj-v8rw host-frame redaction, leaks host call stack2026-10-05ghsa · osvUS
### Summary NodeVM exposes the host `util` module to the sandbox through an unfiltered shallow copy (`Object.assign({}, util)`). On Node.js >= 22.9 this hands sandboxed code `util.getCallSites()`, a programmatic stack-introspection API that returns the host process's full call stack — absolute file paths, function names, and line numbers — including vm2 bridge internals and the embedding application's entrypoint. This bypasses the host-frame redaction established in GHSA-v27g-jcqj-v8rw, which only covers the `Error.prepareStackTrace` channel. ### Details - Root cause — `defaultBuiltinLoaderUtil` copies every static member of the host `util` module and wraps the copy in `vm.readonly()` without filtering any member, so newly added Node APIs land in the sandbox automatically: https://github.com/patriksimek/vm2/blob/7a1f5100b96f48d34e0fe104ab37c0acc5944f92/lib/builtin.js#L25-L38 - Second equivalent channel — the deprecated `sys` builtin (an alias of host `util`) goes through the generic builtin loader `vm.readonly(hostRequire(key))`, which also carries `getCallSites`: https://github.com/patriksimek/vm2/blob/7a1f5100b96f48d34e0fe104ab37c0acc5944f92/lib/builtin.js#L230 - Bypassed protection — GHSA-v27g's redaction (`isHostFrameFileName` + `applyCallSiteGetters`) rewrites host-frame metadata getters to `null` only when the *sandbox realm* formats an error stack: https://github.com/patriksimek/vm2/blob/7a1f5100b96f48d34e0fe104ab37c0acc5944f92/lib/setup-sandbox.js#L818-L870 `util.getCallSites()` produces its data host-side and never passes through that formatter, so frames such as `lib/bridge.js @apply` (the bridge apply trap), `lib/nodevm.js @run`, the embedder's own entry file, and `node:internal/*` frames reach the sandbox verbatim as data properties (`scriptName`, `functionName`, `lineNumber`, `columnNumber`, `scriptId`). A repository-wide grep (source, docs/ATTACKS.md, CHANGELOG, tests) shows no occurrence of `getCallSites`; the member was never considered. ### PoC Prerequisites: Node.js >= 22.9 (verified on v22.23.1); run `npm ci --no-audit --no-fund` at the repository root. One-line reproducer (prints `/workspace/repo/lib/bridge.js`, i.e. a vm2-internal host path): node -e "const {NodeVM}=require('/workspace/repo'); console.log(new NodeVM({require:{builtin:['util']}}).run(\"module.exports = require('util').getCallSites(4)[0].scriptName\"))" Observed frames inside the sandbox, with both `require: { builtin: ['util'] }` and `require: { builtin: ['*'] }`: /workspace/repo/lib/bridge.js @apply:1664 vm.js @:5 /workspace/repo/lib/bridge.js @apply:1664 /workspace/repo/lib/nodevm.js @run:563 /workspace/out/<embedder entrypoint>.js @main:29 node:internal/modules/cjs/loader @:1781 node:internal/modules/cjs/loader @:1913 ... (8 node:internal/* frames in total) ### Impact Information disclosure. Any NodeVM configuration that allows the `util` (or `sys`) builtin — including the wildcard `builtin: ['*']`, both typical configurations from the README — lets untrusted sandboxed code programmatically read the host call stack: the vm2 installation path, the embedding application's file layout and entrypoint, and internal function names and line numbers. This is the same information category redacted by GHSA-v27g-jcqj-v8rw (Defense Invariant #5 in docs/ATTACKS.md) and breaks defense-in-depth assumptions of embedders that rely on host frames being invisible to the sandbox. The API returns only strings/numbers (no host object references); no escalation to code execution was identified. Suggested fix: filter members in `defaultBuiltinLoaderUtil` (allowlist, or at minimum drop `getCallSites`), apply the same treatment to the generic loader path used by `sys`, and extend the GHSA-v27g regression tests to cover programmatic stack-introspection APIs.
quellen
Welche Quellen diesen Datensatz belegen und wann.
Referenzen (2) nvd
Externe Belege — Patches, Meldungen, Analysen.
Angreifer nutzen Schwachstellen wie diese gegen im Internet exponierte Dienste aus. Sehen Sie mit einem kostenlosen Passiv-Scan, was exponiert ist.
Kostenloser Scan