CyberLeveling Logo
CVE-2026-22709: vm2 Sandbox Escape

CVE-2026-22709: Understanding a Critical Sandbox Escape in vm2

Introduction

Running untrusted JavaScript safely is a common requirement in modern platforms, such as online code runners, plugin systems, rule engines, and low-code tools. One of the most popular libraries for this purpose in the Node.js ecosystem is vm2.

CVE-2026-22709 exposes a critical flaw in vm2’s sandbox model that allows attackers to escape the sandbox and execute arbitrary code on the host system. This blog post explains what went wrong, why it matters, and what developers can learn from it.

What Is vm2?

vm2 is an open-source Node.js library that provides a sandboxed environment for executing JavaScript code. It is designed to:

  • Restrict access to Node.js internals
  • Prevent filesystem and process access
  • Isolate untrusted code from the host application

Internally, vm2 relies on JavaScript language features like proxies, contexts, and object wrapping to enforce isolation.

Overview of CVE-2026-22709

  • CVE ID: CVE-2026-22709
  • Affected software: vm2
  • Affected versions: All versions prior to 3.10.2
  • Severity: Critical (CVSS approximately 9.8)
  • Impact: Sandbox escape leading to arbitrary code execution
  • Fixed in: vm2 version 3.10.2

At a high level, this vulnerability allows malicious code running inside the vm2 sandbox to break out and execute code with the same privileges as the Node.js process itself.

The Root Cause: Promise Callback Sanitization

Sanitization in vm2

vm2 attempts to protect the host by sanitizing callback functions passed into sensitive APIs. This includes callbacks passed to:

  • Promise.prototype.then
  • Promise.prototype.catch

Sanitization ensures that these callbacks cannot access dangerous objects like Function, process, or require.

Where It Went Wrong

The vulnerability comes from an incomplete sanitization strategy:

  • localPromise.prototype.then was sanitized
  • globalPromise.prototype.then was not sanitized

This distinction is critical.

Why Async Functions Matter

In JavaScript, all async functions return a global Promise object.

This means:

  • Code inside the vm2 sandbox defines an async function
  • Calling that function returns a global Promise
  • Callbacks attached via .then() or .catch() are not sanitized
  • The callback executes with access to unsafe constructors

This creates a clean and reliable sandbox escape path.

Impact: From Sandbox to System Access

By exploiting this flaw, an attacker can:

  • Reach powerful constructors such as Function
  • Reconstruct access to Node.js internals
  • Execute arbitrary JavaScript on the host
  • Potentially run system commands

In security terms, this is a remote code execution vulnerability for any application running untrusted code via vm2.

Who Is Affected?

You are at risk if your application:

  • Uses vm2 versions earlier than 3.10.2
  • Executes untrusted or user-supplied JavaScript
  • Runs in environments such as:
    • Online editors
    • Plugin systems
    • Automation engines
    • SaaS platforms with scripting features

Even if your usage seems limited, any exposure to attacker-controlled code is enough.

The Fix

The vm2 maintainers fixed this issue in version 3.10.2 by ensuring that:

  • Promise callbacks are sanitized consistently
  • Global and local Promise behavior is aligned

Recommended Actions

  • Upgrade immediately to vm2 version 3.10.2 or later
  • Audit where and why you run untrusted code
  • Consider defense-in-depth approaches, including:
    • OS-level sandboxing such as containers or microVMs
    • Dedicated isolation libraries like isolated-vm

Security Lessons Learned

1. JavaScript Is a Complex Attack Surface

Seemingly small differences, such as global versus local Promise objects, can have major security implications.

2. Language Features Can Bypass Security Assumptions

Async and await are language features, not library features. Security models must account for native behavior.

3. Sandboxing Is Extremely Hard

Pure JavaScript sandboxes are fragile. Every new language feature expands the attack surface.

4. Assume Escape Is Possible

When executing untrusted code:

  • Minimize privileges
  • Isolate at the OS or VM level
  • Monitor and limit potential damage

Conclusion

CVE-2026-22709 is a textbook example of how subtle JavaScript semantics can undermine sandbox security. A single missed sanitization path, combined with async functions, was enough to completely break vm2’s isolation guarantees.

If you rely on vm2, upgrading is mandatory. More importantly, this vulnerability is a reminder that JavaScript sandboxing should never be your only line of defense.