Your RSA-2048 keys break in 2030. Find every one of them before attackers do.
📦 npm
Not in CISA KEV

CVE-2026-92939 — vm2

Fix: patriksimek/vm2@aa146a7

CVE-2026-92939 is a CWE-114 vulnerability in vm2. A fix is available for vm2 — see the affected versions and patch details below.

vm2 3.11.3 through 3.11.6 Native Code Execution via crypto.setEngine

Also known asGHSA-46pr-c5wc-xffx
Published
Updated
Affected
1 pkg
Patched
1 / 1
Exploits
None indexed
Exploitation data as of Oct 22, 2026 · OSV.dev, NVD, FIRST.org (EPSS)

Exploitation Status

Proof-of-concept exploit code exists

  • CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.
  • A successful exploit gives an attacker total control of the affected component, not partial access.

Exploitation and automatability from CISA’s SSVC triage for CVE-2026-92939.

EPSS Exploitation Probability

via FIRST.org ↗
0.6%probability of exploitation in next 30 days
Lower Risk0.00%
Lower risk than most CVEs49th percentile — riskier than 49% of all scored CVEsHighest risk
0.12%0.45%0.78%1.12%0.6%0.6%Oct 26Oct 26

Probability of exploitation in the next 30 days, from FIRST.org EPSS.

Real-World Exposure

1 pkg affected
📦vm2

Real-time download stats are indexed for npm and PyPI packages. This vulnerability affects npm packages — download data is not available via public APIs for these ecosystems.

Description

Summary

vm2 3.11.6 exposes the host crypto module to a NodeVM when that single builtin is allowed. The module is presented through a read-only bridge, but its functions still execute with host-process authority. crypto.setEngine() accepts a filesystem path and asks OpenSSL to dynamically load the referenced native library.

An attacker whose untrusted plugin package contains a native library can therefore load that library into the host process by calling crypto.setEngine() from sandboxed JavaScript. The native library's constructor executes before OpenSSL finishes validating whether the file is a usable engine. Consequently, even the expected ERR_CRYPTO_ENGINE_UNKNOWN exception occurs only after arbitrary native code has already run.

The exploit requires only the crypto builtin. It does not require fs, process, module, child_process, worker_threads, vm, inspector, unrestricted builtins, or vm2 nesting.

Details

The vulnerable boundary is the generic builtin loader. Builtins that are not specially wrapped or classified as dangerous are imported in the host realm and exposed through a recursive read-only proxy:

builtins.set(key, special ? special : vm => vm.readonly(hostRequire(key)));

Read-only prevents sandbox code from assigning properties on the module object. It does not reduce the authority of callable exports. Calls are forwarded to the original host function with bridge values converted back to host values.

The crypto module includes this callable export:

crypto.setEngine(enginePath)

When enginePath names a dynamic library, OpenSSL loads that file into the current process. Operating-system dynamic loaders execute library constructors as part of loading. Engine-symbol validation happens afterward. A file does not have to become a functional cryptographic engine for its constructor to execute.

The resulting exploit flow is:

attacker supplies an untrusted plugin package containing a native library
  -> host executes the plugin in NodeVM with only crypto allowed
  -> plugin calls crypto.setEngine(pathToBundledLibrary)
  -> vm2 forwards the call to the host crypto module
  -> OpenSSL asks the operating-system loader to load the library
  -> the library constructor executes native code in the host process
  -> OpenSSL may then reject the file, but host compromise has already occurred

This is different from merely granting JavaScript filesystem access. A plugin system commonly has to place an untrusted package on disk before running its JavaScript. The native file can therefore already exist inside that package even when the sandbox denies fs and all process-execution builtins. Allowing crypto for hashing or signature verification unexpectedly turns that inert package file into a native-code execution primitive.

PoC

