返回所有文章
发布于 · 作者 Renaud Deraison

关掉沙箱的开关就在沙箱里

9 月 8 日公布的 CVE-2026-82533 是 DeepSeek Harness 上的 9.4 分:被关在沙箱里的编码代理,能用一条 shell 命令关掉自己的沙箱。这套 harness 在限制文件写入的操作系统沙箱里执行代理的命令,同时把控制平面当作 HTTP 接口暴露在回环地址上,而沙箱从来没有覆盖那里。守着那个接口的检查只读调用方自己送来的 Host 标头,从不看连接究竟从哪里来。在 Bromure Agentic Coding 里,代理在 VM 内部本来就不受限制,而它要去调用的控制平面,在它那一侧根本不存在。

这一次完全用不上漏洞利用。被关住的代理对一个本机端口发出一条 shell 命令,请那个关着 它的沙箱把自己关掉,而沙箱同意了。

DeepSeek Harness 把编码代理的命令放在操作系统的沙箱里执行。这个沙箱窄而刻意:文件写 入只留在工作区和临时文件夹里,代理做的其他一切都是别人的问题。项目自己的命令行参考 文档就是这么写的。在默认设置下,“读取和网络访问不受限制”。

这套 harness 还有一个网页接口。它跑在同一台机器上、跑在一个本机 HTTP 端口上,而 harness 把它的地址交给代理的 shell,好让工具能跟它说话。那个接口就是控制平面:它握着 一次会话的模式,包括那个叫作 danger-full-access 的模式,它会关掉沙箱、停掉审批提 示。

这两个设计都很平常。把它们并排放在一起,代理就能用一条命令关掉自己的沙箱,因为沙箱 从来没有覆盖回环地址,而控制平面从来没有检查是谁在调用。

是 OX 的研究人员找到的。VulnCheck 在 9 月 8 日以 CVE-2026-82533 公布,CVSS 9.4。它在默认安装上就成立,不需要网络暴露、也不需要任何凭据,直到 DeepSeek 在 8 月 27 日推出修复为止。

读信封的那道检查

那个接口完全没有身份验证。顶替它位置的是一个叫 isTrustedApiRequest 的函数, DevOps.com 引述了它做的事: 它“读取 Host 请求标头,若该值是回环地址的授权主体,或出现在配置好的 trustedHosts 列表里,就放行”。

Host 标头是客户端自己写的一行文本。它说的是客户端认为自己正在跟哪个地址说话,而网 络上任何位置的调用方都能在里面打上 localhost。连接真正的来源在下一层,在 TCP 的对 端地址里,而 DeepSeek 的检查从来没读过那个值。CVE 记录把这个缺陷归在 CWE-345Reliance on Untrusted Inputs in a Security Decision

坐在一个允许网络调用的沙箱里的代理,对那个接口发了一次调用,把自己的会话设成 danger-full-access,审批设成 never。用 The Hacker News 的说法, 这次模式变更“不需要明确审批,因为它修改的是会话设置,而不是请求新的权限”。

审批系统照设计运作。代理从来没有请求去做危险的事;它请求改一个设置,而那个设置管的 正是危险的事会不会被拿出来问。权限闸门检视的是摆在它面前的那个操作。这次请求是一次 配置写入,而配置写入不在它的清单上。

一台机器、一个进程,两个从未碰面的决定OS 沙箱限制了什么编码代理的 shell 命令写入 → 只限 workspace + temp由操作系统强制,而且它守住了按设计就在范围之外读取:不受限制网络:不受限制,含 loopbackPOST http://127.0.0.1:…Host: localhost控制平面:本机 HTTP,无验证isTrustedApiRequest(req)• 读调用方的 Host 标头• loopback 或 trustedHosts 就放行• 从不读 TCP 对端地址产生的会话状态mode = danger-full-accessapproval = never一次设置写入,所以什么都不问
整段逃脱。操作系统的沙箱把文件写入限制在工作区和临时文件夹;读取和网络调用,包括回环地址在内,按设计就在它的范围之外。harness 的控制平面在一个本机 HTTP 端口上听着,那个地址代理的 shell 早就知道。它的信任检查读的是调用方自己的 Host 标头,从不检视 TCP 的对端地址,所以来自沙箱内进程的请求,看起来就跟开发者发出的一模一样。接着代理把会话模式写成 danger-full-access,审批设置写成 never。那是一次设置写入,不是权限请求,所以什么都不会弹出来问。

同一扇门,换个方向

一个信任调用方所送标头的接口,并不在乎连接是从哪个方向来的。如果那个端口在网络上够 得着,同一次调用从机器外面也一样成立:一个没有身份验证的陌生人可以接管代理,把所有 存下来的对话全部导出,不需要 API 密钥,也不必为一次模型调用花掉任何一个 token。这就 是 CVSS 4.0 向量以 AV:N 开头的原因,也是这个数字是 9.4,而不是某个本地而温和的分数 的原因。

