在本文中,我们将讨论新近流行的开源 Anthropic sandbox-runtime(srt),它是 Claude Code 沙箱化 bash 工具背后的操作系统级沙箱。Anthropic sandbox-runtime 限制进程可以访问哪些文件以及可以连接哪些主机。它无需启动容器即可做到这一点。它也不绑定于 Claude Code。你自己的智能体、本地 MCP 服务器和普通命令行程序都可以在其中运行。

TL;DR

大小:npm 包 @anthropic-ai/sandbox-runtime v0.0.81,解包后约 11.4 MB,Apache-2.0 许可,需要 Node.js 22.12+。

运行环境:任何 macOS 或 Linux 开发机或 CI 机器。macOS 使用 Seatbelt;Linux 需要 bubblewrap、socat 和 ripgrep。Windows 为 alpha 阶段。

性能:在 Anthropic 内部使用中,沙箱化使 Claude Code 的权限提示减少了 84%(自报数据)。

最佳之处:权限提示减少 84%,同时对整个进程树强制执行文件和网络限制。

最差之处:仍是 beta 研究预览版,Windows 支持为 alpha 阶段。

什么是 Anthropic sandbox-runtime?

Anthropic sandbox-runtime 是一个开源工具,可将任意进程包裹在文件系统和网络限制之中。通过 npm install -g @anthropic-ai/sandbox-runtime 安装,然后在命令前加上 srt 即可使用。它既可作为 CLI 使用,也可作为 TypeScript 库使用。

sandbox-runtime 在 macOS、Linux 和 Windows 上如何工作?

srt 使用各操作系统自身的隔离原语。其限制覆盖整个进程树,包括脚本和子进程。

macOS:使用 sandbox-exec 和动态生成的 Seatbelt 配置文件。仅需 ripgrep。

Linux:使用移除了网络命名空间的 bubblewrap。还需要 socat 和 ripgrep。

Windows(alpha):使用专用的 srt-sandbox 账户、Windows Filtering Platform 出站防护栏和显式文件 ACL。

流量仅通过运行在宿主机上的 HTTP 和 SOCKS5 代理离开。在 Linux 上,这些代理位于绑定挂载到沙箱中的 Unix 套接字之后。在 macOS 上,Seatbelt 配置文件仅允许一个 localhost 端口。随后由代理应用你的域名允许列表和拒绝列表。

为什么它同时需要文件系统和网络隔离?

Anthropic 团队认为,只有其中一道边界而缺少另一道就会失效。没有网络隔离,被提示注入的智能体可能窃取 SSH 密钥。没有文件系统隔离,它可能逃出沙箱并获得网络访问权限。

srt 的默认设置遵循这一逻辑。除非被拒绝,否则任何位置都允许读取。除非被允许,否则任何位置都禁止写入。除非域名被加入允许列表,否则禁止网络访问。

如何为 MCP 服务器或你自己的智能体设置沙箱?

对于 MCP 服务器,将 .mcp.json 中的命令从 npx 改为 srt。把原始命令作为参数传入。规则随后存放在 ~/.srt-settings.json 中:

复制代码已复制使用其他浏览器

{

"network": { "allowedDomains": ["api.github.com", "*.npmjs.org"], "deniedDomains": [] },

"filesystem": { "denyRead": ["~/.ssh"], "allowWrite": ["."], "denyWrite": [".env"] }

}

对于你自己的智能体,该库提供 SandboxManager。调用 initialize(config) 启动代理。然后 wrapWithSandbox() 返回一个包装后的命令字符串,你可以用它来启动进程。

84% 这个数字意味着什么?

Anthropic 报告称,在内部 Claude Code 使用中,沙箱将权限提示减少了 84%。这是自报数字,并非外部基准测试。目标是缓解审批疲劳。整天点击“批准”的开发者会不再阅读他们批准的内容。固定的边界让智能体可以在其中自由工作,只在边界处才请求批准。

返回</button>

<button class="btn pri" id="fnext">下一步 </button>

<button class="btn" id="fplay">自动播放</button>

</div>

</div>

<div class="pane" id="p-sim">

<div class="sim">

<div>

<div class="card">

<h5>network.allowedDomains</h5>

<label class="chk"><input type="checkbox" id="d-anth" checked> anthropic.com</label>

<label class="chk"><input type="checkbox" id="d-npm"> *.npmjs.org</label>

<label class="chk"><input type="checkbox" id="d-gh"> github.com</label>

