返回更新列表
新发布Aug 27, 2026

sandbox-runtime v0.0.74

一个轻量级沙箱工具,用于在操作系统层面强制执行任意进程的文件系统和网络限制,而无需使用容器。

分享

Anthropic 沙箱运行时(srt)

一个轻量级沙箱工具,用于在操作系统层面强制对任意进程实施文件系统和网络限制,无需容器。

srt 使用原生操作系统沙箱原语(macOS 上的 sandbox-exec,Linux 上的 bubblewrap)以及基于代理的网络过滤。它可用于沙箱化智能体、本地 MCP 服务器、bash 命令和任意进程的行为。

Beta 研究预览版

沙箱运行时是为 Claude Code 开发的研究预览版,旨在实现更安全的 AI 智能体。它作为早期开源预览版发布,以帮助更广泛的生态系统构建更安全的智能体系统。由于这是早期研究预览版,API 和配置格式可能会发生变化。我们欢迎反馈和贡献,以默认让 AI 智能体更安全!

安装

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

基本用法

# 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

概述

此包提供了一个独立的沙箱实现,既可作为 CLI 工具使用,也可作为库使用。它遵循默认安全的设计理念,针对常见的开发者使用场景量身定制:进程以最小权限启动,您只需显式地打开所需的权限缺口。

核心能力:

  • 网络限制:控制可通过 HTTP/HTTPS 及其他协议访问的主机/域名
  • 文件系统限制:控制可读取/写入的文件/目录
  • Unix 套接字限制:控制对本地 IPC 套接字的访问
  • 违规监控:在 macOS 上,接入系统的沙箱违规日志存储以获取实时警报

使用案例:沙箱化 MCP 服务器

一个关键用例是对模型上下文协议(MCP)服务器进行沙箱化,以限制其能力。例如,要对文件系统 MCP 服务器进行沙箱化:

不使用沙箱(.mcp.json):

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

使用沙箱(.mcp.json):

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

然后在 ~/.srt-settings.json 中配置限制:

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

现在 MCP 服务器将被阻止写入被拒绝的路径:

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

工作原理

该沙箱使用操作系统级原语来强制执行适用于整个进程树的限制:

  • macOS:使用 sandbox-exec 配合动态生成的 Seatbelt 配置文件
  • Linux:使用 bubblewrap 进行容器化,并实现网络命名空间隔离
  • Windows:在专用的 srt-sandbox 本地用户账户下运行沙箱进程,并使用以该账户的 SID 为键的 Windows 筛选平台 出站防护,以及在工作树上的每会话显式 ACE

0d1c612947c798aef48e6ab4beb7e8544da9d41a-4096x2305

双重隔离模型

有效的沙箱化需要同时实现文件系统和网络隔离。如果没有文件隔离,被攻陷的进程可能会窃取 SSH 密钥或其他敏感文件。如果没有网络隔离,进程可能逃逸沙箱并获得不受限制的网络访问。

文件系统隔离 强制执行读和写限制:

  • 读(先拒绝后允许模式):默认情况下,允许在所有位置进行读取访问。你可以拒绝大范围区域(例如 /Users),然后重新允许其中的特定路径(例如 .)。allowRead 优先于 denyRead——这与写操作相反,在写操作中 denyWrite 优先于 allowWrite。比其所在的 allowRead 区域更具体的 denyRead 条目(例如 denyRead: ["**/.env"] 或 ["./secrets"] 配合 allowRead: ["."])仍然保持拒绝状态。
  • 写(仅允许模式):默认情况下,拒绝在所有位置进行写入访问。你必须显式允许路径(例如 .、/tmp)。空的允许列表意味着没有写入访问权限。

网络隔离(仅允许模式):默认情况下,拒绝所有网络访问。你必须显式允许域名。空的 allowedDomains 列表意味着没有网络访问权限。网络流量通过运行在主机上的代理服务器进行路由:

  • Linux:请求通过 Unix 域套接字经由文件系统进行路由。沙箱进程的网络命名空间被完全移除,因此所有网络流量必须通过运行在主机上的代理(监听绑定挂载到沙箱中的 Unix 套接字)

  • macOS:Seatbelt 配置文件仅允许与特定 localhost 端口通信。代理监听此端口,为所有网络访问创建受控通道

  • Windows:机器范围的 WFP 筛选器集阻止源自 srt-sandbox 账户的所有出站连接,但发往代理端口范围的环回连接除外。代理在该范围内监听,为所有网络访问创建受控通道

