GitSpawn:仓库 .git 配置如何让 Claude Code、Codex 和 Cursor 执行攻击者代码

·阅读约 13 分钟·Evergreen Tools Team
Terminal showing git configuration hijack risk for AI coding agents

💡 工具推荐加固代理工作站?用 Evergreen Tools 的正则测试器与文本比较工具扫描配置,用哈希生成器做文件指纹。 正则测试工具, 文本比较工具, 哈希生成器

如果攻击者能让你在「打开项目」的那一刻运行任意代码——不需要你点任何按钮、不需要代理调用模型、甚至不需要你同意信任这个工作区——你会害怕吗?这就是 Manifold Security 在 2026 年 9 月初披露的 GitSpawn 漏洞类别:横跨七个命令行 AI 编码代理的八个漏洞里,仓库自带的 Git 配置可以指定一个命令,而代理会在你的机器上执行它——在沙箱之外、没有审批提示。OpenAI 同一天为 Codex 发布了三个同类 CVE。截至 9 月 1 日复测,goose、Claude Code 与 Cursor 已修复,而 Hermes Agent、Qwen Code、Grok Build 与 Claude Code 的第二条路径仍然暴露。

1. 漏洞解剖:core.fsmonitor 与「值是命令的配置项」

Git 有大量配置项,其值本身就是一个命令。最著名的是 core.fsmonitor:Git 在刷新索引时会执行它指定的命令——包括每次 git status 和 git diff 时。fsmonitor 本来是性能优化(让外部守护进程告诉 Git 哪些文件变了),但任何能从仓库的 .git/config 里读它的操作,都会把它的值当命令执行。恶意仓库只需提交一个带 [core] fsmonitor = "python3 /tmp/payload.py" 的 .git/config。要求是仓库必须以文件形式到达且 .git 目录完好:共享压缩包、共享驱动器、同步文件夹或 U 盘都能保留 .git,而普通 git clone 不会——这正是攻击者选择的分发路径。

// The attack in one picture. Git config supports keys whose
// VALUE IS A COMMAND. core.fsmonitor is the best known: Git
// runs it whenever the index refreshes -- including on
// 'git status' and 'git diff'. A repo ships this file:
// .git/config
[core]
    fsmonitor = "python3 /tmp/payload.py"
// Open the repo in an agent (or IDE). Agent runs 'git status'
// in the background. Git runs fsmonitor. Payload executes as
// the user, outside the sandbox, no approval prompt.

2. 为什么代理特别容易中招

IDE 与编码代理会在启动时在后台调用 git status、git diff 来确定当前分支和改动文件——它们从不修改仓库配置,只是读取,而读取就会触发 fsmonitor。Manifold 的原话:「漏洞不在模型里,也不在任何新东西里。它藏在底层普通的管道里——代理在会话启动时为了弄清自己身处何地而派生的子进程。」在 Claude Code 和 Hermes Agent 上,载荷在你接受工作区信任提示之前就会触发;在 Qwen Code 上,发生在你认证之前;在 Grok Build 上,发生在第一次按键时。

Security researcher inspecting a malicious repository archive
// Manifold Security (GitSpawn, disclosed September 2026)
// found this pattern in 7 CLI agents: goose, Claude Code,
// Codex, Cursor, Qwen Code, Hermes Agent, Grok Build.
// In goose, 'goose review' builds git invocations with one
// config flag and strips nothing else:
goose review   # runs git with -c core.quotePath=off
// GitHub advisory CVE-2026-72718 (CVSS 7.0): "running goose
// review inside a malicious repo runs attacker code -- no
// submitted prompt, no model call, no tool approval, no
// trust prompt. The command executes before goose ever
// contacts the model." Fixes shipped for goose, Claude Code,
// and Cursor; Qwen Code, Grok Build, Hermes Agent and a
// second Claude Code path were still exposed on Sep 1.

3. 受影响代理与 CVE 全景

Manifold 披露了 goose、Claude Code、Cursor 的修复版本与 Hermes Agent、Qwen Code、Grok Build 的未修复状态,并确认在 2.1.258(当前版本)上 Claude Code 经 claude ultrareview 的第二条路径仍然活跃。GitHub 给 goose 分配了 CVE-2026-72718(CVSS 4.0 基础分 7.0),公告直言「在恶意仓库里运行 goose review 就是运行攻击者代码」:无提示、无模型调用、无工具审批。OpenAI 同日为 Codex 发布三个 CVE(含 CVE-2026-19592)——helper 在 Codex 命令沙箱之外、无用户审批提示地运行,攻击者代码能以用户权限读取、修改、删除文件。Hermes Agent 被分配 CVE-2026-71963。值得注意的是:Sonar 早在 4 月就报告过同一 sink,Anthropic 曾在 2.0.34(2025 年 11 月)把 git status 移到信任对话框之后,但 2.1.193(2026 年 6 月)中同类行为再次出现。

