Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: patriksimek/vm2
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v3.11.1
Choose a base ref
...
head repository: patriksimek/vm2
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v3.11.2
Choose a head ref
  • 4 commits
  • 9 files changed
  • 1 contributor

Commits on May 3, 2026

  1. fix(GHSA-9vg3-4rfj-wgcm): null-proto throw write-through via bridge f…

    …rom()
    
    handleException and globalPromise.prototype.then onFulfilled wrapped
    caught/resolved values with bridge.from(). from() builds a sandbox-side
    proxy whose target the bridge treats as host-realm; when called on a
    sandbox-realm null-proto value, the proxy's set trap unwraps incoming
    sandbox proxies of host references back to raw host originals and stores
    them on the underlying sandbox object. The original sandbox reference
    then yields the raw host fn -> .constructor is host Function -> RCE.
    
    Three callsites in lib/setup-sandbox.js reverted to ensureThis() (the
    pre-b57ac2d behavior, sandbox-realm safe). The host-Promise rejection
    sanitizer composes from() outside handleException so the GHSA-mpf8
    invariant -- host null-proto rejection values reach sandbox callbacks
    bridge-wrapped, not raw -- is preserved.
    
    Repro: test/ghsa/GHSA-9vg3-4rfj-wgcm/repro.js (7 tests, all pass after
    fix; 3 fail without it). ATTACKS.md gains Category 26.
    patriksimek committed May 3, 2026
    Configuration menu
    Copy the full SHA
    c33c2bb View commit details
    Browse the repository at this point in the history
  2. fix(GHSA-2cm2-m3w5-gp2f): bind internal state in GlobalLexicalEnviron…

    …ment
    
    GHSA-wp5r-2gw5-m7q7 closed the bare-identifier read path through the
    transformer but left every reflective probe of `globalThis` returning the
    internal state object (bracket access, `Reflect.get`, descriptor APIs,
    own-property enumeration). The transformer is a syntactic gate — it
    cannot see through computed property keys.
    
    Structural fix: declare the canonical identifier as a top-level `let` in
    the bootstrap script source (`vm.js`'s `setupSandboxScript`). The binding
    lands in the context's `[[GlobalLexicalEnvironment]]` — reachable as a
    bare identifier from every script in the context (so transformer-emitted
    catch handlers continue to resolve), but absent from the global object's
    own-property table (so every computed-key probe returns `undefined`).
    The IIFE in `setup-sandbox.js` assigns `interanState` into that outer
    binding; the previous `localReflectDefineProperty(global, …)` install is
    removed entirely.
    
    Three properties of `[[GlobalLexicalEnvironment]]` make this structural:
    
      - It IS reachable as a bare identifier from every script (user
        scripts, indirect-eval'd source, Function constructor bodies, the
        NodeVM module wrapper) — bare-identifier resolution walks the
        record after the script's own lex chain.
    
      - It is NOT reachable from `globalThis[k]`, `Reflect.get`,
        `Object.getOwnPropertyDescriptor`, `Object.getOwnPropertyNames`,
        `Reflect.ownKeys`, prototype-walk enumeration, or any other probe
        of the global object — `[[GlobalLexicalEnvironment]]` is a separate
        record from the global object's own-property table.
    
      - It persists across `runInContext` calls in the same context, so
        user-script `let x = …; …; vm.run('x.…')` semantics are preserved.
    
    The transformer continues to reject any user-source occurrence of the
    canonical identifier (including unicode-escape variants), so user code
    can neither shadow nor reference it. The only reference path that
    resolves is the transformer's own injected emissions.
    
    Supersedes GHSA-wp5r-2gw5-m7q7's identifier-only mitigation by closing
    the entire computed-key class structurally. ATTACKS.md Category 27.
    
    Tests:
      - test/ghsa/GHSA-2cm2-m3w5-gp2f/repro.js — 17 cases (9 attack vectors
        + 8 regressions across VM, NodeVM, VMScript). All pass with the
        fix; verified failing without the patch.
      - npm test — 346 passing, 12 pending, 0 failing.
    patriksimek committed May 3, 2026
    Configuration menu
    Copy the full SHA
    99d410b View commit details
    Browse the repository at this point in the history
  3. fix(GHSA-9qj6-qjgg-37qq): bridge saved-state leak via Array.prototype…

    …[N] setter
    
    `neutralizeArraySpeciesBatch` accumulated saved-state records in a fresh
    sandbox-realm `[]` and appended via `saved[saved.length] = c`. A sandbox
    setter on `Array.prototype[N]` captured that write and dereferenced
    `c.arr` (the host-realm proxy of the argument array) to reach host
    `Function` and execute arbitrary code.
    
    Install entries via `thisReflectDefineProperty` so each appended slot is
    an own data property and no `Array.prototype` setter is invoked while
    the bridge holds raw saved state. `restoreArraySpeciesBatch` becomes
    symmetric: indexed reads land on own data slots, so prototype getters
    cannot intercept restore either.
    
    Codified as new ATTACKS.md Defense Invariant #11
    ("Bridge-internal containers must not invoke sandbox code") and
    documented as Category 26.
    patriksimek committed May 3, 2026
    Configuration menu
    Copy the full SHA
    ca195f0 View commit details
    Browse the repository at this point in the history
  4. chore: bump to 3.11.2

    Patch release closing three advisories with no API changes:
    
    - GHSA-2cm2-m3w5-gp2f -- internal-state probe via computed-key access
      on globalThis (structural fix via GlobalLexicalEnvironment).
    - GHSA-9vg3-4rfj-wgcm -- sandbox-realm null-proto write-through via
      bridge from() set trap (revert sandbox-side from() to ensureThis).
    - GHSA-9qj6-qjgg-37qq -- bridge saved-state leak via Array.prototype[N]
      setter (defineProperty for own-slot writes in neutralizeArraySpeciesBatch).
    
    Tilde-pinned consumers (~3.11.x) auto-pull this release.
    patriksimek committed May 3, 2026
    Configuration menu
    Copy the full SHA
    7a552e8 View commit details
    Browse the repository at this point in the history
Loading