CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-92951

CVE-2026-92951: Sandbox Escape via External Package Allowlist Bypass in vm2

Alon Barad
Alon Barad
Software Engineer

Oct 2, 2026·6 min read·3 visits

Executive Summary (TL;DR)

A flaw in vm2's bare-specifier matcher allowlist check allows sandbox escape. It uses unanchored substring matching and fails to filter directory traversal sequences, allowing untrusted code to load and execute arbitrary host packages with full authority.

An incorrect authorization and directory traversal vulnerability in the vm2 library before version 3.11.7 allows remote attackers to bypass the sandbox's external package allowlist. This flaw permits sandboxed code to resolve and execute arbitrary packages available on the host filesystem under host privileges, leading to unauthenticated sandbox escape and host code execution.

Vulnerability Overview

The vm2 npm package is a widely used Node.js library designed to run untrusted code in a highly restricted sandbox environment. The library exposes various configurations to control access to system resources. Under specific setups, the NodeVM class restricts access to external Node modules using the require.external configuration option. This feature is critical for multi-tenant applications and plugins that execute user-submitted scripts while preventing arbitrary filesystem access or network interaction.\n\nWhen combined with a custom resolver via the require.resolve callback, the package resolution falls back to the LegacyResolver internal component. Security verification within this resolver relies on a pre-check mechanism designed to determine whether a requested package matches the user-configured allowlist. If the requested identifier passes this initial pre-check, the application hands resolution to the custom host-level resolver.\n\nThe core issue lies within LegacyResolver.customResolve, which performs validation checks against bare specifiers before delegating the module resolution process to the host. Because these checks lack proper bounds and directory boundaries, attackers can satisfy the allowlist filters while requesting unauthorized host packages. The flaw manifests in two distinct vulnerability classes: a substring matching collision (CWE-863) and a path traversal vulnerability (CWE-706). Both security failures undermine the isolation boundary and permit complete escape from the execution sandbox.

Root Cause Analysis

The technical breakdown of the vulnerability highlights two separate architectural flaws inside LegacyResolver.customResolve. Both bugs are tied to how the LegacyResolver determines if a module request matches the allowlist before passing it to the custom resolver. These bugs together allow a sandboxed execution thread to arbitrarily extend its allowed packages list.\n\nThe first flaw involves unanchored regular expressions during string verification. The system constructs regex matchers dynamically for each configured allowlist pattern using the internal makeExternalMatcherRegex(pattern) function. These expressions are compiled and stored in this.externalCache. However, the resulting regular expression was compiled without the string start (^) and end ($) anchors. For example, if the allowlist permits the left-pad package, the matcher compiles to /left\-pad/. Because this expression performs an unanchored search, it matches any specifier containing the substring left-pad, such as evil-left-pad or left-pad-evil. If such a module exists on the host system, the resolver resolves it and permanently registers it in this.externals as an allowed module, allowing full host execution.\n\nThe second flaw involves directory traversal vulnerability (CWE-829). To allow access to subpaths of allowlisted modules (e.g., left-pad/utils), the validation engine needs to permit suffix patterns. However, the parser treated the path suffix as arbitrary text. The evaluation system failed to filter directory traversal segments such as .. before parsing. This omission allows an attacker to specify a path like left-pad/../evil-package. The pre-check identifies left-pad/ at the start of the string and allows the query. During actual module loading, standard Node.js resolution path canonicalization processes the traversal segments, collapsing left-pad/../evil-package into evil-package. Because this resolves to a separate, unauthorized directory location, the validation engine is completely bypassed, and unauthorized libraries run under host authority.

Code Analysis and Comparison

An analysis of the vulnerable and patched states in lib/resolver-compat.js illustrates how the two-stage security failure occurred and how the mitigation was structured. The patch directly resolves both the unanchored regex match and the lack of lexical path validation.\n\nBefore the patch, this.externalCache was built by mapping the allowlisted patterns without anchors. The pre-check evaluated bare specifiers directly against this cache:\n\njavascript\n// VULNERABLE CODE PATH\nthis.externalCache = externals.map(pattern => new RegExp(makeExternalMatcherRegex(pattern)));\n// ...\nif (!(this.pathIsAbsolute(x) || this.pathIsRelative(x))) {\n if (!this.externalCache.some(regex => regex.test(x))) return undefined;\n}\nconst resolved = this.customResolver(x, path);\n\n\nThe patch resolves the substring matching issue by anchoring both ends of the regular expression. The pattern now requires the input to be either the exact package name, or the package name followed directly by a path separator (\\ or /) and any arbitrary subpath:\n\njavascript\n// PATCHED REGEX GENERATION\nthis.externalCache = externals.map(pattern => new RegExp('^(?:' + makeExternalMatcherRegex(pattern) + ')(?:[\\\\/].*)?$'));\n\n\nTo block directory traversal attacks that abuse the permitted subpath tail, the patch adds lexical segment validation. The resolver splits the raw specifier string using platform-neutral directory separators. If the sequence contains a double-dot (..) segment, the resolution is rejected immediately, preventing any traversal before the path is passed to the filesystem-level resolver:\n\njavascript\n// PATCHED PATH TRAVERSAL MITIGATION\nif (x.split(/[\\/]/).indexOf('..') !== -1) return undefined;\n\n\nBy implementing this early lexical rejection, the module load process falls back to the standard loader, which denies access through isPathAllowed, raising a 'module not found' error inside the sandbox environment.

