sandbox-runtime README

The project's README from github.com/anthropics/sandbox-runtime. As one markdown file: README.md.

Anthropic Sandbox Runtime (srt)

A lightweight sandboxing tool for enforcing filesystem and network restrictions on arbitrary processes at the OS level, without requiring a container.

srt uses native OS sandboxing primitives (sandbox-exec on macOS, bubblewrap on Linux) and proxy-based network filtering. It can be used to sandbox the behaviour of agents, local MCP servers, bash commands and arbitrary processes.

Beta Research Preview

The Sandbox Runtime is a research preview developed for Claude Code to enable safer AI agents. It's being made available as an early open source preview to help the broader ecosystem build more secure agentic systems. As this is an early research preview, APIs and configuration formats may evolve. We welcome feedback and contributions to make AI agents safer by default!

Installation

npm install -g @anthropic-ai/sandbox-runtime

Basic Usage

# Network restrictions
$ srt "curl anthropic.com"
Running: curl anthropic.com
<html>...</html>  # Request succeeds

$ srt "curl example.com"
Running: curl example.com
Connection blocked by network allowlist  # Request blocked

# Filesystem restrictions
$ srt "cat README.md"
Running: cat README.md
# Anthropic Sandb...  # Current directory access allowed

$ srt "cat ~/.ssh/id_rsa"
Running: cat ~/.ssh/id_rsa
cat: /Users/ollie/.ssh/id_rsa: Operation not permitted  # Specific file blocked

Overview

This package provides a standalone sandbox implementation that can be used as both a CLI tool and a library. It's designed with a secure-by-default philosophy tailored for common developer use cases: processes start with minimal access, and you explicitly poke only the holes you need.

Key capabilities:

Example Use Case: Sandboxing MCP Servers

A key use case is sandboxing Model Context Protocol (MCP) servers to restrict their capabilities. For example, to sandbox the filesystem MCP server:

Without sandboxing (.mcp.json):

{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem"]
    }
  }
}

With sandboxing (.mcp.json):

{
  "mcpServers": {
    "filesystem": {
      "command": "srt",
      "args": ["npx", "-y", "@modelcontextprotocol/server-filesystem"]
    }
  }
}

Then configure restrictions in ~/.srt-settings.json:

{
  "filesystem": {
    "denyRead": [],
    "allowWrite": ["."],
    "denyWrite": ["~/sensitive-folder"]
  },
  "network": {
    "allowedDomains": [],
    "deniedDomains": []
  }
}

Now the MCP server will be blocked from writing to the denied path:

> Write a file to ~/sensitive-folder
✗ Error: EPERM: operation not permitted, open '/Users/ollie/sensitive-folder/test.txt'

How It Works

The sandbox uses OS-level primitives to enforce restrictions that apply to the entire process tree:

0d1c612947c798aef48e6ab4beb7e8544da9d41a-4096x2305

Dual Isolation Model

Both filesystem and network isolation are required for effective sandboxing. Without file isolation, a compromised process could exfiltrate SSH keys or other sensitive files. Without network isolation, a process could escape the sandbox and gain unrestricted network access.

Filesystem Isolation enforces read and write restrictions:

Network Isolation (allow-only pattern): By default, all network access is denied. You must explicitly allow domains. An empty allowedDomains list means no network access. Network traffic is routed through proxy servers running on the host:

Both HTTP/HTTPS (via HTTP proxy) and other TCP traffic (via SOCKS5 proxy) are mediated by these proxies, which enforce your domain allowlists and denylists.

For more details on sandboxing in Claude Code, see:

Architecture

src/
├── index.ts                  # Library exports
├── cli.ts                    # CLI entrypoint (srt command)
├── utils/                    # Shared utilities
│   ├── debug.ts             # Debug logging
│   ├── settings.ts          # Settings reader (permissions + sandbox config)
│   ├── platform.ts          # Platform detection
│   └── exec.ts              # Command execution utilities
└── sandbox/                  # Sandbox implementation
    ├── sandbox-manager.ts    # Main sandbox manager
    ├── sandbox-schemas.ts    # Zod schemas for validation
    ├── sandbox-violation-store.ts # Violation tracking
    ├── sandbox-utils.ts      # Shared sandbox utilities
    ├── http-proxy.ts         # HTTP/HTTPS proxy for network filtering
    ├── socks-proxy.ts        # SOCKS5 proxy for network filtering
    ├── linux-sandbox-utils.ts # Linux bubblewrap sandboxing
    ├── macos-sandbox-utils.ts # macOS sandbox-exec sandboxing
    └── windows-sandbox-utils.ts # Windows srt-win sandboxing

