0001. Self-hosted executor on isolated-vm
- Status: accepted
- Date: 2026-08-01
Context
Section titled “Context”Language models write the JavaScript this product runs, on infrastructure the caller owns, with no dependency on the Cloudflare platform. Untrusted code needs containment that holds under a program written to break it: a separate heap, a memory limit the code cannot raise, and a CPU bound that survives an infinite loop. It also needs a process boundary, because a V8 isolate that dies badly should take exactly one supervised child with it.
node:vm shares the heap with the host. Its context boundary is escapable, and its own documentation says so outright: “The node:vm module is not a security mechanism. Do not use it to run untrusted code.”
SES and ShadowRealm give a clean object graph and no memory or CPU containment whatsoever, so a hostile program there has no bound to defeat. QuickJS compiled to WebAssembly does isolate properly, but it runs an order of magnitude slower and its global is just as empty, so the same implementation bill arrives without the speed. Running Node inside the sandbox is not an option that exists. Node is itself the embedder, and its surface is the anti-goal for untrusted code. Embedding workerd would buy a finished runtime at the price of adopting a whole platform for one isolate and surrendering control at the engine bridge.
Decision
Section titled “Decision”Generated code runs in V8 isolates through isolated-vm, inside supervised child processes. The pool spawns those processes, watches them by heartbeat, retires them by service life, and terminates them on a schedule when they stop answering. workerd is a measurement instrument here, not a dependency: it is the reference runtime the compatibility suite diffs against. Deno is the recorded fallback runtime if the isolated-vm path ever fails a containment gate.
Consequences
Section titled “Consequences”Every web API inside the isolate is this project’s work. Taking the embedder role for one isolate is the whole reason 0004 and 0003 exist, and the surface grows one capability at a time.
Owning the stack down to the engine bridge makes an engine-level defect fixable at all. This repository found the promise-settlement defect in the isolated-vm bridge, proved it by intervention, and carried it upstream. Under a platform dependency the same defect would have remained an inexplicable stall with nowhere to go.
isolated-vm is a native addon, so the runtime floor and the build toolchain become hard constraints, not preferences. Those two constraints are the subject of 0002. But the runtime stays swappable. This product’s contract is the wire protocol and the executor semantics, not isolated-vm. So a replacement lives inside one package, and the differential suite of 0005 proves the outside unchanged.