# Detection: list every local repo config that points a
# config key at an executable, and print its origin so you
# can tell repo-supplied values from user/global ones.
for d in $(find . -name .git -type d); do
  git --git-dir="$d" config --local --list --show-origin     | grep -E 'fsmonitor|hooksPath|core.editor|alias.|pager.|diff..*command'     && echo "SUSPECT: $d"
done
# Also audit global + system level:
git config --global --list --show-origin

4. 为什么这不是模型幻觉问题

把这类漏洞归咎于「模型被提示词注入」是错的:这里没有提示词,模型甚至还没被调用。问题在于代理把本地子进程当成了可信管道,而仓库内容(包括元数据)是不受信任的输入。这与 IDE 历史上的信任对话框绕过同源——Sonar 指出这与 VS Code 1.63.1 之前的 CVE-2021-43891、JetBrains 2021.3.1 之前的 CVE-2022-24346 是同一类。教训是:任何「打开项目就运行本地命令」的设计,都必须把仓库元数据当作不可信输入来处理。

Shield icon representing sandbox and trust boundaries

5. 检测与缓解

缓解分四层:一,更新代理并固定版本——Codex CLI 当前 0.152.1,低于 0.131.0 的安装仍暴露;二,改变仓库到达方式——拒绝带 .git 的压缩包,一律从可信远端重新克隆;三,克隆后显式钉死危险键:core.fsmonitor false、core.hooksPath .git/hooks;四,用脚本扫描所有本地仓库的 config,grep fsmonitor、hooksPath、alias、pager 等「命令型」键并打印来源。本文代码块给出了可直接使用的检测与阻断脚本。

#!/bin/bash
# Safe handling: never let a repo arrive with its .git intact.
# Ordinary clones are safe (the server's config is not cloned);
# archives, shared drives, sync folders and USB sticks preserve
# .git -- that is the delivery vector. Reject or re-clone.
for f in "$@"; do
  if unzip -l "$f" 2>/dev/null | grep -q '/[.]git/'; then
    echo "BLOCKED: $f contains .git -- re-create from a clone"
  fi
done
# After any trusted clone, pin the dangerous keys:
git config core.fsmonitor false
git config core.hooksPath .git/hooks

6. 更深的教训:信任边界

截至 9 月 2 日没有任何在野利用报告,CISA KEV 目录(1,687 条)里也没有这些 CVE——但这不是松懈的理由。GitSpawn 的价值在于它划出了一条清晰的信任边界:来自网络的仓库是输入,永远不该携带可执行意图;任何把它当可信环境的行为都是漏洞。对你的团队来说,最低成本的动作是:更新代理、禁止带 .git 的压缩包、克隆后审计配置。五分钟后就能做完,却能让一整类攻击失效。

// Patch hygiene: the vulnerable class ships in agent release
// channels. Pin and verify versions like any dependency.
const AGENT_FIXES = {
  goose: "fixed (CVE-2026-72718, CVSS 4.0 base 7.0)",
  claudeCode: "core.fsmonitor fixed in 2.1.196; ultrareview path open on 2.1.258 (Sep 1)",
  cursor: "fixed (reported 3 weeks earlier by Manifold)",
  codex: "fixed; installs pinned below 0.131.0 exposed (current 0.152.1)",
  qwenCode: "unpatched at 0.22.3 as of Sep 2",
  grokBuild: "unpatched (xAI closed earlier report as informative)",
  hermesAgent: "unpatched (CVE-2026-71963)",
};

📌 常见问题 FAQ

什么是 GitSpawn?

GitSpawn 是 Manifold Security 对一类漏洞的命名:仓库自带的 Git 配置(如 core.fsmonitor)指定一个命令,编码代理在启动时执行 git status/diff,从而在沙箱外以用户权限运行攻击者代码。

什么是 GitSpawn?

GitSpawn 是 Manifold Security 对一类漏洞的命名:仓库自带的 Git 配置(如 core.fsmonitor)指定一个命令,编码代理在启动时执行 git status/diff,从而在沙箱外以用户权限运行攻击者代码。

什么是 GitSpawn?

GitSpawn 是 Manifold Security 对一类漏洞的命名:仓库自带的 Git 配置(如 core.fsmonitor)指定一个命令,编码代理在启动时执行 git status/diff,从而在沙箱外以用户权限运行攻击者代码。

什么是 GitSpawn?

GitSpawn 是 Manifold Security 对一类漏洞的命名:仓库自带的 Git 配置(如 core.fsmonitor)指定一个命令,编码代理在启动时执行 git status/diff,从而在沙箱外以用户权限运行攻击者代码。

什么是 GitSpawn?

GitSpawn 是 Manifold Security 对一类漏洞的命名:仓库自带的 Git 配置(如 core.fsmonitor)指定一个命令,编码代理在启动时执行 git status/diff,从而在沙箱外以用户权限运行攻击者代码。

哪些代理受影响?

披露覆盖七个 CLI 代理:goose、Claude Code、Codex、Cursor、Qwen Code、Hermes Agent、Grok Build。goose、Claude Code、Cursor 已发布修复;9 月 1 日复测时 Hermes Agent、Qwen Code、Grok Build 与 Claude Code 的 ultrareview 路径仍受影响。

