agentskit.js
Security

Sandbox: deep dive

How @agentskit/sandbox executes untrusted code — backends, policies, limits, and honest isolation claims.

@agentskit/sandbox is the primitive layer underneath the mandatory-sandbox policy. Where the policy is about which tools an agent can call, the sandbox is about where that code actually runs. This page covers the real public surface.

#When you need it

ScenarioSandbox
Agent emits arbitrary JS / PythonRequired
Agent runs shell against user-supplied commandsRequired
Agent reads / writes files in user-controlled pathsStrongly recommended
Agent calls a fixed set of HTTP integrations (Slack, GitHub, etc.)Not required — those tools are already constrained

If your agent's tool set is "send Slack message" + "read three blog posts", you don't need a sandbox. If your agent generates code or shells out to anything user-supplied, you do.

#Backends

@agentskit/sandbox is a thin abstraction; backends do the actual isolation. Each backend implements the package-local SandboxBackend interface:

interface SandboxBackend {
  execute(code: string, options?: ExecuteOptions): Promise<ExecuteResult>
  dispose?(): Promise<void>
}

interface ExecuteResult {
  stdout: string
  stderr: string
  exitCode: number
  durationMs: number
}

#E2B (default cloud backend — optional peer)

import { createSandbox } from '@agentskit/sandbox'

const sandbox = createSandbox({
  apiKey: process.env.E2B_API_KEY!,
  language: 'python',
  timeout: 30_000,        // per-execute wall clock (ms)
  network: false,         // default; maps to allowInternetAccess: false
  // memoryLimit: '512mb' // accepted, NOT enforced by E2B via this adapter
})

Install the optional peer:

npm install @e2b/code-interpreter

The adapter calls Sandbox.create({ apiKey, timeoutMs, allowInternetAccess }) (SDK 2.x). It does not pass a legacy { timeout } field.

Strict isolation: no host filesystem access; no network unless network: true. Combined stdout+stderr is byte-capped. On execute timeout the VM is killed and reset so work cannot continue orphaned.

#Web Worker (@agentskit/sandbox/web)

Browser-native, zero-vendor JS execution off the main thread.

BoundaryProvided?
Thread isolationYes
DOM isolationYes
Network security boundaryNo
Filesystem security boundaryNo
WebContainerNo — this is not StackBlitz WebContainer

Use for playgrounds and semi-trusted JS. For multi-tenant untrusted code, prefer E2B or a container runtime.

#Local runtimes

  • processSandbox — child process + env allowlist (weak isolation)
  • sandboxExecRuntime — macOS seatbelt (scoped file-read, not global)
  • bwrapRuntime — Linux bubblewrap (beta; registry level stays 'process' for compatibility)
  • dockerRuntime — Docker with cap-drop / no-new-privileges; rejects host namespace and privileged escapes in extraArgs

#Custom backend

import type { SandboxBackend } from '@agentskit/sandbox'

const myBackend: SandboxBackend = {
  async execute(code, options) {
    return { stdout: '', stderr: '', exitCode: 0, durationMs: 0 }
  },
  async dispose() {},
}

const sandbox = createSandbox({ backend: myBackend })

#Policy + sandbox together

import { sandboxTool, createMandatorySandbox } from '@agentskit/sandbox'
import { filesystem } from '@agentskit/tools'

const codeExecution = sandboxTool({ apiKey: process.env.E2B_API_KEY! })

const mandatory = createMandatorySandbox({
  sandbox: codeExecution,
  policy: {
    allow: ['code_execution'],
    deny: ['filesystem'],
    requireSandbox: ['code_execution'],
  },
})

const tools = [codeExecution, filesystem({ basePath: './workspace' })].map((t) =>
  mandatory.wrap(t),
)

Important: when requireSandbox matches, the original tool execute body is not invoked. Args are delegated to the sandbox tool's execute. This is intentional routing, not a transparent wrap.

#Failure modes

SymptomCauseFix
AK_SANDBOX_PEER_MISSING@e2b/code-interpreter not installednpm install @e2b/code-interpreter
AK_SANDBOX_BACKEND_FAILEDBackend init/runtime failed (auth, network, disposed)Check apiKey, quota, dispose lifecycle
AK_CONFIG_INVALIDEmpty apiKey, non-positive timeout, bad language, unsafe docker argsFix caller config
AK_SANDBOX_DENIEDPolicy denied the callAdjust allow / deny lists
AK_SANDBOX_INVALID_TOOLWrapped tool has no executeFix the source ToolDefinition
Execute timeoutHit per-call timeoutIncrease timeout or split work; E2B kills the VM on timeout

Errors are typed (SandboxError / ConfigError) — pattern-match on code. Backend errors that merely mention @e2b are not classified as peer missing.

#Cost + latency

Per E2B's pricing, a sandboxed call is typically tens–hundreds of ms plus VM time. Budget accordingly. Pair with observability cost guards if needed.

Explore nearby

✎ Edit this page on GitHub·Found a problem? Open an issue →·How to contribute →

On this page

Ask the docs
Ask anything about AgentsKit. Answers come from the docs corpus and cite their sources.