Exploitation Methodology

Exploitation of CVE-2026-92951 requires specific environmental prerequisites: the sandboxed execution framework must implement a custom package resolver configuration while using an allowlist of permitted external libraries. This layout is typical for serverless compute workers or plugin management systems built on vm2.\n\nAn attacker can trigger the vulnerability using two separate methods based on host package configuration. The first path leverages the substring mismatch. If the administrator allowlists a standard library such as left-pad, the attacker can introduce an external dependency with a colliding name (e.g., evil-left-pad) to their local package list. Invoking require('evil-left-pad') matches /left\-pad/. The sandbox passes this specifier to the host resolver, which loads the attacker's module, executing its entry point within the host's high-privilege context.\n\njavascript\n// Exploit Vector 1: Substring Collision Bypass\nconst payload = "require('evil-left-pad');";\nvm.run(payload);\n\n\nThe second vector bypasses safety rules using directory traversal. Even with anchored regular expressions, the engine permits subpaths starting with the allowlisted prefix. By executing require('left-pad/../evil-package'), the string begins with the legitimate prefix, satisfying the pre-check. When the custom resolver processes the request, the path resolves to the parent directory, allowing the sandbox to execute sibling modules outside of the permitted scope. The following diagram maps the lifecycle of a traversal-based bypass attempt:\n\nmermaid\ngraph LR\n A["Sandboxed require('left-pad/../evil')"] --> B["LegacyResolver Pre-check"]\n B --> C["Regex prefix check matches 'left-pad/'"]\n C --> D["Lexical Traversal Verification (Missing in <3.11.7)"]\n D --> E["Custom Resolver evaluates 'left-pad/../evil'"]\n E --> F["Host filesystem executes 'evil' package entrypoint"]\n\n style A fill:#f9f,stroke:#333,stroke-width:2px\n style F fill:#f99,stroke:#333,stroke-width:2px\n

Impact Assessment

The security impact of CVE-2026-92951 is classified as Critical, as denoted by its CVSS score of 9.9. Successful exploitation results in complete compromise of host integrity, confidentiality, and availability. Because the executing environment runs within the host process, escaping the vm2 sandbox grants the attacker the underlying operating system privileges of the Node.js runner.\n\nOnce the sandbox boundary is crossed, the attacker can execute arbitrary operating system commands, access environment variables containing database credentials or API keys, and perform internal network scans. For cloud-hosted environments, such as Serverless functions or CI/CD pipelines, this can lead to lateral movement, infrastructure takeover, or data exfiltration.\n\nThe scope of this flaw is further widened due to structural design limitations within the Node.js architecture. Once an untrusted module runs inside the host's V8 engine context, the executing thread can access global properties, manipulate standard input/output streams, or load native platform binaries, rendering sandbox recovery impossible.

Official Patches

Patrik ŠimekOfficial patch fixing the regex and path traversal vulnerabilities
Patrik ŠimekRelease v3.11.7

Fix Analysis (1)

Technical Appendix

CVSS Score
9.9/ 10
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H
EPSS Probability
0.54%
Top 57% most exploited

Affected Systems

Applications executing untrusted code using vm2 NodeVM configurationsMulti-tenant plugin hosting systems relying on vm2 external module allowlistsServerless runtimes and webhooks using deprecated vm2 sandbox instances

Affected Versions Detail

Product
Affected Versions
Fixed Version
vm2
Patrik Šimek
< 3.11.73.11.7
AttributeDetail
CWE IDCWE-706, CWE-863, CWE-829
Attack VectorNetwork
CVSS v3.1 Score9.9 (Critical)
Exploit StatusProof of Concept (PoC) documented in test suite
CISA KEV StatusNot Listed
EPSS Score0.00539
ImpactComplete Sandbox Escape & Host Code Execution

