sandbox

js/ai/sandbox.ts

fino:ai/sandbox — capability-gated execution for model-written TypeScript.

An AISandbox runs source in a separate process Realm with a deny-all import map. The child can import only fino:ai/sandbox/capabilities; every operation in that synthetic module is checked and executed by the parent. Ambient network globals are removed before user source evaluates.

Grants are explicit values, not booleans: filesystem grants name roots, network grants name origins and methods, subprocess grants name binaries, and environment/secret grants contain only the names visible to the child. Resource limits bound capability calls and transferred bytes. Subprocesses additionally use the runtime's strict process sandbox and fail closed when the host cannot enforce it.

Audit events are published on fino:ai/sandbox. They contain capability names and targets but never environment or secret values.

import { AISandbox } from 'fino:ai/sandbox';

const code = `
  import { environment, readText } from 'fino:ai/sandbox/capabilities';
  export default async (path: string) => ({
    mode: await environment('MODE'),
    text: await readText(path),
  });
`;
using sandbox = new AISandbox(code, {
  environment: { MODE: 'analysis' },
  filesystem: { read: ['/srv/input'] },
});
console.log(await sandbox.call('/srv/input/prompt.txt'));

Interfaces

interface SandboxFilesystemGrant {

Filesystem roots visible to sandbox code.

Properties

read?: string[]

Absolute roots from which readText() may read.

write?: string[]

Absolute roots beneath which writeText() may write.

interface SandboxNetworkGrant {

HTTP requests visible to sandbox code.

Properties

origins: string[]

Exact URL origins such as https://api.example.com.

methods?: string[]

Allowed methods. Defaults to GET.

interface SandboxSubprocessGrant {

Strictly sandboxed child-process access.

Properties

commands: string[]

Exact executable paths the child may request.

environment?: Record<string, string>

Replacement environment for spawned commands. Defaults to empty.

sandbox?: ProcessSandboxOptions

Strict runtime sandbox policy. A fail-closed default is used when omitted.

timeoutMs?: number

Maximum command runtime. Defaults to 30 seconds.

interface SandboxResourceGrant {

Limits shared across one sandbox lifetime.

Properties

maxOperations?: number

Maximum parent-side capability calls. Defaults to 100.

maxReadBytes?: number

Maximum bytes returned by one file read. Defaults to 1 MiB.

maxWriteBytes?: number

Maximum bytes accepted by one file write. Defaults to 1 MiB.

maxNetworkBytes?: number

Maximum bytes returned by one HTTP response. Defaults to 1 MiB.

maxProcessOutputBytes?: number

Maximum combined stdout and stderr bytes. Defaults to 1 MiB.

wallClockMs?: number

Maximum elapsed time for one call(). Defaults to 30 seconds.

interface AISandboxOptions {

Capability grants supplied by trusted parent code.

Properties

filesystem?: SandboxFilesystemGrant

Scoped file access. Omit to deny all filesystem operations.

network?: SandboxNetworkGrant

Scoped outbound HTTP access. Omit to deny all network operations.

subprocess?: SandboxSubprocessGrant

Scoped subprocess access. Omit to deny all process creation.

environment?: Record<string, string>

Exact environment variable names and values visible to the child.

secrets?: Record<string, string>

Exact secret names and values visible to the child. Values are never audited.

resources?: SandboxResourceGrant

Operation, byte, and elapsed-time limits.

interface SandboxAuditEvent {

Event published for sandbox capability use, denial, and execution results.

Properties

capability: string

Capability such as filesystem.read, secret, or execute.

target?: string

Requested name, path, origin, or executable. Never a secret value.

outcome: 'used' | 'denied' | 'error'

Whether the operation was used, denied, or failed after authorization.

timestamp: number

Unix timestamp in milliseconds.

reason?: string

Human-readable denial or failure reason.

Classes

class SandboxDeniedError extends Error {

Structured error for a denied capability or exhausted resource grant.

Readonly Properties

readonly capability: string

Capability that rejected the request.

readonly target?: string

Requested target, when one is safe to expose.

Constructors

constructor(capability: string, message: string, target?: string)

Create a capability denial. Applications normally receive these from an AISandbox.

class AISandbox<F extends (...args: any[]) => any = (...args: any[]) => any> {

A single-use, process-isolated, parent-capability-backed TypeScript execution context. Single-use execution avoids retaining a privileged RPC channel after model-written code returns.

Call terminate() or use explicit resource management when done.

Constructors

constructor(source: string, options: AISandboxOptions = {})

Validate grants and prepare source for a deny-by-default process Realm.

Invalid grants throw during construction. Source transpilation and process creation happen when call() starts. Capability operations fail with SandboxDeniedError; child failures reject call().

Methods

async call(...args: Parameters<F>): Promise<Awaited<ReturnType<F>>>

Invoke the source module's default export.

The elapsed-time limit rejects and terminates the sandbox. Capability counters and byte limits apply to this single execution.

terminate(): void

Stop the process Realm. Repeated calls are harmless.