<h5 style="margin-top:12px">filesystem</h5>

<label class="chk"><input type="checkbox" id="f-ssh" checked> denyRead: ~/.ssh</label>

<label class="chk"><input type="checkbox" id="f-env" checked> denyWrite: .env</label>

</div>

</div>

<div>

<div class="cmds" id="cmds">

<button class="cmd" data-c="0">srt "cat README.md"</button>

<button class="cmd" data-c="1">srt "cat ~/.ssh/id_rsa"</button>

<button class="cmd" data-c="2">srt "curl anthropic.com"</button>

<button class="cmd" data-c="3">srt "curl example.com"</button>

<button class="cmd" data-c="4">srt "npm install"</button>

<button class="cmd" data-c="5">srt "echo KEY=1 >> .env"</button>

</div>

<div class="term" id="term" style="margin-top:10px"><span class="dim">选择一条命令。切换配置,看看会有什么变化。</span></div>

<div class="why" id="why"></div>

</div>

</div>

</div>

<div class="pane" id="p-plat">

<div class="plat">

<div class="pc on" data-p="0"><h4>macOS</h4><span class="tag t-g">支持</span><ul><li>sandbox-exec</li><li>Seatbelt 配置文件</li><li>需要 ripgrep</li></ul></div>

<div class="pc" data-p="1"><h4>Linux</h4><span class="tag t-g">支持</span><ul><li>bubblewrap</li><li>无网络命名空间</li><li>socat + ripgrep</li></ul></div>

<div class="pc" data-p="2"><h4>Windows</h4><span class="tag t-o">Alpha</span><ul><li>srt-sandbox 账户</li><li>WFP 出站围栏</li><li>一次性安装</li></ul></div>

</div>

<div class="desc pdetail" id="pdesc"></div>

</div>

<div class="pane" id="p-defs">

<div class="defs">

<div class="dc"><div class="kicker">读取</div><div class="big" style="color:#b5cc94">允许</div><p>默认在所有位置允许。拒绝 ~/.ssh 等区域,可通过 allowRead 重新允许。</p></div>

<div class="dc"><div class="kicker">写入</div><div class="big" style="color:#ef7a73">拒绝</div><p>默认在所有位置拒绝。通过 allowWrite 开放 "." 和 /tmp 等路径。</p></div>

<div class="dc"><div class="kicker">网络</div><div class="big" style="color:#ef7a73">拒绝</div><p>默认无访问权限。每个主机都必须匹配 allowedDomains。</p></div>

</div>

<div class="bars" id="bars">

<div class="kicker" style="margin-bottom:4px">Claude Code 权限提示(已索引)</div>

<div class="bar"><div class="lb"><span>未使用沙箱</span><span>100</span></div><div class="bg"><div class="fg" data-w="100" style="background:var(--muted)"></div></div></div>

<div class="bar"><div class="lb"><span>使用沙箱</span><span>16</span></div><div class="bg"><div class="fg" data-w="16" style="background:var(--orange)"></div></div></div>

<div class="note">Anthropic 内部使用中提示词减少 84%(自报数据,2025 年 10 月工程博客)。以 100 为基准索引。</div>

</div>

</div>

<div class="pane" id="p-cmp">

<div class="tblwrap">

<table>

<thead><tr><th></th><th>srt</th><th>Codex CLI</th><th>Docker Sandboxes</th><th>E2B</th></tr></thead>

<tbody>

<tr class="row"><td>隔离方式</td><td class="hl">操作系统原语</td><td>操作系统原语</td><td>microVM</td><td>Firecracker microVM</td></tr>

<tr class="row"><td>运行位置</td><td class="hl">本地</td><td>本地</td><td>本地</td><td>云端 / BYOC</td></tr>

<tr class="row"><td>容器或虚拟机</td><td class="hl">否</td><td>否</td><td>是</td><td>是</td></tr>

<tr class="row"><td>网络默认策略</td><td class="hl">全部拒绝</td><td>关闭(可切换)</td><td>选定策略</td><td>开启</td></tr>

<tr class="row"><td>域名允许列表</td><td class="hl">通配符 + 端口</td><td>未披露</td><td>通配符 + 端口</td><td>allowOut,通配符</td></tr>

<tr class="row"><td>许可证</td><td class="hl">Apache-2.0</td><td>Apache-2.0</td><td>未披露</td><td>Apache-2.0(SDK)</td></tr>

</tbody>

</table>

</div>

</div>

