你为编码智能体建起的每一道控制——审批弹窗、工具白名单、沙箱——都坐落在模型与世界之间,而 GitSpawn 压根不从模型旁边经过。Manifold Security 披露了一类横跨七款 CLI 编码智能体的八个缺陷:打开一个被做了手脚的仓库就是全部攻击——外壳跑一次 git status 来收集上下文,Git 遵从了仓库自己提供的 core.fsmonitor 设置,于是攻击者的命令在任何人敲下提示词之前,就以完整的用户权限执行了。研究者在 9 月 1 日复测时,八个中有四个仍在执行仓库提供的命令。
披露的是什么
Git 有一项叫 core.fsmonitor 的性能特性:把它指向一个辅助程序,Git 每次刷新索引时就会运行那个程序,从而免去一次完整的文件系统扫描。这项设置可以存在仓库自己的 .git/config 里。而被检视的几乎每一款 CLI 编码智能体,都会在会话开始时悄悄跑一次 git status、git diff 之类的命令来弄清自己身处何处。这两个事实合起来,就成了不含任何漏洞利用的任意代码执行——配置被完全按设计读取,命令被完全按配置运行。
| 步骤 | 开发者看到的 | 实际发生的 |
|---|---|---|
| 仓库落到磁盘上 | 一个来自同事、客户或缺陷报告的文件夹 | 一份攻击者撰写的 .git/config 随之而来 |
| 智能体打开该目录 | 工具正在启动 | 外壳向 git 派生子进程以取上下文 |
| Git 刷新索引 | 什么也没有——没有任何输出 | core.fsmonitor 拉起攻击者的可执行文件 |
| 会话开始 | 一个提示符,等着你输入 | 代码已以登录用户的身份跑完了 |
受影响的名单并非一堆边缘的业余项目:Claude Code、OpenAI Codex、Cursor、Grok Build、Goose、Hermes Agent 和 Qwen Code。七支独立的团队、七套独立的代码库、一个共有的盲区。
那道审批弹窗从来就不在这条路径上
读一遍过去一年的智能体安全文献,它们收敛到同一个思维模型:模型是不可信的决策者,所以在"它决定什么"和"实际发生什么"之间设一道关。审批工具调用。把命令列进白名单。把整套东西塞进容器。这些控制无一例外都锚在一个模型回合上——而对它所针对的那个威胁而言,这是个好模型。
GitSpawn 提醒我们:外壳不是中立的管道。在模型看到任何东西之前,外壳就在收集上下文:列文件、读配置、查分支、算 diff。那些活儿是你的智能体替你运行的代码,跑在你的账号里,输入由攻击者掌控,而这一整个品类没有任何产品把它当作一道有特权的边界。研究者指出,在某些情形下它甚至在用户完成认证之前就触发了——也就是说,那个跑掉了攻击者命令的进程,当时还没确立是谁在用它。
- 审批弹窗无从触发,因为没有人提议过这个动作。这里没有工具调用,只有一个外壳每次都会跑的子进程。
- 命令白名单会放行它。
git status在有史以来每一份白名单上,而危险行为在 Git 内部,不在参数向量里。 - 沙箱往往还没起来。启动时的上下文收集经常跑在宿主进程里;而即便它跑在容器内,那个容器的范围也是照着智能体的工作划的,不是照着任意的攻击者代码划的。
- 没有任何东西被记为可疑,因为按智能体自己的记账法,没发生任何可疑的事。成绩单是从损害之后才开始的。
这与拦截日志这条注入通道是同一个结构性论点的另一个方向。那边,攻击者的文本抵达了一个可信存储,智能体把它当作指令读了。这边,攻击者根本不需要模型配合——外壳就够了。两者都是"有意思的攻击面在循环周围的管道上,而不在循环里"。
git clone 是安全的,而这正是陷阱
从 GitHub 克隆不会携带载荷。Git 会用你自己的默认值和远端 URL 在本地构建 .git/config;源仓库的配置不会被传过来。正是这一个事实,让人们对这次披露的第一反应通常是"归到理论问题里去"——而这恰恰是它值得读第二遍的原因,因为那些确实会携带整个目录的投递路径,都平淡无奇。
- 压缩包。一个工作树的 zip 或 tarball 会原样复制
.git。客户交付代码库是这样、笔试题送达是这样、仓库被附在支持工单上也是这样。 - 共享盘与同步文件夹。网络共享、同步客户端、U 盘、挂进虚拟机的目录。它们都不会重写配置。
- 预构建的开发容器与镜像。工作树是在别人的机器上准备好、整个发过来的。这也是开发者最不可能去检查、却最愿意信任的那条路径——因为"免去检查"本来就是镜像存在的意义。
- 恢复的备份与快照。一次恢复会重现抓取时点的那份配置,包括更早一次入侵放进去的那份。
把这些和编码智能体的实际用法放在一起,暴露面就清晰了。这类智能体的日常就是被指向陌生代码——给这个仓库做分诊、复核这位外包的活儿、迁移这个遗留项目。"打开一个别人准备好的目录"对这个品类而言不是边缘情况,那就是本职工作。
更有用的产物是那份披露记录
Goose 发布了修复并拿到 CVE-2026-72718。Claude Code 的 core.fsmonitor 问题于 6 月 26 日报出、三天后由 2.1.196 修复——那份报告本身被作为"同一天更早提交的另一份报告的重复"关闭了,这说明有两位研究者在几小时之内发现了同一件事。Cursor 修好了自己那条路径。这是一套运转正常的披露流程。
另一半才是故事。9 月 1 日复测时,仍有四个发现在执行仓库提供的命令:Grok Build、Qwen Code、Hermes Agent,以及 Claude Code 的第二条配置路径。Hermes Agent 的 CVE-2026-71963 是在六次联系无人应答之后被独立分配的——一家已经发布了智能体、却联系不上安全对接人的厂商。
从这道分野里能取走的两件事,比漏洞本身更值得记:
- 一家厂商打了补丁,不等于一整类问题被打了补丁。同一款智能体,一条路径三天修好,另一条两个月后仍然敞着。"我们修好了 GitSpawn"这种厂商层面的表述,撑不过一类八个发现的检验,钉死版本号的缓解措施也撑不过。
- 安全成熟度如今是智能体工具的一条采购维度。一个项目有没有安全对接人、有没有公告订阅源、有没有"把一份报告变成一次发布"的记录,对于一件你要拿自己的凭据指向不可信代码的工具来说,不是加分项。它决定了你的暴露窗口,而在七款在功能对比表上看起来都差不多的产品之间,这项差别大得惊人。
真正有用的做法
即刻的修复属于厂商,而且并不精微:拒绝由仓库提供的可执行配置。Git 自带机制——safe.directory 会拦下不属于当前用户的仓库,而智能体在派生子进程时也可以强制指定自己的配置作用域。这个品类里的每一款智能体,在做上下文收集时都应当关掉仓库级配置对可执行设置的影响,并且应当在文档里写明这一点。
不必等待、你自己就能做的事更窄,但真实有效,而且能推广到这项设置之外:
- 把"打开一个目录"当作那个有特权的动作。不是第一次工具调用——而是智能体被指向一棵目录树的那一刻。信任决策其实发生在那里,而目前没有任何产品会在那里弹窗。
- 在用智能体打开非自己克隆的代码之前,先看一眼
.git/config。对来路不明的目录树grep一遍fsmonitor、hooksPath、sshCommand、pager和editor。这是一道两行的、类似 pre-commit 的检查,覆盖了目前已知的那些形态。 - 重新克隆,而不是就地打开。如果仓库是以压缩包形式到来的,就从权威远端克隆一份再把差异打上去。这在构造上就丢弃了攻击者掌控的配置——这是一次工作流改动,而不是一道控制。
- 把陌生仓库放进一个已经起好的沙箱里跑。价值不在于沙箱有多聪明,而在于它在智能体进程启动之前就已存在,于是它能框住智能体自身权限系统永远看不见的那段启动代码。开发容器只有在镜像是你自己的时候才管用。
- 盯住智能体子进程再派生出的进程。行为信号——
git拉起了一个不是 Git 子命令的东西——告警成本很低,而且熬得过下一个变体,因为下一个变体会换一个配置键。
更一般的教训比 core.fsmonitor 活得更久。编码智能体会派生子进程去调用的每一件工具,都有自己的配置语言,而其中好几种要么是图灵完备的,要么能指名一个待运行的程序:构建系统、测试运行器、linter、格式化工具、包管理器、编辑器。一个为了帮上忙而去读项目配置的智能体,执行的正是那个项目的意图。把模型当作唯一不可信组件的威胁模型,建模的是另一个系统。
常见问题
GitSpawn 是什么?
Manifold Security 披露的一类横跨七款 CLI 编码智能体的八个漏洞:仓库自己的 core.fsmonitor Git 设置,会在编码智能体执行一次寻常的后台 git status 时,运行一条攻击者选定的命令。不需要敲提示词,也不需要点审批;在某些情形下,它甚至在用户完成认证之前就触发了。
我只从 GitHub 克隆,会受影响吗?
沿这条路径不会。git clone 是在本地构建 .git/config 的,不会复制源仓库的那一份。暴露来自那些以压缩包形式抵达、放在共享盘或同步盘上、装在预构建开发容器里、或者经由恢复备份而来的仓库——任何复制而非重建 .git 目录的方式。
沙箱能保护我吗?
只能保护一部分,而且只有当它在智能体进程启动之前就已运行时才行。启动时的上下文收集经常在宿主进程里执行;即便它确实跑在容器内,那个容器的范围也是照着智能体的工作划的,不是照着任意攻击者代码划的。沙箱框住的是损害,它并不阻止那次执行。
哪些智能体已经修了?
Goose(CVE-2026-72718)、Cursor,以及 Claude Code 的 core.fsmonitor 路径——后者在 6 月 26 日报告后三天由 2.1.196 修复。四个发现——Grok Build、Qwen Code、Hermes Agent(CVE-2026-71963)以及 Claude Code 的第二条配置路径——在 9 月 1 日复测时仍在执行仓库提供的命令。去查你自己那个版本,而不是查厂商的一句声明。
这算提示词注入吗?
不算,而且这个区分很要紧。提示词注入是去说服一个模型做某件事;这件事从头到尾没有模型参与。它是通过一件外壳自作主张调用的可信工具而实现的任意代码执行——这正是为什么每一道瞄准"模型决定什么"的防御对它都无关。
最小可用的检查是什么?
在用智能体打开之前,对进来的工作树 grep 一遍 .git/config 里的 fsmonitor、hooksPath、sshCommand、pager 和 editor。它覆盖了已知形态、不花什么成本,而且可以脚本化成你现有那层包装里的一个"打开前"钩子。
延伸阅读
本站相关:
- 智能体外壳——为什么没人公布的那一半系统,通常正是出错的那一半。
- 沙箱与执行——一道边界要在什么之前立起来才守得住。
- 智能体供应链安全——这件事落在哪个品类里,以及那个品类其余部分的形状。
- 环境权限——为什么被用掉的总是进程手里已经握着的那份凭据。
- 爆炸半径——那个在你还不知道攻击原理时就能框住的属性。
- 检测智能体被攻陷——那些熬得过"换一个配置键的变体"的行为信号。