Skip to content

v3.11.0

Choose a tag to compare

@patriksimek patriksimek released this 01 May 20:37
· 83 commits to main since this release

Coordinated security release closing 13 advisories, plus a new bufferAllocLimit option and a realpath() method on the FileSystem adapter contract. Minor version bump because of the new public option and the FileSystem contract addition; no incompatible changes to the existing public API surface.

Embedders running untrusted code should upgrade. Several of the advisories close full sandbox-escape RCE primitives.

What's Changed

Security fixes

Plus two related hardenings discovered during pre-release red-team:

  • trace_events added to the dangerous-builtins denylist — createTracing({categories: [Proxy<Array>]}) triggered a C++ assertion that aborted the host process.
  • wasi added to the denylist — experimental syscall surface (filesystem preopens, host clock/random, network) too broad for default '*' exposure.

New options

  • bufferAllocLimit (VM, NodeVM) — non-negative number or Infinity. Caps individual Buffer.alloc family requests from inside the sandbox. Default: Infinity (fully backwards-compatible). Embedders running untrusted code should opt into a finite cap as part of layered DoS defense.

FileSystem contract

  • DefaultFileSystem.realpath() and VMFileSystem.realpath() added. require.root boundary checks now canonicalise candidate paths via realpath before the prefix check, closing CWE-59 (symlinks inside the allowed root pointing outside it). Especially relevant for pnpm / npm-workspaces / npm link layouts where every node_modules entry is a symlink by design.

Upgrade Notes

  • Custom fs adapters with require.root must implement realpathSync (or realpath() on a fully custom FileSystem class). Without it, new NodeVM({require: {root, fs: customAdapter}}) now throws a VMError at construction citing GHSA-cp6g-6699-wx9c. Default fs users are unaffected.
  • Embedders running untrusted async code should install a host-side unhandledRejection handler. The GHSA-hw58 fix closes synchronous executor throws but cannot reach async-function / async-generator / await using rejection paths (V8 creates rejection promises via the realm's intrinsic Promise). See Hardening recommendations.
  • Embedders in memory-constrained environments should opt into a finite bufferAllocLimit (e.g. 32 * 1024 * 1024).

Documentation

Full Changelog: v3.10.5...v3.11.0