The attached PoC is local and harmless. Its native library constructor creates a marker file; it does not spawn a process, open a network connection, or modify any other file.

  1. Install Node.js with OpenSSL engine support, a C compiler, and npm.

  2. In the attached poc directory, install the exact affected package:

    npm install --ignore-scripts
    
  3. Build the marker library.

    On macOS:

    cc -dynamiclib -O2 -o probe-engine.dylib engine_probe.c
    node poc.js ./probe-engine.dylib
    

    On Linux:

    cc -shared -fPIC -O2 -o probe-engine.so engine_probe.c
    node poc.js ./probe-engine.so
    
  4. A vulnerable result contains all of the following:

    • the sandbox configuration lists only crypto as an allowed builtin;
    • crypto.setEngine() reports ERR_CRYPTO_ENGINE_UNKNOWN or returns;
    • vm2-setengine-native-marker.txt exists afterward;
    • the marker contains VM2_SETENGINE_NATIVE_CODE_EXECUTED.

The exception is not a negative result. The marker proves that the native constructor ran before engine validation failed.

Impact

This is a sandbox escape to arbitrary native code execution. The code runs with the operating-system identity and privileges of the Node.js host process, outside all vm2 language and module restrictions.

An attacker can replace the marker-only constructor with native code that:

  • reads application secrets, environment variables, credentials, and files available to the host user;
  • modifies application data or executable files and establishes persistence;
  • accesses internal services using the host's network identity;
  • steals other tenants' data from the same process;
  • terminates or corrupts the host process; and
  • executes arbitrary operating-system actions permitted to the host account.

The realistic affected workflow is a plugin, automation, notebook, or multi-tenant code runner that stores attacker-supplied package contents on disk and runs the package's JavaScript in NodeVM while allowing crypto. The attacker does not need the sandbox to expose a file-write or command-execution module.

Affected Packages

1 total 1 fixed
EcosystemPackageVulnerable rangeFix
📦npmvm2≥ 3.11.3&&< 3.11.73.11.7npm install vm2@3.11.7

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for vm2, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.

  2. Fix

    Update vm2 to 3.11.7 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-92939 is resolved across your whole dependency graph.

  3. Workarounds

    If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.

Fixing This On Your OS

If you run this on a Linux distribution, patch through your package manager against the distro's own security advisory below — it tracks the exact backported fix for your release, which can ship on a different timeline (and sometimes a different severity) than the upstream project.

Red HatImportant

This vulnerability is rated as Important rather than Critical because successful exploitation requires specific environmental prerequisites, including the allowance of the built-in cryptographic module within the execution sandbox and the presence of an attacker-controlled shared library on the local filesystem. In…

Workaround published by Red Hat
Mitigation for this issue is either not available or the currently available options do not meet the Red Hat Product Security criteria comprising ease of use and deployment, applicability to widespread installation base, or stability.
Source: Red Hat security advisory for CVE-2026-92939 (CC BY 4.0)
ProductFixed inAdvisory
Red Hat Ansible Automation Platform 2.1ansible-automation-platform/automation-portal:1791295379RHSA-2026:80603
Red Hat Ansible Automation Platform 2.2ansible-automation-platform/automation-portal:1791293780RHSA-2026:80644
Red Hat Ansible Automation Platform 2.2ansible-automation-platform/bootc-automation-portal-rhel9:1791865660RHSA-2026:82151
Red Hat Developer Hub 1.10rhdh/red-hat-developer-hub-backstage-plugin-lightspeed-backend:1791242697RHSA-2026:76788
Red Hat Developer Hub 1.10rhdh/rhdh-hub-rhel9:1791311495RHSA-2026:79088

Frequently Asked Questions

Summary vm2 3.11.6 exposes the host `crypto` module to a `NodeVM` when that single builtin is allowed. The module is presented through a read-only bridge, but its functions still execute with host-process authority. `crypto.setEngine()` accepts a filesystem path and asks OpenSSL to dynamically load the referenced native library. An attacker whose untrusted plugin package contains a native library can therefore load that library into the host process by calling `crypto.setEngine()` from sandboxed JavaScript. The native library's constructor executes before OpenSSL finishes validating whether
O3 Security · Impact-Aware SCA

Is CVE-2026-92939 in your dependencies?

Find it across npm, including transitive dependencies.

CVE-2026-92939: vm2 — Fixed in 3.11.7