关掉沙箱的开关就在沙箱里
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-345,Reliance on Untrusted
Inputs in a Security Decision。
坐在一个允许网络调用的沙箱里的代理,对那个接口发了一次调用,把自己的会话设成
danger-full-access,审批设成 never。用
The Hacker News 的说法,
这次模式变更“不需要明确审批,因为它修改的是会话设置,而不是请求新的权限”。
审批系统照设计运作。代理从来没有请求去做危险的事;它请求改一个设置,而那个设置管的 正是危险的事会不会被拿出来问。权限闸门检视的是摆在它面前的那个操作。这次请求是一次 配置写入,而配置写入不在它的清单上。
同一扇门,换个方向
一个信任调用方所送标头的接口,并不在乎连接是从哪个方向来的。如果那个端口在网络上够
得着,同一次调用从机器外面也一样成立:一个没有身份验证的陌生人可以接管代理,把所有
存下来的对话全部导出,不需要 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 上,身份就是拓扑:字节是从哪一条桥进来
的。那不是你能在请求里打出来的东西。
设不成 never 的审批
danger-full-access 的后半段关掉了提示,这一半值得自己的答案。一个能让自己的审批闭嘴
的代理,才是会让我睡不着的那部分。
在 Bromure 的工作区里,提示住在主机上。代理服务器把它们举起来的时候,请求已经离开 VM
了,所以客户机里的那次会话,身上没有任何一个设置能压下其中任何一个。使用前先问会
在一次会话中某份凭据第一次被用到时停下来,并给出有时限的授予:五分钟、一小时、这次
会话的剩下时间,或是不允许。写入策略设成写入前先问时,每一次变更操作都会被一
个标题为
Allow write on "<scope>" from workspace "<name>"? 的对话框拦下来,上面显示原原本本的
操作内容、SQL 语句本身,或 REST 调用的 METHOD /path。允许一次根本不建立授予,所
以下一次写入还是会问。授予住在内存里,会话窗口一关就消失。
护栏那一页用一个从句说完了这个性质:写入策略“在代理服务器里强制执行,所以 VM 里被攻
陷的代理绕不过去”。底下的出口防火墙也是一样的做法:一张有序的规则表,带着一个可以设
成 Deny 的 Unmatched 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,把开关放到你的代理够不着的地方。