MITRE ATT&CK Mapping

T1190Exploit Public-Facing Application
Initial Access
CWE-706
Use of Incorrectly-Resolved Name or Reference

The application uses a name or reference to access a resource, but fails to correctly resolve or restrict the resource boundaries, allowing access to unexpected resources.

Known Exploits & Detection

GitHub security advisory test casesFunctional unit tests demonstrating unanchored regex match and path traversal validation bypasses

Vulnerability Timeline

Remediation commit pushed to the repository
2026-08-22
CVE-2026-92951 assigned and published
2026-09-17
Google OSV database entry updated
2026-09-19

References & Sources

  • [1]GHSA-c48m-32m9-vx93
  • [2]VulnCheck Security Advisory
  • [3]NVD - CVE-2026-92951

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•42 minutes ago•CVE-2026-92958
8.5

CVE-2026-92958: Built-in Module Denylist Bypass via fs/promises in vm2 NodeVM Subsystem

CVE-2026-92958 is a high-severity sandbox escape and denylist bypass vulnerability within the NodeVM subsystem of the vm2 sandboxing library. When configuring wildcards with negative deny entries, exact-string matches fail to block subpaths like fs/promises. Sandboxed code can import these subpaths to bypass isolation and execute arbitrary filesystem operations on the host.

Amit Schendel
Amit Schendel
2 views•6 min read
•about 3 hours ago•CVE-2026-92940
10.0

CVE-2026-92940: Host-Realm Credential Exposure and Socket Hijacking via globalAgent in vm2

A critical vulnerability in the Node.js sandbox library vm2 allows sandboxed code to retrieve the process-wide http.globalAgent and https.globalAgent singletons. By attaching event listeners to these host-realm emitters, sandboxed code can intercept host-realm network requests, capturing sensitive Authorization headers and hijacking active TLSSocket streams.

Amit Schendel
Amit Schendel
4 views•9 min read
•about 4 hours ago•CVE-2026-92950
9.3

CVE-2026-92950: Sandbox Escape Vulnerability in vm2 CLI

CVE-2026-92950 (GHSA-jxxv-8r27-vm4p) is a critical sandbox escape vulnerability in the command-line interface of the vm2 library prior to version 3.11.7. The flaw allows untrusted scripts to bypass sandbox constraints and execute arbitrary system commands with the privileges of the host process by exploiting insecure default configurations of the module resolver.

Amit Schendel
Amit Schendel
5 views•5 min read
•about 5 hours ago•CVE-2026-92948
9.9

CVE-2026-92948: Sandbox Escape and Remote Code Execution in vm2 via node:test

CVE-2026-92948 is a critical sandbox escape vulnerability in the vm2 library affecting versions 3.9.6 through 3.11.6 when executed on Node.js 24 and newer. The vulnerability allows an attacker to bypass built-in module blocking defenses by double-prefixing a restricted module name (such as node:node:test). This permits the loading of the node:test module, whose test runner execution can be leveraged to execute arbitrary shell commands outside the VM sandbox.

Amit Schendel
Amit Schendel
9 views•6 min read
•about 6 hours ago•CVE-2026-92952
8.9

CVE-2026-92952: Sandbox Escape and State Corruption in vm2 via Node.js-internal Symbol Leak

A high-severity sandbox escape and state corruption vulnerability exists in the vm2 library (versions 3.11.4 through 3.11.6). The vulnerability is caused by an incomplete blocklist of Node.js-internal registered symbols crossing the sandbox-host bridge boundary. Specifically, the filters in `lib/setup-sandbox.js` and write traps in `lib/bridge.js` omitted the symbols `nodejs.stream.disturbed` and `nodejs.stream.errored`, allowing untrusted code within the sandbox to corrupt host-realm stream state checks.

Amit Schendel
Amit Schendel
7 views•6 min read
•about 7 hours ago•CVE-2026-73607
5.8

CVE-2026-73607: Missing Authorization in SiYuan /api/storage/getOutlineStorage Leads to Information Disclosure

An architectural evaluation of CVE-2026-73607 in the SiYuan personal knowledge management system. This technical advisory details a Missing Authorization (CWE-862) vulnerability in the Go-based backend kernel, specifically within the outline storage API endpoint. Under certain configurations, authenticated low-privilege users can query metadata, heading structures, and block hierarchies of restricted documents.

Amit Schendel
Amit Schendel
9 views•7 min read