@faustine-ai/browser-sandbox
Run model-written JavaScript in the browser, in a dedicated Worker inside an
opaque-origin <iframe sandbox>: no network, no DOM, no storage, only the
functions you hand it, called over a private MessageChannel. Functions
you mark can be held for a human before they run. A busy loop is stopped
with terminate(), not hoped away.
your page sandbox frame (origin "null")
┌─────────────────────────────────────┐ ┌───────────────────────────────────────┐
│ functions = defineFunctions({ … }) │ │ CSP: default-src 'none'; │
│ run here, with your session, │ │ connect-src 'none'; │
│ your router, your storage │◀─MC──┼─▶ worker-src blob: │
│ │ │ ┌ Worker ─────────────────────────┐ │
│ sandbox.run({ code, functions }) │ │ │ sdk.orders.list(input) → "call" │ │
│ → { status, value | error | … } │ │ │ ES builtins, timers, console │ │
└─────────────────────────────────────┘ │ │ no fetch / XHR / WS / DOM │ │
│ └─────────────────────────────────┘ │
└───────────────────────────────────────┘- One door. The code sees a tree of the names you defined and nothing else. A name outside the map runs nothing.
- Structured clone only.
FileandBlobcross; functions, DOM nodes and class instances do not. - Approval at the bridge. Mark a function
approval: trueand decide per call (pause) or per batch after the run was cut (collect), with a deterministic replay. The model cannot skip it. - Real limits. Wall clock, a busy-loop watchdog, calls per run, input and output bytes, log lines. Expiry terminates the worker.
- Fits the AI SDK, Cloudflare
codemodeand TanStack AI through small adapters; no runtime dependency on any of them. - 8.5 KB min+gz for the core, 2.4 KB for the worker runtime, 0.5 KB for the frame relay. No dependencies.
Tested in Chromium, Firefox and WebKit on every change, including a suite of escape attempts that must all fail (see Security model).
Contents
- 01Why a frame and a worker
- 02Getting started
- 03Frame modessrcdoc: no server · url: a static document you serve
- 04Functions
- 05Running code
- 06Approvaldeny (default) · pause: one decision per call, the run waits · collect: one decision per batch, after the run was cut
- 07Limits and cancellation
- 08IntegrationsAI SDK (useChat, Chat) · Cloudflare @cloudflare/codemode · TanStack AI
- 09What crosses the boundary
- 10Security model
- 11Browser support, size, versioning
- 12API referencecreateSandbox(options): Sandbox · sandbox.run(options): Promise<RunResult> · Functions · Output · Frame (@faustine-ai/browser-sandbox/frame, also on the main entry) · Adapters · Types
- 13FAQ