哪些代理受影响?

披露覆盖七个 CLI 代理:goose、Claude Code、Codex、Cursor、Qwen Code、Hermes Agent、Grok Build。goose、Claude Code、Cursor 已发布修复;9 月 1 日复测时 Hermes Agent、Qwen Code、Grok Build 与 Claude Code 的 ultrareview 路径仍受影响。

哪些代理受影响?

披露覆盖七个 CLI 代理:goose、Claude Code、Codex、Cursor、Qwen Code、Hermes Agent、Grok Build。goose、Claude Code、Cursor 已发布修复;9 月 1 日复测时 Hermes Agent、Qwen Code、Grok Build 与 Claude Code 的 ultrareview 路径仍受影响。

哪些代理受影响?

披露覆盖七个 CLI 代理:goose、Claude Code、Codex、Cursor、Qwen Code、Hermes Agent、Grok Build。goose、Claude Code、Cursor 已发布修复;9 月 1 日复测时 Hermes Agent、Qwen Code、Grok Build 与 Claude Code 的 ultrareview 路径仍受影响。

哪些代理受影响?

披露覆盖七个 CLI 代理:goose、Claude Code、Codex、Cursor、Qwen Code、Hermes Agent、Grok Build。goose、Claude Code、Cursor 已发布修复;9 月 1 日复测时 Hermes Agent、Qwen Code、Grok Build 与 Claude Code 的 ultrareview 路径仍受影响。

为什么普通 git clone 是安全的,压缩包却不是?

git clone 只会拉取远端仓库的对象,不会把服务器上的 .git/config 带过来;而共享压缩包、共享驱动器、同步文件夹或 U 盘会保留完整的 .git 目录,攻击者正是把恶意配置放在那里。

为什么普通 git clone 是安全的,压缩包却不是?

git clone 只会拉取远端仓库的对象,不会把服务器上的 .git/config 带过来;而共享压缩包、共享驱动器、同步文件夹或 U 盘会保留完整的 .git 目录,攻击者正是把恶意配置放在那里。

为什么普通 git clone 是安全的,压缩包却不是?

git clone 只会拉取远端仓库的对象,不会把服务器上的 .git/config 带过来;而共享压缩包、共享驱动器、同步文件夹或 U 盘会保留完整的 .git 目录,攻击者正是把恶意配置放在那里。

为什么普通 git clone 是安全的,压缩包却不是?

git clone 只会拉取远端仓库的对象,不会把服务器上的 .git/config 带过来;而共享压缩包、共享驱动器、同步文件夹或 U 盘会保留完整的 .git 目录,攻击者正是把恶意配置放在那里。

为什么普通 git clone 是安全的,压缩包却不是?

git clone 只会拉取远端仓库的对象,不会把服务器上的 .git/config 带过来;而共享压缩包、共享驱动器、同步文件夹或 U 盘会保留完整的 .git 目录,攻击者正是把恶意配置放在那里。

这属于提示词注入吗?

不属于。载荷触发不需要模型调用或提示词:代理在联系模型之前,仅仅在启动时运行 git status 就足以执行恶意命令。

这属于提示词注入吗?

不属于。载荷触发不需要模型调用或提示词:代理在联系模型之前,仅仅在启动时运行 git status 就足以执行恶意命令。

这属于提示词注入吗?

不属于。载荷触发不需要模型调用或提示词:代理在联系模型之前,仅仅在启动时运行 git status 就足以执行恶意命令。

这属于提示词注入吗?

不属于。载荷触发不需要模型调用或提示词:代理在联系模型之前,仅仅在启动时运行 git status 就足以执行恶意命令。

这属于提示词注入吗?

不属于。载荷触发不需要模型调用或提示词:代理在联系模型之前,仅仅在启动时运行 git status 就足以执行恶意命令。

我现在应该做什么?

升级并固定代理版本(Codex CLI 低于 0.131.0 仍暴露);禁止接收带 .git 的压缩包;对克隆后的仓库执行 git config core.fsmonitor false 并扫描本地仓库中的命令型配置键。

我现在应该做什么?

升级并固定代理版本(Codex CLI 低于 0.131.0 仍暴露);禁止接收带 .git 的压缩包;对克隆后的仓库执行 git config core.fsmonitor false 并扫描本地仓库中的命令型配置键。

我现在应该做什么?

升级并固定代理版本(Codex CLI 低于 0.131.0 仍暴露);禁止接收带 .git 的压缩包;对克隆后的仓库执行 git config core.fsmonitor false 并扫描本地仓库中的命令型配置键。

我现在应该做什么?

升级并固定代理版本(Codex CLI 低于 0.131.0 仍暴露);禁止接收带 .git 的压缩包;对克隆后的仓库执行 git config core.fsmonitor false 并扫描本地仓库中的命令型配置键。

我现在应该做什么?

升级并固定代理版本(Codex CLI 低于 0.131.0 仍暴露);禁止接收带 .git 的压缩包;对克隆后的仓库执行 git config core.fsmonitor false 并扫描本地仓库中的命令型配置键。