CVE-2026-92951: Vm2 Vm2 Custom Module Resolver Can Vulnerability
CRITICALCVE-2026-92951 is a CRITICAL (CVSS 9.9) vm2 custom module resolver can vulnerability (CWE-829: Inclusion of Functionality from Untrusted Control Sphere) affecting Vm2 libraries in the npm ecosystem. The issue involves vm2 custom module resolver can bypass the external package allowlist by loading a colliding host package. Remediation is available by upgrading affected packages to version 3.11.7.
CVE-2026-92951 at a Glance
Security Impact
CVSS: 9.9
The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H).
How to Fix CVE-2026-92951
To remediate this vulnerability, upgrade all affected Vm2 dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.
npm install vm2@3.11.7
Run the following command in your project directory to verify that all resolved dependencies use the patched release:
npm ls vm2
How to Check if You Are Affected
To determine whether your Node.js application is affected by CVE-2026-92951, inspect your project dependencies using npm:
npm ls vm2
Analyze the terminal output to locate any version of Vm2 in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 3.11.7), your application is affected.
Note: The npm ls vm2 command inspects dependencies declared in your package.json and lockfile; it does not perform automated runtime dynamic scanning.
Technical Details
Vulnerability Mechanism & Technical Analysis
This vulnerability is classified under CWE-829: Inclusion of Functionality from Untrusted Control Sphere, where the product imports, requires, or includes executable functionality (such as a library) from a source that is outside of the intended control sphere. In Vm2, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.
Source Advisory Statement
CVE-2026-92951 Affected Vm2 Versions
1 component(s)| Product / Package | Ecosystem | Affected Versions | Fixed Version |
|---|---|---|---|
|
vm2
|
npm |
< 3.11.7
|
3.11.7
|
References
Frequently Asked Questions
What is CVE-2026-92951?
Which Vm2 versions are affected?
What version fixes CVE-2026-92951?
Is vm2 affected?
What is the CVSS score of CVE-2026-92951?
What CWE is associated with CVE-2026-92951?
How can I check npm dependencies for CVE-2026-92951?
Machine-readable OSV JSON
OSV v1.5 Schema
{
"schema_version" : "1.4.0",
"id" : "GHSA-c48m-32m9-vx93",
"modified" : "2026-10-01T15:37:19Z",
"published" : "2026-10-01T15:37:19Z",
"aliases" : [ "CVE-2026-92951" ],
"summary" : "vm2 Custom Module Resolver Can Bypass the External Package Allowlist by Loading a Colliding Host Package",
"details" : "### Summary\n\nvm2 is a sandbox library for isolating and executing untrusted JavaScript code inside a Node.js process. It can restrict access to built-in modules and external packages.\n\nWhen `NodeVM` enables an `external` allowlist together with a custom `resolve` callback, vm2 checks the requested package name with a non-exact match. For example, if the allowlist only permits `left-pad`, an attacker can still bypass the check with a colliding package name such as `evil-left-pad`, because it contains the allowlisted name.\n\nIf the colliding package already exists in a host path resolvable by the custom resolver, or if the target application's custom resolver / dependency-management workflow downloads the package and places it in a resolvable path, vm2 loads and executes that package in the host context. This lets sandboxed code bypass the module allowlist and may further lead to host code execution.\n\n### Details\n\n`NodeVM` supports `require.external` to configure which external npm packages sandboxed code may load. It also supports a custom resolver through `require.resolve`. This combination is commonly used in business plugin systems, user-script platforms, or sandbox execution environments: the application allows only a small set of trusted dependencies while using a custom resolver that points to the application's own package directory.\n\nThe vulnerability is in the allowlist pre-check logic before the custom resolver is called. vm2 generates a regular expression from the `external` allowlist and uses it to check the original package name supplied by sandboxed code. However, the regular expression is not anchored to the full package-name boundary, so it performs a substring match on the original package name.\n\nFor example, with the following configuration:\n\n```js\nnew NodeVM({\n require: {\n external: ['left-pad'],\n resolve: id => require.resolve(id, { paths: [customRoot] }),\n context: 'host',\n builtin: []\n }\n})\n```\n\nThe intended policy is that sandboxed code can only load `left-pad`. However, because vm2 uses a non-exact match similar to `/left\\-pad/` for the requested package name, names such as `evil-left-pad` and `left-pad-backdoor` also pass the allowlist pre-check.\n\nAfter `evil-left-pad` passes the check, vm2 calls the custom resolver configured by the application. If the resolver can find that colliding package in a host-resolvable path, vm2 adds the returned path to the loadable list and, in `context: 'host'` mode, loads the package with the host `require()`. At that point, the package's top-level code executes in the host context instead of being constrained by sandbox restrictions such as `NodeVM`'s `builtin: []`.\n\nIn local verification, the PoC only allows `external: ['left-pad']` and sets `builtin: []`, so sandboxed code cannot directly load `child_process`. However, after the sandboxed code executes `require('evil-left-pad')`, vm2 still loads the colliding package from a host path. The colliding package's top-level code successfully invokes the host `child_process` module and prints `HOST_EXEC`.\n\nThis issue does not mean that vm2 automatically downloads malicious packages from npm at runtime. The attack requires the colliding package to already be in a path resolvable by the custom resolver, or for the target application's own dependency resolution / download workflow to place that package in such a path. This precondition limits the affected scenarios, but it does not change the core vulnerability: the `external` allowlist is not enforced against complete package-name boundaries, allowing sandboxed code to load a host package that the application did not authorize.\n\n### PoC\n\nAn independent PoC is attached in the `poc` directory. The PoC installs vm2 `3.11.5`, creates a temporary host package directory, and writes an unauthorized `evil-left-pad` package into it.\n\nRun the following from the `poc` directory:\n\n```bash\nnpm install\nnode poc.js\n```\n\nWhen the vulnerability is present, the output is similar to:\n\n```text\n[+] vm2 version: 3.11.5\n[+] customRoot: /tmp/vm2-resolver-poc-xxxxxx/custom\n[+] Direct sandbox require(\"child_process\") is blocked: ENOTFOUND\n[+] Unrelated package is blocked: ENOTFOUND\n[+] require(\"evil-left-pad\") result: HOST_EXEC\n[+] RESULT: VULNERABLE\n```\n\n`HOST_EXEC` is produced by the top-level code of the `evil-left-pad` package through host-side `child_process.execFileSync()`, demonstrating that the unauthorized package has executed in the host context.\n\nExpected result: when the `external` allowlist only contains `left-pad`, `evil-left-pad` should be rejected.\n\nActual result: `evil-left-pad` passes the check because it contains the `left-pad` substring and then executes in the host context.\n\n### Impact\n\nUnder the affected configuration, an attacker can load a colliding host package that is not allowed by the `external` allowlist through sandboxed code, breaking `NodeVM`'s module access control.\n\nIf the attacker can control or influence the contents of the colliding package, for example by placing a malicious package through a plugin upload directory, a user-controllable dependency directory, a private registry synchronization directory, an application-specific dependency download workflow, or another path reachable by the resolver, the attacker can further execute code in the host Node.js process context. The attacker may read files, environment variables, and secrets accessible to the host process, modify host-writable data, or interrupt the host service.\n\nThe main exploitation prerequisites are:\n\n- The application uses vm2 `NodeVM` to execute untrusted or low-trust JavaScript code.\n- The application enables a `require.external` allowlist instead of allowing all external packages.\n- The application configures a custom `require.resolve`.\n- The colliding package already exists in a path resolvable by that custom resolver, or the application's workflow downloads / synchronizes it into that path.\n- The application loads external packages in the host context, or keeps the relevant default behavior.\n\nIf the deployed custom resolver only searches a fixed dependency directory that is fully trusted and cannot be influenced by an attacker, practical exploitability is reduced. However, in scenarios such as plugin systems, user scripts, uploadable dependency packages, private package-source synchronization, or multi-tenant sandbox platforms, this vulnerability can bypass the sandbox boundary.\n\n### Credit\n\nThis vulnerability was discovered by:\n\n- XlabAI Team of Tencent Xuanwu Lab (xlabai@tencent.com)\n- Atuin Automated Vulnerability Discovery Engine\n- Guannan Wang (wgnbuaa@gmail.com), Zhanpeng Liu (pkugenuine@gmail.com), Jiashuo Liang (761232680@qq.com), Guancheng Li (lgcpku@gmail.com)",
"severity" : [ {
"type" : "CVSS_V3",
"score" : "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H"
} ],
"affected" : [ {
"package" : {
"ecosystem" : "npm",
"name" : "vm2"
},
"ranges" : [ {
"type" : "ECOSYSTEM",
"events" : [ {
"introduced" : "0"
}, {
"fixed" : "3.11.7"
} ]
} ],
"database_specific" : {
"last_known_affected_version_range" : "<= 3.11.6"
}
} ],
"references" : [ {
"type" : "WEB",
"url" : "https://github.com/patriksimek/vm2/security/advisories/GHSA-c48m-32m9-vx93"
}, {
"type" : "ADVISORY",
"url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-92951"
}, {
"type" : "WEB",
"url" : "https://github.com/patriksimek/vm2/commit/ab4ee7d803e8c80155e9eb3672226bddbca4aa9c"
}, {
"type" : "PACKAGE",
"url" : "https://github.com/patriksimek/vm2"
}, {
"type" : "WEB",
"url" : "https://github.com/patriksimek/vm2/releases/tag/v3.11.7"
}, {
"type" : "WEB",
"url" : "https://www.vulncheck.com/advisories/vm2-before-3.11.7-module-allowlist-bypass-via-custom-resolver"
} ],
"database_specific" : {
"cwe_ids" : [ "CWE-706", "CWE-829", "CWE-863" ],
"severity" : "CRITICAL",
"github_reviewed" : true,
"github_reviewed_at" : "2026-10-01T15:37:19Z",
"nvd_published_at" : null
}
}