Usage

As a CLI tool

The srt command (Anthropic Sandbox Runtime) wraps any command with security boundaries:

# Run a command in the sandbox
srt echo "hello world"

# With debug logging
srt --debug curl https://example.com

# Specify custom settings file
srt --settings /path/to/srt-settings.json npm install

As a library

import {
  SandboxManager,
  type SandboxRuntimeConfig,
} from '@anthropic-ai/sandbox-runtime'
import { spawn } from 'child_process'

// Define your sandbox configuration
const config: SandboxRuntimeConfig = {
  network: {
    allowedDomains: ['example.com', 'api.github.com'],
    deniedDomains: [],
  },
  filesystem: {
    denyRead: ['~/.ssh'],
    allowWrite: ['.', '/tmp'],
    denyWrite: ['.env'],
  },
}

// Initialize the sandbox (starts proxy servers, etc.)
await SandboxManager.initialize(config)

// Wrap a command with sandbox restrictions
const sandboxedCommand = await SandboxManager.wrapWithSandbox(
  'curl https://example.com',
)

// Execute the sandboxed command
const child = spawn(sandboxedCommand, { shell: true, stdio: 'inherit' })

// Handle exit and cleanup after child process completes
child.on('exit', async code => {
  console.log(`Command exited with code ${code}`)
  // Cleanup when done (optional, happens automatically on process exit)
  await SandboxManager.reset()
})

Violation attribution (commandId / commandText). Violations observed while a wrapped command runs (seatbelt log lines, seccomp events, proxy denies) are stored under an attribution key, and annotateStderrWithSandboxFailures(key, stderr) / getViolationsForCommand(key) look them up by that same key. By default the key is the wrapped string itself. Pass an opaque per-invocation commandId (e.g. a tool-use id) to key by that instead — recommended: keys compare on their first 100 characters, so long commands sharing a prefix would otherwise cross-attribute, and a rerun of the same text would inherit the earlier run's events. If the string you execute is not the command the invocation represents (e.g. you wrap an assembled source <snapshot> && eval '<cmd>'), also pass commandText: '<cmd>': it is what ignoreViolations command patterns match against and what each violation reports as its command.

const wrapped = await SandboxManager.wrapWithSandbox(
  assembledCommand, // what actually runs
  undefined,
  undefined,
  undefined,
  { commandId: invocationId, commandText: rawCommand },
)
// ... run it ...
const annotated = SandboxManager.annotateStderrWithSandboxFailures(invocationId, stderr)

Available exports

// Main sandbox manager
export { SandboxManager } from '@anthropic-ai/sandbox-runtime'

// Violation tracking
export { SandboxViolationStore } from '@anthropic-ai/sandbox-runtime'

// TypeScript types
export type {
  SandboxRuntimeConfig,
  NetworkConfig,
  FilesystemConfig,
  IgnoreViolationsConfig,
  SandboxAskCallback,
  FsReadRestrictionConfig,
  FsWriteRestrictionConfig,
  NetworkRestrictionConfig,
} from '@anthropic-ai/sandbox-runtime'

Configuration

Settings File Location

By default, the sandbox runtime looks for configuration at ~/.srt-settings.json. You can specify a custom path using the --settings flag:

srt --settings /path/to/srt-settings.json <command>

Complete Configuration Example

{
  "network": {
    "allowedDomains": [
      "github.com",
      "*.github.com",
      "lfs.github.com",
      "api.github.com",
      "npmjs.org",
      "*.npmjs.org"
    ],
    "deniedDomains": ["malicious.com"],
    "allowUnixSockets": ["/var/run/docker.sock"],
    "allowLocalBinding": false
  },
  "filesystem": {
    "denyRead": ["~/.ssh"],
    "allowRead": [],
    "allowWrite": [".", "src/", "test/", "/tmp"],
    "denyWrite": [".env", "config/production.json"]
  },
  "ignoreViolations": {
    "*": ["/usr/bin", "/System"],
    "git push": ["/usr/bin/nc"],
    "npm": ["/private/tmp"]
  },
  "enableWeakerNestedSandbox": false,
  "enableWeakerNetworkIsolation": false,
  "allowAppleEvents": false
}

Configuration Options

Network Configuration

Uses an allow-only pattern - all network access is denied by default.

TLS termination (network.tlsTerminate, experimental): when set, HTTPS CONNECTs are terminated in-process so SRT can see (and filter, via network.filterRequest) the decrypted requests. The sandboxed process is pointed at a trust bundle containing the MITM CA (caCertPath/caKeyPath, or an ephemeral CA if omitted) plus the host's regular roots, so proxy-minted certificates and real upstream certificates both verify.

