Anthropic Sandbox Runtime (srt)
一个轻量级的沙箱工具,可在操作系统级别对任意进程强制执行文件系统和网络限制,而无需使用容器。
srt 使用原生操作系统沙箱原语(macOS 上的 sandbox-exec,Linux 上的 bubblewrap)和基于代理的网络过滤。它可用于沙箱化代理、本地 MCP 服务器、bash 命令和任意进程的行为。
Beta 研究预览
沙箱运行时是为 Claude Code 开发的研究预览,旨在实现更安全的 AI 代理。它作为早期开源预览提供给更广泛的生态系统,以帮助构建更安全的代理系统。由于这是一个早期研究预览,API 和配置格式可能会演变。我们欢迎反馈和贡献,以使 AI 代理默认更安全!
安装
npm install -g @anthropic-ai/sandbox-runtime
基本用法
# 网络限制
$ srt "curl anthropic.com"
Running: curl anthropic.com
<html>...</html> # 请求成功
$ srt "curl example.com"
Running: curl example.com
Connection blocked by network allowlist # 请求被阻止
# 文件系统限制
$ srt "cat README.md"
Running: cat README.md
# Anthropic Sandb... # 当前目录访问允许
$ srt "cat ~/.ssh/id_rsa"
Running: cat ~/.ssh/id_rsa
cat: /Users/ollie/.ssh/id_rsa: Operation not permitted # 特定文件被阻止
概述
此包提供了一个独立的沙箱实现,既可用作 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 服务器将无法写入被阻止的路径:
> 写入文件到 ~/sensitive-folder
✗ Error: EPERM: operation not permitted, open '/Users/ollie/sensitive-folder/test.txt'
工作原理
沙箱使用操作系统级别的原语来强制执行适用于整个进程树的限制:
- macOS:使用
sandbox-exec并动态生成 Seatbelt profiles - Linux:使用 bubblewrap 进行容器化,并使用网络命名空间隔离
双重隔离模型
文件系统和网络隔离都是有效沙箱化的必要条件。没有文件隔离,受感染的进程可能会窃取 SSH 密钥或其他敏感文件。没有网络隔离,进程可能会逃逸沙箱并获得无限制的网络访问。
文件系统隔离 强制执行读取和写入限制:
- 读取(拒绝-然后-允许模式):默认情况下,读取访问允许 everywhere。您可以拒绝广泛区域(例如,
/Users),然后重新允许其中特定的路径(例如,.)。allowRead优先于denyRead——与写入相反,denyWrite优先于allowWrite。 - 写入(仅允许模式):默认情况下,写入访问 everywhere 被拒绝。您必须明确允许路径(例如,
.,/tmp)。空允许列表意味着没有写入访问。
网络隔离(仅允许模式):默认情况下,所有网络访问都被拒绝。您必须明确允许域名。空 allowedDomains 列表意味着没有网络访问。网络流量通过主机上运行的代理服务器路由:
- Linux:请求通过文件系统通过 Unix 域套接字路由。沙箱化进程的网络命名空间被完全移除,因此所有网络流量都必须通过主机上运行的代理(这些代理监听绑定到沙箱的 Unix 套接字)
- macOS:Seatbelt profile 仅允许与特定 localhost 端口通信。代理在该端口上监听,为所有网络访问创建受控通道
这些代理通过这些代理调解 HTTP/HTTPS(通过 HTTP 代理)和其他 TCP 流量(通过 SOCKS5 代理),并执行您的域名允许列表和拒绝列表。
有关 Claude Code 中沙箱化的更多详细信息,请参阅:
架构
src/
├── index.ts # 库导出
├── cli.ts # CLI 入口(srt 命令)
├── utils/ # 共享工具
│ ├── debug.ts # 调试日志
│ ├── settings.ts # 设置读取器(权限 + 沙箱配置)
│ ├── platform.ts # 平台检测
│ └── exec.ts # 命令执行工具
└── sandbox/ # 沙箱实现
├── sandbox-manager.ts # 主要沙箱管理器
├── sandbox-schemas.ts # 用于验证的 Zod 模式
├── sandbox-violation-store.ts # 违规跟踪
├── sandbox-utils.ts # 共享沙箱工具
├── http-proxy.ts # 用于网络过滤的 HTTP/HTTPS 代理
├── socks-proxy.ts # 用于网络过滤的 SOCKS5 代理
├── linux-sandbox-utils.ts # Linux bubblewrap 沙箱化
└── macos-sandbox-utils.ts # macOS sandbox-exec 沙箱化
用法
作为 CLI 工具
srt 命令(Anthropic 沙箱运行时)将任何命令包装在安全边界中:
# 在沙箱中运行命令
srt echo "hello world"
# 带有调试日志
srt --debug curl https://example.com
# 指定自定义设置文件
srt --settings /path/to/srt-settings.json npm install
作为库
import {
SandboxManager,
type SandboxRuntimeConfig,
} from '@anthropic-ai/sandbox-runtime'
import { spawn } from 'child_process'
// 定义您的沙箱配置
const config: SandboxRuntimeConfig = {
network: {
allowedDomains: ['example.com', 'api.github.com'],
deniedDomains: [],
},
filesystem: {
denyRead: ['~/.ssh'],
allowWrite: ['.', '/tmp'],
denyWrite: ['.env'],
},
}
// 初始化沙箱(启动代理服务器等)
await SandboxManager.initialize(config)
// 使用沙箱限制包装命令
const sandboxedCommand = await SandboxManager.wrapWithSandbox(
'curl https://example.com',
)
// 执行沙箱化命令
const child = spawn(sandboxedCommand, { shell: true, stdio: 'inherit' })
// 处理退出和清理子进程完成后的情况
child.on('exit', async code => {
console.log(`Command exited with code ${code}`)
// 完成后清理(可选,进程退出时自动发生)
await SandboxManager.reset()
})
可用导出
// 主要沙箱管理器
export { SandboxManager } from '@anthropic-ai/sandbox-runtime'
// 违规跟踪
export { SandboxViolationStore } from '@anthropic-ai/sandbox-runtime'
// TypeScript 类型
export type {
SandboxRuntimeConfig,
NetworkConfig,
FilesystemConfig,
IgnoreViolationsConfig,
SandboxAskCallback,
FsReadRestrictionConfig,
FsWriteRestrictionConfig,
NetworkRestrictionConfig,
} from '@anthropic-ai/sandbox-runtime'
配置
设置文件位置
默认情况下,沙箱运行时在 ~/.srt-settings.json 中查找配置。您可以使用 --settings 标志指定自定义路径:
srt --settings /path/to/srt-settings.json <command>
完整配置示例
{
"network": {
"allowedDomains": [
"github.com",
"*.github.com",
"lfs.github.com",
"api.github.com"
],
"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
}
配置选项
网络配置
使用 仅允许模式 - 默认情况下所有网络访问都被拒绝。
network.allowedDomains- 允许的域名数组(支持通配符,如*.example.com)。空数组 = 没有网络访问。network.deniedDomains- 拒绝的域名数组(首先检查,优先于allowedDomains)network.allowLocalBinding- 允许绑定到本地端口(布尔值,默认:false)
Unix 套接字设置(平台特定行为):
| 设置 | macOS | Linux |
|---|---|---|
allowUnixSockets: string[] | 允许的套接字路径列表 | 忽略(seccomp 无法按路径过滤) |
allowAllUnixSockets: boolean | 允许所有套接字 | 禁用 seccomp 阻止 |
Unix 套接字在 两个平台 上默认都被阻止。
- macOS:使用
allowUnixSockets允许特定路径(例如,["/var/run/docker.sock"]),或allowAllUnixSockets: true允许所有。 - Linux:使用 seccomp 过滤器(仅 x64/arm64)。如果 seccomp 不可用,套接字将不受限制,并显示警告。使用
allowAllUnixSockets: true明确禁用阻止。
Unix 套接字在两个平台上默认都被阻止。
- macOS:使用
allowUnixSockets允许特定路径(例如,["/var/run/docker.sock"]),或allowAllUnixSockets: true允许所有。 - Linux:使用 seccomp 过滤器(仅 x64/arm64)。如果 seccomp 不可用,套接字将不受限制,并显示警告。使用
allowAllUnixSockets: true明确禁用阻止。
Linux 搜索深度:在 Linux 上,沙箱使用 ripgrep 扫描允许写入路径中的子目录中的危险文件。默认情况下,它搜索深度为 3 以提高性能。您可以配置此设置:
{
"mandatoryDenySearchDepth": 5,
"filesystem": {
"allowWrite": ["."]
}
}
- 默认:
3(搜索深度为 3) - 范围:
1到10 - 较高的值提供更多保护但更慢的性能
- CWD(深度 0)中的文件始终受到保护,无论此设置如何
路径语法 (macOS):
路径支持类似 .gitignore 语法的 git-style glob 模式:
*- 匹配任何字符(不包括/)(例如,*.ts匹配foo.ts但不匹配foo/bar.ts)**- 匹配任何字符(包括/)(例如,src/**/*.ts匹配src/中的所有.ts文件)?- 匹配任何单个字符(不包括/)(例如,file?.txt匹配file1.txt)[abc]- 匹配集合中的任何字符(例如,file[0-9].txt匹配file3.txt)
示例:
"allowWrite": ["src/"]- 允许写入整个src/目录"allowWrite": ["src/**/*.ts"]- 允许写入src/和子目录中的所有.ts文件"denyRead": ["~/.ssh"]- 拒绝读取 SSH 目录"denyRead": ["/Users"], "allowRead": ["."]- 拒绝读取/Users的所有内容,但重新允许当前目录"denyWrite": [".env"]- 拒绝写入.env文件(即使当前目录被允许)
路径语法 (Linux):
Linux 目前不支持 glob 匹配。 仅使用字面路径:
"allowWrite": ["src/"]- 允许写入src/目录"denyRead": ["/home/user/.ssh"]- 拒绝读取 SSH 目录"denyRead": ["/home"], "allowRead": ["."]- 拒绝读取/home的所有内容,但重新允许当前目录
所有平台:
- 路径可以是绝对路径(例如,
/home/user/.ssh)或相对于当前工作目录(例如,./src) ~扩展为用户的家目录
其他配置
ignoreViolations- 映射命令模式到应忽略违规的路径数组enableWeakerNestedSandbox- 在 Docker 环境中启用较弱沙箱模式(布尔值,默认:false)enableWeakerNetworkIsolation- 允许访问 macOS 沙箱中的com.apple.trustd.agent(布尔值,默认:false)。这是 Go 程序(gh,gcloud,terraform,kubectl等)在使用httpProxyPort与 MITM 代理和自定义 CA 时验证 TLS 证书时需要的。安全警告:启用此功能会通过 trustd 服务打开潜在的数据泄露向量。
常见配置配方
允许 GitHub 访问(所有必要的端点):
{
"network": {
"allowedDomains": [
"github.com",
"*.github.com",
"lfs.github.com",
"api.github.com"
],
"deniedDomains": []
},
"filesystem": {
"denyRead": [],
"allowWrite": ["."],
"denyWrite": []
}
}
限制到特定目录:
{
"network": {
"allowedDomains": [],
"deniedDomains": []
},
"filesystem": {
"denyRead": ["~/.ssh"],
"allowWrite": [".", "src/", "test/"],
"denyWrite": [".env", "secrets/"]
}
}
仅工作区文件系统访问(拒绝工作区外读取):
{
"network": {
"allowedDomains": [],
"deniedDomains": []
},
"filesystem": {
"denyRead": ["/Users"],
"allowRead": ["."],
"allowWrite": ["."],
"denyWrite": []
}
}
这会拒绝读取 /Users 下任何内容(或 Linux 上的 /home),然后重新允许当前工作目录。系统路径(/usr, /lib 等)仍然可读。
常见问题和提示
运行 Jest:使用 --no-watchman 标志以避免沙箱违规:
srt "jest --no-watchman"
Watchman 访问沙箱边界之外的文件,这会触发权限错误。禁用它允许 Jest 使用内置文件监视器运行。
平台支持
- macOS:使用
sandbox-exec并使用自定义配置文件(无需额外依赖) - Linux:使用
bubblewrap(bwrap)进行容器化 - Windows:尚未支持
平台特定依赖
Linux 需要:
bubblewrap- 容器运行时- Ubuntu/Debian:
apt-get install bubblewrap - Fedora:
dnf install bubblewrap - Arch:
pacman -S bubblewrap
- Ubuntu/Debian:
socat- 套接字中继,用于代理桥接- Ubuntu/Debian:
apt-get install socat - Fedora:
dnf install socat - Arch:
pacman -S socat
- Ubuntu/Debian:
ripgrep- 快速搜索工具,用于检测拒绝路径- Ubuntu/Debian:
apt-get install ripgrep - Fedora:
dnf install ripgrep - Arch:
pacman -S ripgrep
- Ubuntu/Debian:
可选 Linux 依赖(用于 seccomp 回退):
该包包含为 x86-64 和 arm 架构预生成的 seccomp BPF 过滤器。这些依赖仅在您处于无法提供预生成过滤器的不同架构时才需要:
gcc或clang- C 编译器libseccomp-dev- seccomp 库开发文件- Ubuntu/Debian:
apt-get install gcc libseccomp-dev - Fedora:
dnf install gcc libseccomp-devel - Arch:
pacman -S gcc libseccomp
- Ubuntu/Debian:
macOS 需要:
ripgrep- 快速搜索工具,用于检测拒绝路径- 通过 Homebrew 安装:
brew install ripgrep - 或从以下位置下载:https://github.com/BurntSushi/ripgrep/releases/releases
- 通过 Homebrew 安装:
开发
# 安装依赖
npm install
# 构建项目
npm run build
# 构建 seccomp 二进制文件(需要 Docker)
npm run build:seccomp
# 运行测试
npm test
# 运行集成测试
npm run test:integration
# 类型检查
npm run typecheck
# 代码格式化
npm run lint
# 格式化代码
npm run format
构建seccomp二进制文件
预生成的 BPF 过滤器包含在存储库中,但如有需要,您可以重新构建它们:
npm run build:seccomp
此脚本使用 Docker 跨编译 seccomp 二进制文件以支持多个架构:
- x64 (x86-64)
- arm64 (aarch64)
脚本构建静态生成器二进制文件,生成 BPF 过滤器(每个约 104 字节),并将它们存储在 vendor/seccomp/x64/ 和 vendor/seccomp/arm64/。生成器二进制文件被删除以保持包大小较小。
实现细节
网络隔离架构
沙箱在主机机器上运行 HTTP 和 SOCKS5 代理服务器,根据权限规则过滤所有网络请求:
- HTTP/HTTPS 流量:HTTP 代理服务器拦截请求并验证它们是否允许通过允许/拒绝的域名
- 其他网络流量:SOCKS5 代理处理所有其他 TCP 连接(SSH、数据库连接等)
- 权限执行:代理执行您的配置中的
permissions规则
平台特定代理通信:
-
Linux:请求通过文件系统通过 Unix 域套接字路由。沙箱化进程的网络命名空间被完全移除,因此所有网络流量都必须通过主机上运行的代理(这些代理监听绑定到沙箱的 Unix 套接字)
-
macOS:Seatbelt profile 仅允许与特定 localhost 端口通信。代理在该端口上监听,为所有网络访问创建受控通道
这些代理通过这些代理调解 HTTP/HTTPS(通过 HTTP 代理)和其他 TCP 流量(通过 SOCKS5 代理),并执行您的域名允许列表和拒绝列表。
文件系统隔离
文件系统限制在操作系统级别执行:
- macOS:使用
sandbox-exec并动态生成 Seatbelt profiles,指定允许的读取/写入路径 - Linux:使用 bubblewrap 进行容器化,并使用网络命名空间隔离
默认文件系统权限:
-
读取(拒绝-然后-允许):默认情况下允许 everywhere。您可以拒绝广泛区域(例如,
/Users),然后重新允许其中特定的路径(例如,.)。allowRead优先于denyRead——与写入相反,denyWrite优先于allowWrite。- 示例:
denyRead: ["~/.ssh"]以阻止访问 SSH 密钥 - 示例:
denyRead: ["/Users"], allowRead: ["."]以阻止/Users的所有内容,但重新允许工作区 - 空的
denyRead: []= 完全读取访问(没有拒绝)
- 示例:
-
写入(仅允许模式):默认情况下 everywhere 被拒绝。您必须明确允许路径(例如,
.,/tmp)。空允许列表意味着没有写入访问denyWrite在允许路径内创建例外(拒绝优先于允许)
读取和写入的优先级故意相反:allowRead 覆盖 denyRead,而 denyWrite 覆盖 allowWrite。这允许您在拒绝区域内雕刻可读取区域,并在可写入区域内雕刻受保护的区域。
Unix 套接字限制 (Linux)
在 Linux 上,沙箱使用 seccomp BPF (Berkeley Packet Filter) 在系统调用级别阻止 Unix 域套接字创建。这提供了额外的安全层,以防止进程创建新的 Unix 域套接字用于本地 IPC(除非明确允许)。
工作原理:
-
预生成的 BPF 过滤器:该包包含为不同架构(x64, ARM64)预编译的 BPF 过滤器。这些是 ~104 字节,存储在
vendor/seccomp/。过滤器是架构特定的但 libc 独立的,因此它们适用于 glibc 和 musl -
运行时检测:沙箱自动检测您的系统架构并加载适当的预生成 BPF 过滤器
-
系统调用过滤:BPF 过滤器拦截
socket()系统调用并返回EPERM以阻止创建AF_UNIX套接字。这可以防止沙箱化代码创建新的 Unix 域套接字 -
两阶段应用使用 apply-seccomp 二进制文件
- 外部 bwrap 创建具有文件系统、网络和 PID 命名空间限制的沙箱
- 网络桥接进程(socat)在沙箱内启动(需要 Unix 套接字)
- apply-seccomp 二进制文件通过
prctl()应用 seccomp 过滤器 - apply-seccomp 执行具有活动 seccomp 的用户命令
- 用户命令以所有沙箱限制运行
安全限制:过滤器仅阻止 socket(AF_UNIX, ...) 系统调用。它不会阻止从父进程继承的 Unix 套接字操作或通过 SCM_RIGHTS 传递的 Unix 套接字描述符。对于大多数沙箱化场景,阻止套接字创建就足够了以防止未经授权的 IPC
零运行时依赖:预构建的静态 apply-seccomp 二进制文件和预生成的 BPF 过滤器包含在 x64 和 arm64 架构中。运行时不需要编译工具或外部依赖
架构支持:x64 和 arm64 完全支持预构建的二进制文件。其他架构目前不受支持。要在不受支持的架构上使用沙箱化而无需 Unix 套接字阻止,请在配置中设置 allowAllUnixSockets: true
违规检测和监控
当沙箱化进程尝试访问受限资源时:
- 在操作系统级别阻止操作(返回
EPERM错误) - 记录违规(平台特定机制)
- 通知用户(在 Claude Code 中,这会触发权限提示)
macOS:沙箱运行时通过 macOS 的系统沙箱违规日志存储进行实时通知。这提供了有关尝试访问和为什么被阻止的详细信息。这是 Claude Code 使用的相同机制。
# 实时查看沙箱违规
log stream --predicate 'process == "sandbox-exec"' --style syslog
Linux:bubblewrap 不提供内置违规报告。使用 strace 跟踪系统调用以识别阻止的操作:
# 跟踪所有拒绝的操作
strace -f srt <your-command> 2>&1 | grep EPERM
# 跟踪特定文件操作
strace -f -e trace=open,openat,stat,access srt <your-command> 2>&1 | grep EPERM
# 跟踪网络操作
strace -f -e trace=network srt <your-command> 2>&1 | grep EPERM
高级:自带代理
对于更复杂的网络过滤,您可以配置沙箱使用您自己的代理而不是内置代理。这启用了:
- 流量检查:使用工具如 mitmproxy 检查和修改流量
- 自定义过滤逻辑:实现超出简单域名允许列表的复杂规则
- 审计日志:记录所有网络请求以进行合规性或调试
示例 mitmproxy:
# 启动 mitmproxy 带有自定义过滤脚本
mitmproxy -s custom_filter.py --listen-port 8888
注意:在新的配置格式中,不支持自定义代理配置。此功能将在未来的版本中添加。
重要安全注意事项:即使使用域名允许列表,也可能存在数据泄露向量。例如,允许 github.com 允许进程推送到任何仓库。使用自定义 MITM 代理和适当的证书设置,您可以检查和过滤特定的 API 调用以防止这种情况
安全限制
- 网络沙箱化限制:沙箱化系统通过限制进程可以访问的域名/域来工作。它不会检查通过代理传递的流量,用户有责任确保其策略中只允许受信任的域名
- 通过 Unix 套接字进行权限提升:
allowUnixSockets配置可能会无意中授予对强大系统服务的访问权限,可能导致沙箱绕过。例如,如果它用于允许访问/var/run/docker.sock,这将有效地授予对主机系统的访问权限,通过利用 docker 套接字。用户应仔细考虑任何允许通过沙箱的 Unix 套接字。 - 文件系统权限提升:过于宽泛的文件系统写入权限可能启用权限提升攻击。允许写入包含可执行文件的目录(如
$PATH)的系统配置目录或用户 shell 配置文件(.bashrc,.zshrc)可能导致在不同安全上下文中执行代码 - Linux 沙箱强度:Linux 实现提供强大的文件系统和网络隔离,但包括
enableWeakerNestedSandbox模式,该模式使它能够在 Docker 环境中工作而无需特权命名空间。此选项大大削弱了安全性,仅在您在其他地方强制执行其他隔离的情况下才应使用 - 较弱的网络隔离 (macOS):
enableWeakerNetworkIsolation选项重新启用对 macOS 沙箱中的com.apple.trustd.agent的访问。这是 Go 程序(gh,gcloud,terraform,kubectl等)在使用httpProxyPort与 MITM 代理和自定义 CA 时验证 TLS 证书时需要的。这会通过 trustd 服务打开潜在的数据泄露向量,因此仅在需要 Go TLS 验证时才应启用。安全警告:启用此功能会通过 trustd 服务打开潜在的数据泄露向量,因此只有在需要 Go TLS 验证时才应启用。
已知限制和未来工作
Linux 代理绕过:目前使用环境变量 (HTTP_PROXY, HTTPS_PROXY, ALL_PROXY) 将流量路由到代理。这适用于大多数应用程序,但可能被不尊重这些变量的程序忽略,导致它们无法连接到互联网。
未来改进:
-
Proxychains 支持:在 Linux 上添加对
proxychains的支持使用LD_PRELOAD在较低级别拦截网络调用,使绕过更困难 -
Linux 违规监控:实现基于
strace的自动违规检测,集成到违规存储中。目前,Linux 用户必须手动运行strace才能查看违规,而 macOS 则通过系统日志存储进行自动违规监控