你信任的是工作区,而不是那些服务器
2026 年 6 月 26 日,Wiz 披露了 CVE-2026-12957:一个克隆下来的仓库里的 `.amazonq/mcp.json` 让 Amazon Q 自动启动 MCP 服务器,而这些服务器继承了开发者的完整环境——AWS 密钥、云 CLI 令牌、API 机密以及 SSH agent 套接字,对服务器本身却没有单独的同意环节。一次「信任此工作区」的点击,替代了为生成携带你实时云会话的后台进程而本应有的确认。Amazon 在 Language Servers 1.69.0 中修复了它。这里说明为什么这次修复堵住了一个产品却没堵住这一类问题,以及当打开仓库的智能体运行在按 profile 隔离的 Bromure 虚拟机里、位于凭据代理、读写护栏和虚拟机监控级追踪之后时,会有什么不同。
昨天 Wiz 披露了 CVE-2026-12957。你克隆的一个仓库可以
附带一个名为 .amazonq/mcp.json 的文件,而当你在 Amazon Q 中
打开这个文件夹并点击 信任此工作区 的那一刻,该文件就会
启动后台服务器,没有第二次提示。它们启动时
继承了你的 AWS 密钥、你的云 CLI 令牌、你的 API 机密,
以及你的 SSH agent 套接字。一次信任点击触及了你的 shell
所能触及的一切,并把它交给了仓库所选定的代码。
一个为了试用某个基础设施模块而克隆仓库的开发者,并不会
把这当作授予了任何访问权限。克隆是惰性的:它
往磁盘写入文件,什么都不运行。需要判断的时刻发生在
下一步,当你在编辑器里打开该文件夹、助手
问你是否信任它的时候。那条提示读起来就像每个 IDE 都会弹出的、
人们熟悉的「你是否信任此文件夹中文件的作者」那道关卡,
于是你像过去成千上万次那样点了「是」,因为
另一个选项是一个连你的代码都读不了的助手。这一次的「是」
做的事情不止是让助手去读。在 Amazon Q 中,修复之前,
它还会启动仓库写进
.amazonq/mcp.json 里的任何服务器,而那些服务器启动时
就已经把你的实时云会话装进了它们的环境里。
本月早些时候我们写过 同一种形态, 当时 Miasma 蠕虫 把项目配置植入了微软自家 73 个仓库, 载荷在文件夹打开时触发。那个故事讲的是一个 受信任的来源 成了攻击面。这一次更狭窄、也更令人不安: 没有蠕虫,没有被攻陷的维护者,没有任何东西可以指责, 只有助手本身。漏洞在于 Amazon Q 如何读取一个普通的 项目配置文件,并在你一次信任点击之下决定生成 携带你笔记本上最敏感之物的长驻进程。
CVE-2026-12957 究竟做了什么。
2026 年 6 月 26 日,Wiz Research 披露了 CVE-2026-12957, 这是 Language Servers for AWS 中一个高危漏洞(CVSS 8.5), 也就是为 VS Code、JetBrains、Eclipse 和 Visual Studio 上的 Amazon Q Developer 提供动力的引擎。Wiz 在 4 月 20 日 向 Amazon 报告, Amazon 在 5 月 12 日 发布了修复,细节在 6 月 26 日 公开。没有迹象表明它在野外被利用过。 其机理,简化来说:
- Amazon Q 会从你打开的工作区读取
.amazonq/mcp.json:这是一个 按项目作用域的文件,声明了供助手使用的 Model Context Protocol 服务器。 - 打开文件夹时,Q 启动了该文件声明的 MCP 服务器, 对服务器本身却没有单独的同意环节。因此你克隆下来的一个仓库 可以把一个服务器定义摆到助手面前, 并让它运行。
- 被生成的进程 继承了开发者的完整 环境,用 Wiz 的话说,就是「AWS 密钥、云 CLI 令牌、API 机密以及 SSH agent 套接字」。MCP 服务器不过是 Q 启动的一条命令,而那条命令启动时拥有你自己 shell 会拥有的一切。
- 一个服务器定义可以指向任何命令,所以该文件实际上等于 文件夹打开即任意代码执行:它以你的身份运行,你的 云凭据已经加载就绪,就在你信任工作区的那一刻。
这次披露中包含一个关于同意的真实分歧,而这 正是本文的全部重点。Amazon 的立场:「用户在被提示时 必须信任工作区。」 确实有一道关卡,你点击通过了它。Wiz 的发现: 修复之前,对 MCP 服务器本身没有单独的 同意环节。两者都成立,而失败 就存在于二者之间的缝隙里。一个粗粒度、熟悉的信任 决定——和你为了让编辑器索引文件夹而给出的同一个是/否—— 授权了一个大得多的许可:生成携带你实时会话的后台 服务器。你回答的是一个关于 读取 文件 的问题。Amazon Q 却把这次点击花在了 以你的身份运行服务器 上。
Amazon 在 Language Servers 1.69.0 中修复了它(客户端:VS Code 2.20+、 JetBrains 4.3+、Eclipse 2.7.4+、Visual Studio 1.94.0.0+),加入了 此前缺失的按服务器同意,并修补了一个相关的 符号链接检查绕过漏洞 CVE-2026-12958。请更新 Amazon Q。然后越过 补丁,看看它没能解决的那一部分:打开一个仓库 可能会把你的实时云会话放进一个由仓库 所选定的进程里。
同一个仓库,在 Bromure Agentic Coding 内打开。
Bromure Agentic Coding 让你的编码智能体,
包括 Amazon Q,运行在一个 按 profile 隔离的 Linux 虚拟机 里:它有
自己的内核、自己的文件系统、自己的网络栈,跑在 Apple 的 Virtualization
框架上。一个 profile 是一段连贯的工作范围:这个客户、这个
服务、这个你为评估而克隆的开源模块。你把
仓库克隆到那个 profile 里并在那里打开它。漏洞行为
完全像 Wiz 描述的那样复现:你点击 信任此
工作区,Q 读取 .amazonq/mcp.json,并启动该文件声明的
服务器。生成动作触发,仓库
所选定的代码运行起来。
它在 guest 里运行。MCP 服务器在虚拟机内启动并
继承虚拟机的环境,而虚拟机的环境并不持有
你的云会话。Bromure 在 guest 中附带 stub:
对 aws、gcloud、az、kubectl、git 以及任何
读取 Authorization 头或
AWS_ACCESS_KEY_ID 的东西看起来都像真的假值。你 Mac 上的一个代理
坐在离开沙箱的每一个连接前面,识别出 stub,并在请求离开时
在线路上 把它换成真正的机密;
持有密钥的那个沙箱 详细讲解了这个机制。
真正的 AWS 密钥、真正的云 CLI 令牌、真正的 API 机密
从不接触虚拟机能读到的任何文件、环境变量或内存页。
那就让我们把 CVE 的继承过程在那道边界上走一遍。被生成的
服务器读取 $AWS_ACCESS_KEY_ID,得到一个 stub。它读取 ~/.aws
得到一个 stub profile。它从环境里读取云
令牌和 API 机密,得到的是占位符。该服务器
按所写内容完整运行,继承的是一个从未持有你
密钥的盒子。让 CVE-2026-12957 成为凭据窃取漏洞的,是 生成时的
环境继承,而 Bromure 并不破坏它。它让被
继承的环境变得一文不值。
「信任此工作区」是个错误的问题。
这个 CVE 的价值不只在一条补丁说明,因为它涉及那个同意缺口, 而这个缺口是个粒度问题。信任提示问了一个宽泛的 问题,你是否信任这个文件夹,而一个「是」必须同时涵盖 你本意中无害的那件事(让助手读我的代码)和 你并不知道还附带着的危险那件事(用我的云会话 启动后台服务器)。你无法把这答好。没人 能,因为这个问题把两个彼此毫不相干的许可 揉在一起,却只向你展示了无辜的那一个。
Bromure 并不要求你在那种判断上做得更好。它把 判断从路径上移走。在一个 profile 内的信任点击仍然让 助手做它的工作,而它仍然无法启动一个持有 你真实云会话的进程,因为那个会话不在虚拟机里供它 继承。它存活在宿主机上、位于代理之后,只能作为 代理在线路上填入并记录的一个 stub 化请求来触达。许可中危险的 那一半消失了。你并没有保留它;那里根本没有 东西可以授予,因为边界处在智能体之下, 信任提示无法把它挪动。
另一半 危险是一个被生成的服务器从只是好奇
转向具有破坏性,它遇到了 护栏。Bromure 读取
操作,而不只是连接:aws s3 ls 是读,
aws s3 rm 是写;git fetch 是读,git push 是
写。把一个 profile 的云凭据设为 写时询问,那么
当代码伸手去做一个会改变状态的调用,比如 DELETE、
Terminate* 或强制推送时,Bromure 会在线路上把它拦下并
在你 Mac 上弹出一条提示,点名动词、目标和
profile。读永远不会打断你。暂停的是变更,
就像「智能体删除了生产数据库」不再是
事后复盘 而成为你拒绝的一个对话框。
追踪展示了什么。
每个团队在这类事情落地后的第二天早上都会问同一个 问题:我是不是打开过那个仓库,它都运行了什么? 在一台普通笔记本上 诚实的答案是耸耸肩。Q 生成的 MCP 服务器是 你会话里的一个子进程,它读取的任何东西、向哪里联络, 都是以你的身份进行的,没有任何把它与你自己工作 区分开来的记录。
在 Bromure 内,智能体坐在虚拟机里,每一个外发字节都 经过宿主代理,所以即使智能体看不见,生成动作 及其调用仍然可见。宿主机会记录 MCP 服务器的 启动、它运行的命令、它请求代理填入的 凭据,以及它尝试的每一个连接,写进 与智能体所做其余一切相同的 会话追踪,写在智能体之下,被生成的代码无法 伸进去编辑。「这个仓库的服务器有没有碰过我的账户」不再是 你几周后从 CloudTrail 重建出来的一个猜测,而成为 你读到的一行:代理交出的是一个 stub、请求有名字、 目标被记录了下来。对一家企业而言,这就是 我们修补了 Amazon Q 与 我们能展示我们开发者打开的每一个仓库都做了什么 之间的差距,而这种审计姿态正是我们 企业工作 反复回到的那一点。
这在哪些地方救不了你。
被转发的 ssh-agent 套接字在转发期间是可用的。
Bromure 把你的 SSH 私钥保存在 macOS 钥匙串里,从不
把它们复制进虚拟机。但如果一个 profile 转发了 ssh-agent
套接字(这正是 OpenSSH 的本意),一个被生成的服务器就可以在套接字活动时
请求 agent 用那些密钥去 签名。
密钥文件从不离开宿主机;签名能力却确实
触达了 guest。只把套接字转发进确实需要它的 profile,
并像代理给凭据划定作用域那样给它划定作用域。
你批准的一次写操作就是一次会发生的写操作。
读写护栏拦下智能体没有告诉你的那个破坏性
调用。它不会读你关于意图的心思。如果
你是有意要拆掉一个栈、并且批准了那条
提示,Bromure 就会转发那个 Terminate。提示买给你的是
看一眼动词和目标的机会;你仍然得去读它。
profile 是长驻的,所以持久化会持久存在。
一个 Bromure profile 不是一块用完即弃的磁盘。一个把自己 写入 profile 内某个启动路径的被生成服务器,可以在 那个 profile 的下一次会话里苏醒。它醒来时面对的是一个 没有宿主密钥的 guest,以及一个只会说短时、 需提示、有作用域令牌的代理:存在于一个空无一物的盒子里,但 存在依旧。
已修补不等于已解决。
Amazon 在 1.69.0 中加入了按服务器同意,你应该更新。 但下一个在文件夹打开时读取项目配置的助手 仍会做出同一类决定,而它弹出的提示看起来会 一样平常。隔离才是不依赖于 某个特定厂商把某个特定同意对话框做对的那部分。
下一个工作区已经在某处被克隆好了。
Red Hat 作用域 的教训 是发布者不是一道防线。微软 仓库 的教训是仓库 也不是,而且打开一个文件夹就足以运行代码。Amazon Q 又添了一行:信任提示也不是一道防线。它向你 提出的问题,你是否信任这个文件夹,并不是 答案真正重要的那个问题,那个问题是 这个文件夹是否应该能够 生成携带我云会话的服务器。第二个问题从来没有向你 展示过,就算展示了你也无法把它答好。
你不会靠更仔细地读那条提示来修好这个问题,因为
提示本身就是错误的提示。你修好它的方式,是把事情安排成
让「这是哪个工作区」不再是你的云密钥所悬挂的那个
问题;为什么编码智能体不是一个
沙箱 是这个论点的更长
版本。Bromure Agentic
Coding 就是这样一种配置:智能体在一个按 profile 隔离的虚拟机里
打开仓库,真正的凭据留在宿主机上、位于代理
之后,智能体做的每一次写都必须通过一条提示,而
它生成的每一个服务器都被写进一份它无法编辑的追踪。一个被投毒的
mcp.json 最坏也只能继承一个从未持有
你密钥的盒子。它免费、开源,并且今天就已发布。