{"description":"Trending threats, MITRE ATT\u0026CK coverage, and detection metadata — refreshed continuously.","feed_url":"https://feed.craftedsignal.io/products/vm2-3.10.5/","home_page_url":"https://feed.craftedsignal.io/","items":[{"_cs_actors":[],"_cs_cves":[],"_cs_exploited":false,"_cs_products":["vm2 (3.10.5)"],"_cs_severities":["high"],"_cs_tags":["sandbox-escape","remote-code-execution","symlink"],"_cs_type":"advisory","_cs_vendors":["npm"],"content_html":"\u003cp\u003eThe vm2 library, a popular Node.js sandbox, is vulnerable to a symlink bypass in version 3.10.5. This flaw allows sandboxed code to escape the intended restrictions imposed by the \u003ccode\u003erequire.root\u003c/code\u003e option. The vulnerability arises because the path validation performed by \u003ccode\u003eisPathAllowed\u003c/code\u003e uses \u003ccode\u003epath.resolve()\u003c/code\u003e, which does not dereference symlinks. In contrast, Node.js\u0026rsquo;s native \u003ccode\u003erequire()\u003c/code\u003e function, used for module loading, does follow symlinks. This discrepancy allows an attacker to create a symlink within the allowed root directory that points to a location outside the root, effectively bypassing the sandbox and enabling the loading of arbitrary host-realm modules. This can lead to remote code execution on the host system. The presence of symlinks is common in environments using pnpm, npm workspaces, or npm link.\u003c/p\u003e\n\u003ch2 id=\"attack-chain\"\u003eAttack Chain\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003eHost application creates a \u003ccode\u003eNodeVM\u003c/code\u003e instance with \u003ccode\u003erequire.root\u003c/code\u003e set to a specific directory (e.g., \u003ccode\u003e/tmp/root\u003c/code\u003e) and \u003ccode\u003erequire.context\u003c/code\u003e set to \u003ccode\u003ehost\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eA symlink is created within the \u003ccode\u003erequire.root\u003c/code\u003e directory (e.g., \u003ccode\u003e/tmp/root/node_modules/safe\u003c/code\u003e) that points to a location outside the root directory (e.g., \u003ccode\u003e/outside/root/vm2/\u003c/code\u003e). This symlink can be created using tools like pnpm or npm link.\u003c/li\u003e\n\u003cli\u003eSandboxed code within the \u003ccode\u003eNodeVM\u003c/code\u003e calls \u003ccode\u003erequire('safe')\u003c/code\u003e, intending to load a module from within the allowed root.\u003c/li\u003e\n\u003cli\u003eThe \u003ccode\u003eDefaultResolver.resolveFull()\u003c/code\u003e function resolves the module path to \u003ccode\u003e/tmp/root/node_modules/safe/index.js\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eThe \u003ccode\u003eisPathAllowed()\u003c/code\u003e function checks if the resolved path starts with the \u003ccode\u003erequire.root\u003c/code\u003e directory, which passes because the symlink is not yet resolved.\u003c/li\u003e\n\u003cli\u003eThe \u003ccode\u003eloadJS()\u003c/code\u003e function detects that \u003ccode\u003econtext\u003c/code\u003e is set to \u003ccode\u003ehost\u003c/code\u003e and calls \u003ccode\u003ethis.hostRequire(filename)\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eNode.js\u0026rsquo;s native \u003ccode\u003erequire()\u003c/code\u003e function follows the symlink, loading the module from the actual location outside the root directory, \u003ccode\u003e/outside/root/vm2/index.js\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eThe module from outside the intended sandbox is executed in the host realm, potentially granting the attacker the ability to execute arbitrary commands on the host system.\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"impact\"\u003eImpact\u003c/h2\u003e\n\u003cp\u003eSuccessful exploitation allows untrusted sandboxed code to escape the vm2 sandbox, achieving remote code execution on the host system. An attacker can bypass the \u003ccode\u003erequire.root\u003c/code\u003e restriction, a primary defense mechanism, and load arbitrary modules from the host realm. This is particularly impactful in environments that use pnpm, npm workspaces, or \u003ccode\u003enpm link\u003c/code\u003e, as these tools frequently create symlinks, making the vulnerability more readily exploitable. The vulnerability can lead to complete compromise of the host system.\u003c/p\u003e\n\u003ch2 id=\"recommendation\"\u003eRecommendation\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eApply the recommended remediation by dereferencing symlinks with \u003ccode\u003efs.realpathSync\u003c/code\u003e before path validation in \u003ccode\u003elib/filesystem.js\u003c/code\u003e and \u003ccode\u003elib/resolver-compat.js\u003c/code\u003e as outlined in the advisory to prevent the bypass.\u003c/li\u003e\n\u003cli\u003eDeploy the \u0026ldquo;vm2 Sandbox Escape via Suspicious Host Require\u0026rdquo; Sigma rule to detect attempts to load modules from outside the intended sandbox via symlinks.\u003c/li\u003e\n\u003cli\u003eUpgrade to a patched version of vm2 that includes the fix for CVE-2026-43998.\u003c/li\u003e\n\u003c/ul\u003e\n","date_modified":"2024-01-03T12:00:00Z","date_published":"2024-01-03T12:00:00Z","id":"/briefs/2024-01-03-vm2-symlink-bypass/","summary":"A vulnerability exists in vm2 version 3.10.5 where NodeVM's `require.root` path restriction can be bypassed using filesystem symlinks, allowing sandboxed code to load modules from outside the allowed root directory in host context, leading to remote code execution.","title":"vm2 NodeVM require.root Bypass via Symlink Traversal","url":"https://feed.craftedsignal.io/briefs/2024-01-03-vm2-symlink-bypass/"}],"language":"en","title":"CraftedSignal Threat Feed — Vm2 (3.10.5)","version":"https://jsonfeed.org/version/1.1"}