时间线上有个值得记住的细节。两位开发者在 8 月 13 日和 14 日,各凭自己的判断,把这个发 现贴到 DeepSeek 的 GitHub 讨论区上,那是在 OX 于 8 月 24 日确认之前,也在 CVE 存在之 前。这个仓库在 9 月 9 日有超过 216,000 颗星,却没有一份说明如何私下报告漏洞的安全策略 文件,所以唯一还能放的地方就是一串公开讨论。修复来的时候,是身份验证:这个工具现在 会在启动地址上打印出一次性的令牌,浏览器拿那个令牌去换一份签名过的 cookie,而对接口 的每一次调用都要带着那份 cookie。

如果你在跑这套 harness,去查你机器上的版本,而不是项目发布的版本。第三方的桌面外壳会 自己带一份。0.1.2-alpha.1 在 8 月 27 日只出现在 GitHub 上,8 月 30 日的 0.1.2-alpha.2 才是第一个带着修复的 npm 版本,而某个 Windows 外壳一直停在 0.1.1-rc.2,直到 9 月 6 日才换到打过补丁的构建。

你的 harness 也长了一个

你可以把这件事归档成某个项目的缺陷,然后往前走。但这个形状会旅行,因为代理的 harness 正在长出一个个本机控制平面:给仪表板用的状态服务器、IDE 桥接、MCP 端点、一个在 localhost 上把差异画出来的页面。每一个都是你机器上的一个小小 HTTP 服务,而你的代理跑 的代码全部够得着,因为代理就跑在那台机器上,而 localhost 的意思正是“那台机器”。

一旦控制平面坐到了它所控制的那个东西旁边,决定结局的就只剩一个问题:被关住的一方, 能不能寻址到关住它的那套设置?DeepSeek 的答案是能,靠的是一道对调用方一面之词照单全 收的检查。就算换上更强的检查,它回答的仍然是一个本来就不该问得出口的问题。身份验证 函数是代码,代码有兜底分支,而今年是一场漫长的游行,安全决策一个接一个地败在没人走 过的那条分支上。

在 Bromure 工作区里,开关住在哪里

Bromure Agentic Coding 从另一端开始。Bromure 的工作区让代理不受限制。

在客户机里面,代理早就拥有 DeepSeek Harness 会称为 danger-full-access 的东西。那是设 计上的静止状态。手册也是这么写的:一个被提示注入或以其他方式乱来的代理“可以在客户机 内部为所欲为,但它读不到真正的 API 密钥、无法用真正的 AWS 密钥签名、也取不出 SSH 私 钥——这些东西在它那一侧都不存在”。代理可以写进文件系统的任何地方、执行任何它想执行 的东西、绑定任何端口,所以它没有任何可以再往上爬的模式了。边界是一道 hypervisor 的边 缘,而代理在那道边缘的另一侧。

因此客户机根本没有控制平面的地址。工作区的策略(护栏、凭据、防火墙规则、MCP 服务器) 住在你 Mac 上 ~/Library/Application Support/BromureAC/profiles/ 底下的一个 profile.json 里,而你在 Edit workspace 窗口里修改它。客户机没有通往那个文件的文件系 统路径,也没有通往读它的那个进程的网络路径。

两侧通过 virtio socket 说话,那是跑在 VM 网络之外的主机对客户机点对点桥接。一台工作区 VM 有八条,每条都有自己的差事:8443 把客户机的 HTTPS 送到主机的代理服务器,8444 是 ssh-agent 桥接,8445 喂给 AWS 凭据辅助程序,5800 承载终端和文件路径,5010 转发 OAuth 回调。每一条只服务一个固定协议,没有一条收 Host 标头,所以调用方根本没有一份 trustedHosts 列表可以靠嘴巴混进去。在 vsock 上,身份就是拓扑:字节是从哪一条桥进来 的。那不是你能在请求里打出来的东西。

harness:沙箱与它的设置,同一台机器沙箱里的代理写入受限网络不受限制知道接口的地址回环 HTTP守着的是调用方写的标头控制平面会话模式审批设置离它所管的东西只有一次请求Bromure 工作区:里面全给,策略在另一侧工作区 VM代理在这里有完整访问权到处写 · 什么都跑 · 绑任何端口没有可以再爬的模式它开的本机控制平面听在这台 VM 的回环地址上这一侧没有真的凭据hypervisorvsock 8443只有 HTTPS没有控制路径macOS 主机每工作区代理服务器:线上的边界护栏 · 出口防火墙 · 换上假凭据:80 与 :443 由虚拟交换机转走客户机无从解除策略存放的地方~/Library/Application Support/BromureAC/…同意对话框画在这里,用 AppKit
同一个开关的两种摆法。上:harness 的沙箱与管着它的控制平面跑在同一台机器上,所以代理通过回环地址就够到了设置,而挡在中间的只有一道对代理自己所写标头的检查。下:Bromure 的工作区在客户机内部把一切都交给代理,并把策略放到 hypervisor 的另一侧。虚拟交换机把客户机对外的 HTTPS 转进主机的代理服务器,没有任何环境变量可以解除;护栏、出口防火墙与凭据替换全都在那里运行;而审批对话框画在 macOS 上。客户机对这些东西一个地址都没有。