HTTP/HTTPS(通过 HTTP 代理)和其他 TCP 流量(通过 SOCKS5 代理)均由这些代理进行中介,这些代理强制执行你的域名允许列表和拒绝列表。

有关 Claude Code 中沙箱化的更多详细信息,请参阅:

架构

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

使用方法

作为 CLI 工具

srt 命令(Anthropic Sandbox Runtime)将任何命令包装在安全边界内:

# 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

设置文件是可选的——如果 ~/.srt-settings.json 处没有文件,srt 会使用内置默认值运行:无网络访问、不在默认写入路径之外写入、读取不受限制。如果设置文件_确实_存在但为空、无法读取或未通过校验,则视为错误:srt 会报告该错误并退出,而不是回退到那些默认值,因为那些默认值是一种不同的配置,而非更弱的配置——回退会丢弃该文件中的 denyRead、allowRead 和凭据规则以及它所述的其他所有内容。通过 --settings 指定的文件也是如此,该文件也必须存在。

在命令运行期间更新配置:--control-fd

--control-fd <fd> 从调用方已打开的描述符读取配置更新,每行一个 JSON 对象,其结构与设置文件相同。每一行都会替换整个配置,但只有网络列表(allowedDomains / deniedDomains)会改变已在运行的内容:代理会按请求查询它们。文件系统规则在包装时被编译进沙箱,因此更改它们的行对当前运行中的任何内容都不适用。

# fd 3 is the read end of a pipe the caller writes lines to
srt --control-fd 3 -- npm test
  • 描述符必须是3 或以上的整数且可读——0-2 是标准流。当 srt 无法读取给定的描述符时,它会报错退出而不是运行命令,因此死通道永远不会被误认为活通道。在传递任何更新之前就死掉的通道会连带终止命令;在传递更新之后才死掉的通道会报告这一情况,并让命令在最后应用的配置下继续运行。
  • 不是有效配置的行会在 stderr 上报告并被丢弃;之前的配置继续生效。
  • srt 随被包装的命令一起退出,不会等待写入方关闭描述符。输入结束也不是错误:命令会在最后应用的配置下继续运行。
  • 给 srt 一个专用的、只读的端。srt 会把管道或套接字置于非阻塞模式,而该标志存在于打开的文件描述上,因此任何其他持有同一描述的东西——shell 的 exec 3<fifo、父进程继续使用的描述符的 pass_fds——从此以后它自己的阻塞读取都会得到 EAGAIN。
  • 在 macOS 和 Linux 上,沙箱化的命令不会获得该描述符:srt 会把那个槽位指向 /dev/null 供命令使用,因此沙箱内的任何东西都无法读取更新或写入自己的配置。

作为库使用

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()
})

违规归因(commandId / commandText)。 在包装命令运行期间观察到的违规(seatbelt 日志行、seccomp 事件、代理拒绝)会存储在一个归因键下,而 annotateStderrWithSandboxFailures(key, stderr) / getViolationsForCommand(key) 会通过同一个键来查找它们。默认情况下,该键就是被包装的字符串本身。传入一个不透明的每次调用 commandId(例如工具使用 id)来改为以它作为键——推荐这样做:键会比较其前 100 个字符,因此共享前缀的长命令否则会交叉归因,并且同一文本的重新运行会继承先前运行的事件。如果你_执行_的字符串不是该调用_所代表_的命令(例如你包装了一个组装而成的 source <snapshot> && eval '<cmd>'),还要传入 commandText: '<cmd>':它是 ignoreViolations 命令模式所匹配的对象,也是每个违规报告为其 command 的内容。你传给 wrapWithSandbox 的 commandId 必须与你随后传给 annotateStderrWithSandboxFailures / getViolationsForCommand 的是同一个非空字符串;空字符串会被视为完全没有 commandId,因此键就是该命令。

只有键会被截断到 100 个字符。自 v0.0.76 起,所报告的 command——以及 ignoreViolations 命令模式所匹配的文本——对于未带 commandId 包装的调用而言是整个命令,而不是其前 100 个字符;因此一个模式只能比以前抑制得更多,绝不会更少。一个本进程的任何调用都未注册的归因键(这些载体可从沙箱内部写入)会被以净化后的形式报告,并截断到相同的键长度。

分类