<div class="ft"><span>来源:github.com/anthropics/sandbox-runtime · anthropic.com/engineering · v0.0.81</span><span class="mtp">由 Marktechpost 构建</span></div>

</div>

<script>

(function(){

var R=document.getElementById('srt-x');

function post(){try{parent.postMessage({srtH:R.offsetHeight+40},'*')}catch(e){}}

var tabs=R.querySelectorAll('.tab');

tabs.forEach(function(b){b.addEventListener('click',function(){

tabs.forEach(function(x){x.classList.remove('on')});b.classList.add('on');

R.querySelectorAll('.pane').forEach(function(p){p.classList.remove('on')});

var t=b.getAttribute('data-t');document.getElementById('p-'+t).classList.add('on');

if(t==='defs')bars();if(t==='cmp')rows();setTimeout(post,60);

})});

// flow

var steps=[

['你的智能体运行一条命令','智能体、MCP 服务器或 CLI 工具发出命令。命令本身不变;srt 只是将其包装起来。',0,'act'],

['srt 构建策略','srt 加载 ~/.srt-settings.json(或内置默认值),并在主机上启动 HTTP 和 SOCKS5 代理。',1,'act'],

操作系统强制执行边界

Seatbelt(macOS)、bubblewrap(Linux)或 WFP 围栏(Windows alpha)将文件规则应用于整个进程树。

act

所有流量都经过代理

沙箱没有直接对外路由。在 Linux 上,网络命名空间被移除;代理通过 Unix 套接字访问。

act

允许的主机:连接继续

allowedDomains 中的主机会通过,前提是经过检查确认它不会解析到回环或云元数据 IP。

ok

未知主机:阻止或询问

被拒绝或未列出的主机会被拒绝,或由 ask 回调决定。违规行为会被记录,供智能体读取。

bad

];

var fi=0,timer=null;

function draw(){

var s=steps[fi];var ns=R.querySelectorAll('.node');

ns.forEach(function(n,i){n.classList.remove('act','ok','bad');if(i<s[2])n.classList.add('act')});

ns[s[2]].classList.add(s[3]);

var pk=document.getElementById('pkt');pk.style.left=(s[2]*22)+'%';

pk.style.background=s[3]==='ok'?'#788c5d':s[3]==='bad'?'#d4504a':'#d97757';

document.getElementById('fdesc').innerHTML='<h4>Step '+(fi+1)+' of '+steps.length+': '+s[0]+'</h4>'+s[1];

}

document.getElementById('fnext').onclick=function(){fi=(fi+1)%steps.length;draw()};

document.getElementById('fprev').onclick=function(){fi=(fi-1+steps.length)%steps.length;draw()};

document.getElementById('fplay').onclick=function(){

if(timer){clearInterval(timer);timer=null;this.textContent='Auto-play';return}

this.textContent='Pause';timer=setInterval(function(){fi=(fi+1)%steps.length;draw()},1800);

function(){return [0,'Connection blocked by network allowlist','example.com is not allowlisted.']},

function(){return on('d-npm')?[1,'packages installed (illustrative output)','*.npmjs.org is allowlisted, so the registry is reachable.']:[0,'npm ERR! network request to registry.npmjs.org failed\nConnection blocked by network allowlist','The classic trade-off: too strict, and installs fail.']},

function(){return on('f-env')?[0,'bash: .env: Operation not permitted','denyWrite beats allowWrite, so .env stays protected inside the project.']:[1,'(written)','"." is in allowWrite, so the write succeeds.']}

];

var busy=false;

R.querySelectorAll('.cmd').forEach(function(b){b.addEventListener('click',function(){

if(busy)return;busy=true;var r=C[+b.getAttribute('data-c')]();var t=document.getElementById('term');

t.innerHTML='<span class="p">$</span> '+b.textContent.replace(/</g,'<')+'\n<span class="dim">Running inside sandbox...</span>';

document.getElementById('why').textContent='';

setTimeout(function(){

t.innerHTML='<span class="p">$</span> '+b.textContent.replace(/</g,'<')+'\n<span class="'+(r[0]?'ok':'no')+'">'+(r[0]?'✓ ':'✗ ')+r[1].replace(/</g,'<')+'</span>';

document.getElementById('why').textContent=r[2];busy=false;post();

},650);

})});

// platforms

var P=['macOS uses the built-in sandbox-exec tool with Seatbelt profiles generated per run. The profile allows only 1 localhost port, where the srt proxies listen. Violations can be read from the system log in real time.',

'Linux uses bubblewrap and removes the network namespace entirely. Proxies are reached through Unix sockets bind-mounted into the sandbox. Ubuntu 24.04+ needs an AppArmor change for user namespaces.',

'Windows (alpha) runs commands as a dedicated srt-sandbox account. A machine-wide WFP filter blocks its outbound traffic except to the proxy ports. Setup needs 1 elevated install.'];

var pcs=R.querySelectorAll('.pc');

function pd(i){pcs.forEach(function(x){x.classList.remove('on')});pcs[i].classList.add('on');document.getElementById('pdesc').innerHTML='<h4>'+pcs[i].querySelector('h4').textContent+'</h4>'+P[i];post()}

pcs.forEach(function(c,i){c.addEventListener('click',function(){pd(i)})});pd(0);

function bars(){R.querySelectorAll('.fg').forEach(function(f){f.style.width='0';setTimeout(function(){f.style.width=f.getAttribute('data-w')+'%'},80)})}

function rows(){R.querySelectorAll('tr.row').forEach(function(r,i){r.classList.remove('in');setTimeout(function(){r.classList.add('in')},90*i+60)})}

window.addEventListener('load',post);window.addEventListener('resize',post);setTimeout(post,300);

})();

