Foundations

Sandbox

Understand the environment where source code executes.

Sandbox

The sandbox is the restricted JavaScript environment in which guest source executes. It is implemented with QuickJS inside a Node.js worker thread and is created fresh for every invocation.

The sandbox provides the JavaScript needed to compute over data, but no ambient access to the host application. Reaching application data or an external service requires a host function.

Source

The source property accepts JavaScript or type-stripped TypeScript. The source is evaluated as the body of an asynchronous function rather than as a module, so it can use top-level await and return.

const result = await run({
  source: `
    const values: number[] = [10, 20, 12];
    return values.reduce((total, value) => total + value, 0);
  `,
});

Capabilities and limitations

  • Guest code can use standard JavaScript values such as objects, arrays, promises, maps, sets, dates, regular expressions, errors, typed arrays, and internationalization APIs. It can also use a size-limited console, together with atob() and btoa().
  • The guest implementation of Date and Math.random() is deterministic. This allows an interrupted run to execute consistently when it is replayed.
  • TypeScript annotations are stripped before execution. Common TypeScript syntax works, but nothing is type-checked and this is not a full TypeScript compiler.
  • The source cannot use static imports or dynamic import(). Dependencies must either be included directly in the source or represented by a host function.
  • The sandbox does not provide Node.js globals such as process, require, module, or Buffer. It also does not provide browser networking APIs such as fetch, WebSocket, or XMLHttpRequest.
  • Guest code cannot access the filesystem, environment variables, host modules, or application memory. Timers such as setTimeout() and setInterval() are not available. Dynamic code generation through eval() and Function() is blocked, and capabilities such as crypto, WebAssembly, and SharedArrayBuffer are not exposed.

Globals

Each host function namespace becomes a global object in the sandbox. If the host provides a users namespace with a host function named find, guest code can call users.find().

const hostFunctions = {
  users: {
    find: async (id: string) => {
      return { id, name: 'Ada' };
    },
  },
};

A host function namespace must be a valid JavaScript identifier and must not conflict with a reserved global. Names beginning with __run are reserved for the runtime.

The sandbox also contains internal runtime helpers. They are implementation details, not part of the guest API.

Isolation

Every invocation receives a separate QuickJS context with its own global objects and values. The context is disposed when the invocation finishes, so guest state does not persist between invocations.

Worker threads may be pooled and reused. Reusing a worker does not reuse the guest context that previously ran inside it.

The sandbox is a separate JavaScript engine on a worker thread, with hardened globals, explicit host functions, serialization, and resource limits. It is not a container, a virtual machine, or a separate operating-system process.

Trust

The sandbox controls what guest code can access directly, but host functions remain trusted application code. A broad host function grants broad authority, however well the sandbox itself is configured.

A host function that accepts an arbitrary URL and forwards the request, for example, hands the guest general network access. Accept a specific business-level operation instead, validate its arguments, enforce authorization in the host, and return only the data the guest needs.

The sandbox is one part of the security model. Host function design and resource limits determine what guest code can actually do.