{
  "network": {
    "allowedDomains": ["*.example.com", "internal-mtls.example.net"],
    "deniedDomains": [],
    "tlsTerminate": {
      "excludeDomains": ["internal-mtls.example.net"],
      "extraCaCertPaths": ["/etc/internal-mtls-roots.pem"]
    }
  }
}

Unix Socket Settings (platform-specific behavior):

Setting macOS Linux
allowUnixSockets: string[] Allowlist of socket paths Ignored (seccomp can't filter by path)
allowAllUnixSockets: boolean Allow all sockets Disable seccomp blocking

Unix sockets are blocked by default on both platforms.

Filesystem Configuration

Uses two different patterns:

Read restrictions (deny-then-allow pattern) - all reads allowed by default:

Write restrictions (allow-only pattern) - all writes denied by default:

Path Syntax (macOS):

Paths support git-style glob patterns on macOS, similar to .gitignore syntax:

Examples:

Path Syntax (Linux):

Linux currently does not support glob matching. Use literal paths only:

All platforms:

Other Configuration

sandbox-runtime (anthropics/sandbox-runtime)

Searching Database…

Что это такое?srt (Anthropic Sandbox Runtime) — это легковесный инструмент изоляции, который накладывает ограничения на доступ к файловой системе и сети для любых процессов на уровне операционной системы, без необходимости в контейнере. Он создан для безопасного запуска ИИ-агентов, локальных MCP-серверов и bash-команд.
Это CLI-инструмент или библиотека, которую я импортирую в код?И то, и другое: srt поставляется как отдельный CLI, который оборачивает любую команду, а также как пакет, который можно импортировать, чтобы встроить изоляцию в свой код на TypeScript/Node.
Как запустить команду внутри песочницы?Оберните любую команду в CLI srt (например, `srt -- your-command`). По умолчанию ограничения читаются из ~/.srt-settings.json, но можно указать другой файл с помощью флага --settings.
Нужны ли Docker или виртуальная машина для использования?Нет, среда контейнеров вообще не требуется: srt использует встроенные механизмы ОС — sandbox-exec на macOS, bubblewrap на Linux, а на Windows отдельную локальную учетную запись и фильтр исходящего трафика на базе Windows Filtering Platform. Это пакет Node.js, написанный на TypeScript (для работы нужен Node 20.11+).
Насколько это стабильно и готово ли к продакшену?Проект официально помечен как Beta Research Preview и создан для Claude Code. Авторы говорят, что API и форматы конфигурации могут еще меняться, и просят обратную связь, поэтому относитесь к этому как к ранней стадии.
Получает ли Windows такие же гарантии изоляции, как macOS и Linux?Не совсем тот же механизм: macOS и Linux используют настоящие песочницы уровня ядра (Seatbelt и bubblewrap), а Windows запускает процесс под отдельной локальной учетной записью srt-sandbox, с сетевым фильтром на уровне всей машины и файловыми ACL, действующими на время сеанса.
Зачем изолировать MCP-сервер?MCP-серверам по умолчанию часто выдается широкий доступ к файловой системе и сети. Если обернуть такой сервер в srt, можно ограничить его только теми путями и доменами, которые ему действительно нужны, например запретить запись за пределами разрешенной папки.
Как работают правила разрешения и запрета для сети?Доступ к сети работает по принципу «только разрешенное»: всё запрещено, пока вы не добавите домен в allowedDomains (поддерживаются подстановочные символы и необязательные суффиксы :port). При этом deniedDomains всегда имеют приоритет и могут содержать собственную причину блокировки, которая показывается заблокированному процессу.
Почему правила чтения и записи файлов устроены по-разному?Чтение работает по схеме «сначала запрет, потом выборочное разрешение»: всё доступно для чтения, пока вы не запретите, а затем выборочно разрешаете нужное. Запись устроена строже, по схеме «только разрешенное»: всё запрещено, пока явно не разрешено. Доступ на запись — это то, что нужно включать вручную для каждого пути.
Может ли он перехватывать HTTPS-трафик для фильтрации?Да, через экспериментальный режим терминации TLS: он выполняет MITM-перехват HTTPS CONNECT-запросов внутри самого процесса, чтобы SRT мог проверять и фильтровать расшифрованные запросы. Можно исключить домены, которые используют mTLS или закрепление сертификатов (certificate pinning).
What are similar projects?arc-code, agentbox, qwen-code, quicksand, NemoClaw, nono, box, SPACE
Creator
anthropics
Size
10.7 MB
Stars
5.6K
Age
11mo
Commits · 90 Days