</script>

</body>

</html>

">

真正的权衡:严格的允许列表 vs 可用的智能体

编码智能体做的远不止编辑文件。它们会安装依赖、拉取文档并调用 API。允许列表设得太严,npm install 就会失败。设得太松,沙箱就几乎起不到保护作用。srt 提供了几个可调项,用来把握这中间的平衡:

通配符与端口:诸如 *.npmjs.org 或 api.example.com:443 这样的条目。

询问回调:决定没有规则覆盖的主机,并可返回一个模型能读取的理由。

按命令的允许列表:只为一次调用开放某个注册表。

实时更新:--control-fd 可在命令运行期间替换网络列表。

解析地址检查:阻止解析到回环地址或云元数据 IP 的已允许域名。

被拒域名的理由:告知智能体可用的替代方案,例如 HTTPS git remote。

它与其他智能体沙箱相比如何?

功能Anthropic sandbox-runtimeOpenAI Codex CLI sandboxDocker SandboxesE2B隔离方式操作系统原语:Seatbelt、bubblewrap、Windows 账户 + WFP操作系统原语:Seatbelt、bubblewrap、原生 Windows 沙箱每个沙箱一个 microVM每个会话一个 Firecracker microVM运行位置本地机器本地机器本地机器云端或 BYOC(AWS、GCP)是否需要容器或 VM否否是(microVM)是(托管 microVM)能否在其自身智能体之外使用可以,CLI + 库可作用于任意进程内置于 Codex可以,面向编码智能体的 sbx CLI可以,JS 和 Python SDK网络默认全部拒绝;代理允许列表在 workspace-write 下关闭;可通过配置开关首次启动时选择策略(如全部拒绝、均衡)默认开启;可禁用域名允许列表可以,支持通配符 + 端口未披露(文档仅说明开/关切换)可以,支持通配符 + 端口可以,allowOut 支持通配符(基于 SNI/Host)许可证Apache-2.0Apache-2.0未披露Apache-2.0(SDK)状态Beta 研究预览;Windows 为 alpha随 Codex CLI 发布已发布产品已发布产品

要点总结

srt 在操作系统层面为任意进程提供沙箱,无需容器。

macOS 上使用 Seatbelt,Linux 上使用 bubblewrap,Windows 支持处于 alpha 阶段。

网络默认拒绝;每个连接都要经过主机侧的允许列表代理。

Anthropic 报告 Claude Code 的权限提示减少了 84%(内部数据)。

允许列表的宽窄才是真正的安全调节旋钮;宽泛的域名可能导致数据泄露。

查看 GitHub 仓库、Anthropic 工程博客以及 Claude Code 沙箱文档。所有功劳归于该项目的研究者。另外,欢迎在 Twitter 上关注我们,别忘了加入我们 150k+ 的 ML SubReddit 并订阅我们的 Newsletter。等等!你在 Telegram 上吗?现在你也可以在 Telegram 上加入我们。

需要与我们合作推广你的 GitHub 仓库、Hugging Face 页面、产品发布或网络研讨会等?联系我们

文章《Meet Anthropic’s sandbox-runtime: OS-Level Sandboxing for AI Agents, No Containers》首发于 MarkTechPost。