📦anthropics / sandbox-runtime
← 返回首页
A lightweight sandboxing tool for enforcing filesystem and network restrictions on arbitrary processes at the OS level, without requiring a container.
⚖️ Apache-2.0📅 创建于 2025-10-20🔄 更新于 2026-10-30
🔗 GitHub TypeScript

📄 仓库 README

在 GitHub 查看 ↗
来自 GitHub 仓库自述文件 · 版权归原作者所有

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:

  • Network restrictions: Control which hosts/domains can be accessed via HTTP/HTTPS and other protocols
  • Filesystem restrictions: Control which files/directories can be read/written
  • Unix socket restrictions: Control access to local IPC sockets
  • Violation monitoring: On macOS, tap into the system's sandbox violation log store for real-time alerts

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:

  • macOS: Uses sandbox-exec with dynamically generated Seatbelt profiles
  • Linux: Uses bubblewrap for containerization with network namespace isolation
  • Windows: Runs the sandboxed process under a dedicated srt-sandbox local user account, with a Windows Filtering Platform egress fence keyed on that account's SID, a write-restricted token, and explicit ACEs on the working 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:

  • Read (deny-then-allow pattern): By default, read access is allowed everywhere. You can deny broad regions (e.g., /Users) and then re-allow specific paths within them (e.g., .). allowRead takes precedence over denyRead — the opposite of write, where denyWrite takes precedence over allowWrite. A denyRead entry that is more specific than the allowRead region it falls inside (e.g. denyRead: ["**/.env"] or ["./secrets"] with allowRead: ["."]) still stays denied.
  • Write (allow-only pattern): By default, write access is denied everywhere. You must explicitly allow paths (e.g., ., /tmp). An empty allow list means no write access.

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:

  • Linux: Requests are routed via the filesystem over a Unix domain socket. The network namespace of the sandboxed process is removed entirely, so all network traffic must go through the proxies running on the host (listening on Unix sockets that are bind-mounted into the sandbox)

  • macOS: The Seatbelt profile allows communication only to a specific localhost port. The proxies listen on this port, creating a controlled channel for all network access

  • Windows: A machine-wide WFP filter set blocks outbound connections made by processes running as the srt-sandbox account except loopback to the proxy port range. The proxies listen inside that range, creating a controlled channel for all network access. The filters do not follow a sandboxed process that puts a different token on a thread before creating a socket, nor traffic that a system service carries on its behalf; see the Windows Known limitations

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

The settings file is optional — with no file at ~/.srt-settings.json, srt runs with built-in defaults: no network access, no writes outside the default write paths, and unrestricted reads. A settings file that is there but is empty, cannot be read, or does not validate is an error: srt says so and exits rather than falling back to those defaults, which are a different config rather than a weaker one — falling back would drop the file's denyRead, allowRead and credential rules along with everything else it said. The same goes for a file named with --settings, which must also exist.

Updating the config while the command runs: --control-fd

--control-fd <fd> reads config updates from a descriptor the caller has already opened, one JSON object per line in the same shape as the settings file. Each line replaces the whole config and is validated against the same schema, so a line is a complete config rather than a patch: network and filesystem are required, and a key the line leaves out goes back to its default.

# fd 3 is the read end of a pipe the caller writes lines to
srt --control-fd 3 -- npm test

What an accepted line changes once the command is running:

  • The network lists — network.allowedDomains, deniedDomains (with deniedDomainReasons) and deniedResolvedAddresses — take effect on the next connection, on every platform: the proxy consults them per request, and the resolved-address check is rebuilt from the same line. So do network.mitmProxy and network.tlsTerminate.excludeDomains, which it reads per request too.
  • credentials.sigv4 takes effect on the next request, provided srt started with a credentials block: the signing hook is installed only then, and reads the policies per request rather than capturing them.
  • Nothing else changes. The filesystem rules are already in the seatbelt profile, the bubblewrap argv or the Windows ACEs, the credential masks were built when the command was wrapped, and the running proxy servers captured network.parentProxy, and whether TLS is terminated at all, when they started.
  • On Windows, srt notices a line whose file-access set (filesystem.* together with credentials.files) differs from the one applied at startup, and says so only under SRT_DEBUG: the ACL grant is session-wide, so the set applied at startup stays in force. The rest of the line is applied as above.

How srt reads the channel, and what it refuses:

  • The descriptor must be an integer 3 or above and readable — 0-2 are the standard streams. srt exits with an error instead of running the command when it cannot read the descriptor it was given, so a dead channel never passes for a live one. A channel that dies before it has delivered a single update takes the

📈 近 7 天 Star 趋势

每日新增 Star(柱)与累计 Star(线)· 数据来自 GitHub

🏆 排名变化趋势

在各榜单中的排名历史(数字越小越靠前)

📋 历史上榜记录

每次快照的详细数据
日期 榜单 排名 周期新增 总 STAR