Executive Summary

A critical vulnerability in the vm2 command-line tool allows a malicious script to escape the sandbox and execute arbitrary code in the host Node.js process. This occurs when using the vm2 CLI to run a script, as it runs the script under NodeVM with require:{external:true} and no root/context/builtin configured. An attacker can exploit this by crafting a script that calls require(__filename) to re-execute itself in the host realm, gaining access to sensitive modules like fs and child_process.

Technical Analysis

The vulnerability is caused by the vm2 CLI invoking NodeVM.file with require:{external:true} and no root/context/builtin configured. This allows the resolver to load every relative or absolute require() target through the host require() function, executing the attacker's module body in the host Node.js process. The root cause is the lack of input validation and improper access control in the resolver.

How It Gets Exploited

An attacker can exploit this vulnerability by crafting a malicious script that calls require(__filename) to re-execute itself in the host realm. Here's a step-by-step scenario: - An attacker creates a malicious script, e.g., /tmp/poc.js. - The attacker runs the script using the vm2 CLI: vm2 /tmp/poc.js. - The script tries to require('fs') in the sandbox realm, which throws an error. - The script then calls require(__filename) to re-execute itself in the host realm. - The resolver loads the script via the host require() function, executing its top-level body in the host realm. - The script gains access to sensitive modules like fs and child_process, allowing it to write a sentinel file, e.g., /tmp/vm2.proof.

Impact Assessment

Users who run untrusted scripts with the vm2 CLI are affected. The vulnerability allows an attacker to execute arbitrary code in the host Node.js process, gaining access to sensitive modules and potentially leading to privilege escalation, data exfiltration, or denial-of-service attacks. The blast radius is the full host Node.js process.

Recommended Actions

To mitigate this vulnerability, users should update the vm2 package to a version that fixes the issue. Until a patch is available, users can block the exploitation by setting the require.root option when using the vm2 CLI. For example: ```javascript const vm2 = require('vm2'); const vm = new vm2.NodeVM({ require: { root: './sandboxed-modules', external: true } }); ``` Additionally, users should be cautious when running untrusted scripts with the vm2 CLI and consider using alternative sandboxing solutions.

Sources

- GitHub Security Advisories: https://github.com/advisories/GHSA-jxxv-8r27-vm4p