设不成 never 的审批

danger-full-access 的后半段关掉了提示,这一半值得自己的答案。一个能让自己的审批闭嘴 的代理,才是会让我睡不着的那部分。

在 Bromure 的工作区里,提示住在主机上。代理服务器把它们举起来的时候,请求已经离开 VM 了,所以客户机里的那次会话,身上没有任何一个设置能压下其中任何一个。使用前先问会 在一次会话中某份凭据第一次被用到时停下来,并给出有时限的授予:五分钟、一小时、这次 会话的剩下时间,或是不允许。写入策略设成写入前先问时,每一次变更操作都会被一 个标题为 Allow write on "<scope>" from workspace "<name>"? 的对话框拦下来,上面显示原原本本的 操作内容、SQL 语句本身,或 REST 调用的 METHOD /path允许一次根本不建立授予,所 以下一次写入还是会问。授予住在内存里,会话窗口一关就消失。

护栏那一页用一个从句说完了这个性质:写入策略“在代理服务器里强制执行,所以 VM 里被攻 陷的代理绕不过去”。底下的出口防火墙也是一样的做法:一张有序的规则表,带着一个可以设 成 DenyUnmatched traffic 控制项,套用两次——一次在虚拟交换机上,按目的地 IP 与从 DNS 里嗅到的主机名;一次在代理服务器上,按 TLS 服务器名称,web 规则还加上 HTTP 方法。规则的修改不必重启就会送到运行中的会话。

无人看管的运行会往安全的一边倒。通过 SSH 或自动化以无界面方式驱动的工作区,会在自己 的 tmux 里收到同样四个选项的文本提示,而没有回答就等于拒绝。那里最坏的结果,是一次被 挡下的调用,加上 Security Timeline 上的一行红字。在这个 CVE 里,代理把审批设成 never,提示就消失了。

如果你在 Mac 上跑代理的 harness

去问它的本机接口有哪些、谁可以调用它们。在 Bromure 的工作区里, bromure-cli vm ports <workspace> 会打印出客户机当下正在听的 socket,附上端口、协 议、地址与进程,而且会标出只绑在回环地址上的那些。VM 仪表板的 Listening Ports 卡片 显示的是同一份东西。这份清点正是这个 CVE 赖以成立的那个问题,而一条命令就答完了。

如果那个接口也朝外

CVE-2026-82533 的远程那一半,需要端口够得着。工作区的 VM 跑在一个私有 NAT 网络上: 从你的 Mac 够得着,但它们“不会暴露在你的物理局域网上,而且除非你明确发布某个服务, 否则来自别处的入站连接是不可能的”。一个咖啡馆网络根本路由不到的、没有身份验证的代 理控制端口,会让你有余裕按自己的节奏打补丁。

可以撤销的关押,只是一种偏好

DeepSeek 发布了一道弱检查,并在 OX 确认后三天修好。留下来的,是那道检查在守着什么。由 一个进程自己的运行时,绕着这个进程画出来的边界,是这个进程可以拿来谈判的边界:它有 地址、有 API,还有一个里头带着字段的设置对象。在那个字段的背后某处,跑着一条决定这个 调用方能不能写它的代码路径,而这一类的代码路径,离变成装饰品只差一个糟糕的默认值。

把边界画在进程底下,就没有对手可以谈判了。Bromure 工作区里的代理握有 root、握有整个文 件系统,还能在任何端口上起任何它想起的服务。它的 API 密钥是诱饵,它通往网络的唯一路 径是一条通往你 Mac 上代理服务器的 virtio socket,而装着它权限的那个文件,放在它读不到 的地方。在线的那一侧把一切都交给代理,你就不必再守那条线了。

编码代理还会继续长出本机控制平面,因为控制平面正是你打造仪表板、IDE 桥接或差异查看器 的方式。于是每个项目都得回答一个问题:它的代理所执行的代码,跟管着那个代理的设置,是 不是在线的同一侧。答错了,还撑着的就只剩身份验证,而一个 9.4 分就是这样落到一条 shell 命令上的。 装上 Bromure Agentic Coding,把开关放到你的代理够不着的地方。