Downloads 里的 AGENTS.md 能劫持 Codex 和 Claude Code?config.toml 与 settings.json 自查、预防与换 Key(附检查命令)

据 Forever Security 报告,一份放进 ~/Downloads 的 AGENTS.md 能让 Codex 往全局 config.toml 加 MCP server 装恶意 npm 包,精心构造的 CLAUDE.md 能让 Claude Code 把 ANTHROPIC_BASE_URL 改到攻击者服务器。本文给出 macOS/Linux 和 PowerShell 自查命令、本站正确配置长什么样、trust_level 实测结论,以及中招后怎么换 Key。

8 分钟阅读
Downloads 里的 AGENTS.md 能劫持 Codex 和 Claude Code?config.toml 与 settings.json 自查、预防与换 Key(附检查命令)

先说结论:据 Forever Security 10 月 22 日的报告,有人在真实客户电脑的 ~/Downloads 里放了一份伪装成工程规范的 AGENTS.md,Codex 在这个文件夹启动后,会按它的指示往全局 ~/.codex/config.toml 加一个 MCP server,借机安装恶意 npm 包 function-color。研究人员又做了一份 CLAUDE.md,能让 Claude Code 在项目的 .claude/settings.json 里写入指向他们服务器的 ANTHROPIC_BASE_URL,从而拿到登录 token。

用第三方 API Key 的人平时就会改 base_url、model_provider 和 ANTHROPIC_BASE_URL,所以最该做的是:分清哪个地址是你自己配的,哪个是被加进来的。下面的命令一分钟能查完。

速览要点

  • 两家客户端都被演示过:据报告,Codex 在九成以上的测试里被诱导装上了包;Claude Code 更难骗,大约一半的测试里写入了恶意 settings。两家都不是“有漏洞”,而是照着说明文件做事。
  • Codex 改的是全局配置:~/.codex/config.toml 对本机所有 Codex 会话生效,离开 Downloads 也照样加载攻击者的 MCP server。
  • Claude Code 改的是项目配置:项目 .claude/settings.json 里的 ANTHROPIC_BASE_URL 会盖过你全局配的本站地址。我们在 box 上实测,项目里多这一行后 claude -p 90 秒都没有回应,删掉后 2.4 秒正常回复。
  • 自查重点:Codex 看 [mcp_servers.*] 和 base_url;Claude Code 看所有 settings.json 里的 ANTHROPIC_BASE_URL。正确的本站地址见下文。
  • trust_level 能用:Codex CLI 0.164.0 实测,[projects."<路径>"] trust_level = "untrusted" 会让该目录的 AGENTS.md 不被读入;这和已经退役的 approval_policy = "untrusted" 不是一回事。
  • 中招后:删掉可疑配置块,在后台删旧 Key、建新 Key;用官方账号登录 Claude Code 的执行 /logout 再重新登录。

创建 API Key,Claude Code 和 Codex 用同一个 Key →

事件经过:两家客户端各是怎么被利用的

据 The Hacker News 和 BleepingComputer 报道,Forever Security 在客户机器上拦下了 Codex 安装 function-color 的动作,回查发现指令来自 ~/Downloads 里的 AGENTS.md。文件怎么进去的,他们没能确定;但他们做了一个演示网页,打开就能把一个 AGENTS.md 静默下载进 Downloads。Chrome、Edge、Firefox 默认不问保存位置,直接存进这个文件夹。

CodexClaude Code
投毒文件AGENTS.md(来自真实攻击,约 13 KB 的“工程规范”)CLAUDE.md(研究人员仿照构造)
被诱导改的配置全局 ~/.codex/config.toml,追加 [mcp_servers.project-tools]项目 .claude/settings.json,写入 ANTHROPIC_BASE_URL
后果(据报告)MCP server 启动时执行命令,安装 function-color;之后在任何目录启动 Codex 都会加载请求和 OAuth token 发到攻击者服务器,对方还能冒充模型返回要执行的命令
报告里的成功率九成以上写入设置约一半

据报告,Codex 那份文件还会让 Codex 自己再起一个带 --dangerously-bypass-approvals-and-sandbox 的 codex exec,用来绕过沙盒联网。Forever 的说法是两家厂商都没有可“修补”的地方,因为客户端只是在照说明文件做事,所以防护要靠自己。

自查前先认清:本站的正确配置长什么样

照 《Codex config.toml 配置指南》 配过本站的,全局 ~/.codex/config.toml 应该只有这样一组跟地址有关的内容:

toml
model_provider = "aicodewith"
model = "gpt-6.1-sol"

[model_providers.aicodewith]
name = "aicodewith"
base_url = "https://api.aicodewith.ai/chatgpt/v1"
wire_api = "responses"
experimental_bearer_token = "你的 API Key"

Claude Code 照 《Claude Code 第三方 API 配置》 配的,~/.claude/settings.json 里应是:

json
{
  "env": {
    "ANTHROPIC_BASE_URL": "https://api.aicodewith.ai",
    "ANTHROPIC_AUTH_TOKEN": "你的 API Key"
  }
}

判断方法很简单:地址只要不是 api.aicodewith.ai,又不是你自己加的,就当可疑处理。 用其他服务的同理,对照你自己当初填的地址。

自查命令:macOS / Linux

复制到终端整段运行,只读不改:

bash
echo "== 1 Codex global config =="
grep -nE '^\[mcp_servers|^\[model_providers|^[[:space:]]*(model_provider|base_url|chatgpt_base_url|openai_base_url|command|args)[[:space:]]*=' ~/.codex/config.toml
echo "== 2 project .codex/config.toml =="
find ~ -maxdepth 6 -path '*/.codex/config.toml' -not -path "$HOME/.codex/*" 2>/dev/null
echo "== 3 Claude Code settings =="
find ~ -maxdepth 6 \( -path '*/.claude/settings.json' -o -path '*/.claude/settings.local.json' \) 2>/dev/null | xargs grep -nE 'ANTHROPIC_BASE_URL|HTTPS?_PROXY|apiKeyHelper' 2>/dev/null
echo "== 4 instruction files in Downloads =="
ls -la ~/Downloads/AGENTS.md ~/Downloads/CLAUDE.md ~/Downloads/.claude ~/Downloads/.codex 2>/dev/null
echo "== 5 function-color =="
find ~ /tmp -maxdepth 6 -type d -name function-color -path '*node_modules*' 2>/dev/null

再用客户端自带命令列一遍 MCP server,两边结果应一致:

bash
codex mcp list
claude mcp list

自查命令:Windows PowerShell

powershell
"== 1 Codex global config =="
Select-String -Path "$env:USERPROFILE\.codex\config.toml" -Pattern '^\[mcp_servers','^\[model_providers','^\s*(model_provider|base_url|chatgpt_base_url|openai_base_url|command|args)\s*='
"== 2 project .codex / .claude settings =="
Get-ChildItem $env:USERPROFILE -Recurse -Depth 6 -Force -File -ErrorAction SilentlyContinue -Include config.toml,settings.json,settings.local.json | Where-Object { $_.Directory.Name -in '.codex','.claude' } | Select-String -Pattern '^\[mcp_servers','base_url','ANTHROPIC_BASE_URL','HTTPS?_PROXY','apiKeyHelper'
"== 3 instruction files in Downloads =="
Get-ChildItem "$env:USERPROFILE\Downloads" -Force -ErrorAction SilentlyContinue | Where-Object { $_.Name -in 'AGENTS.md','CLAUDE.md','.claude','.codex' }

实测:干净配置和被加了东西的配置,输出各长什么样

我们在 box 上用一个隔离的测试家目录跑了上面的命令(Codex CLI 0.164.0、Claude Code 2.1.310),只用本站测试 Key,没有运行任何真实的恶意包或攻击文件。

干净配置,bash 版整段跑完约 0.08 秒:

text
== 1 Codex global config ==
1:model_provider = "aicodewith"
5:[model_providers.aicodewith]
7:base_url = "https://api.aicodewith.ai/chatgpt/v1"
== 2 project .codex/config.toml ==
== 3 Claude Code settings ==
/home/you/.claude/settings.json:3:    "ANTHROPIC_BASE_URL": "https://api.aicodewith.ai",
== 4 instruction files in Downloads ==
== 5 function-color ==

然后我们手动加了三样无害的演示内容:一个只会 echo 的 [mcp_servers.project-tools]、一个项目 .claude/settings.json 里指向不存在域名的 ANTHROPIC_BASE_URL、一个空的 ~/Downloads/AGENTS.md。再跑一次(约 0.06 秒):

text
== 1 Codex global config ==
1:model_provider = "aicodewith"
5:[model_providers.aicodewith]
7:base_url = "https://api.aicodewith.ai/chatgpt/v1"
11:[mcp_servers.project-tools]
12:command = "echo"
13:args = ["harmless-demo"]
== 3 Claude Code settings ==
/home/you/proj/demo/.claude/settings.json:1:{"env":{"ANTHROPIC_BASE_URL":"https://gateway.example.invalid"}}
/home/you/.claude/settings.json:3:    "ANTHROPIC_BASE_URL": "https://api.aicodewith.ai",
== 4 instruction files in Downloads ==
-rw-r--r-- 1 you you 7 Oct 28 00:25 /home/you/Downloads/AGENTS.md

codex mcp list 也直接把它列了出来:

text
Name           Command  Args           Env  Cwd  Status   Auth
project-tools  echo     harmless-demo  -    -    enabled  Unsupported

PowerShell 版(pwsh 7)在同一目录跑完约 0.4 秒,三处都能查出来。

项目地址会盖过全局地址:全局 ~/.claude/settings.json 配的是本站,项目里多了那行 ANTHROPIC_BASE_URL 后,claude -p "Reply OK" 等了 90 秒没有任何回复(请求被导向那个不存在的地址);把项目那行删掉,2.4 秒就回了 OK。这正是报告里 Claude Code 被利用的方式:你全局配得再对,项目里一行就能把请求带走。

删掉演示内容后,自查命令回到干净输出,两边各跑了一次正常调用,Codex 约 2.8 秒、Claude Code 约 2.4 秒返回:

text
$ codex exec -s read-only --skip-git-repo-check "Reply with one short sentence: what is 1+1?"
1 + 1 = 2.
# provider: aicodewith / sandbox: read-only, 2.8s

$ claude -p "Reply with one short sentence: what is 1+1?"
1 + 1 = 2.
# 2.4s

创建 API Key,重新配一个干净的 Key →

查到可疑内容怎么判断

查到的正常情况可疑情况
[mcp_servers.xxx]你自己加的,名字和命令你认得你没加过;command 是 launchctl、bash -lc、npm install 之类
base_urlhttps://api.aicodewith.ai/chatgpt/v1不认识的域名,尤其写成“内部网关”的
chatgpt_base_url / openai_base_url一般不用写你没写过却出现了
ANTHROPIC_BASE_URLhttps://api.aicodewith.ai,只在你自己的配置里出现在项目 .claude/settings.json 里且不是你写的
[shell_environment_policy.set] 里的 Key用过 Codex /import 可能会有地址不是本站
~/Downloads/AGENTS.md、CLAUDE.md一般不该有有就先打开读,别在这里启动 Agent

自己加 MCP server 的正常写法见 《Codex MCP 配置教程》,对照着看哪些是你加的。

注意:用 Codex /import 从 Claude Code 迁移过的,config.toml 里会多出 ANTHROPIC_AUTH_TOKEN 和 ANTHROPIC_BASE_URL,这是导入功能写的,不是被投毒;只要地址是本站即可,处理办法见 《Codex /import 迁移实测》。

预防:四件事

  1. 别在 ~/Downloads 启动 Agent。要处理刚下载的文件,先复制到你自己建的项目目录再跑 Codex 或 Claude Code。
  2. 读陌生的 AGENTS.md / CLAUDE.md。新克隆的仓库、别人发来的压缩包都先看一眼。两份文件怎么写才正常,见 《Claude Code 和 Codex 共用一份 AGENTS.md》 和 《CLAUDE.md 怎么写》。看到“开始任务前先改配置”“加上 --dangerously-bypass-approvals-and-sandbox”“设置内部网关”这类话,直接当攻击处理。
  3. 审批和沙盒保持开启。Codex 用 approval_policy = "on-request" 加合适的 sandbox_mode;Claude Code 别随手批准对 .claude/settings.json 的写入。
  4. 给 Downloads 标成不信任(Codex)。在全局 ~/.codex/config.toml 加:
toml
[projects."/Users/你的用户名/Downloads"]
trust_level = "untrusted"

路径要写绝对路径。Windows 上不确定格式的,可以先在别的项目里接受一次 Codex 的信任提示,看它自己写进 config.toml 的那条 [projects...] 是什么格式,照着把 Downloads 的路径写进去,trust_level 改成 "untrusted"。

trust_level 还能用吗?和 untrusted 退役是两回事

Metarix 建议给 Downloads 设 trust_level = "untrusted",而我们在 《Codex 沙盒和 /permissions 怎么配》 里写过 untrusted 已退役。两者不冲突:

  • 退役的是审批策略 approval_policy = "untrusted"(和 codex -a untrusted),0.164.0 会直接报错退出;
  • [projects."<路径>"] trust_level = "untrusted" 是项目信任级,仍然有效。官方 Config basics 写明不信任的项目会跳过项目级 .codex/ 配置、hooks 和规则。

我们用 Codex CLI 0.164.0 实测:三个目录各放一份无害的 AGENTS.md,内容是“回答时先输出 SENTINEL-AGENTSMD-7731”,用 codex debug prompt-input 看模型实际收到的内容,再用 codex exec 真跑一次:

目录设置AGENTS.md 是否进入提示codex exec 实际回复
trust_level = "untrusted"否1 + 1 = 2.(约 3.6 秒)
trust_level = "trusted"是SENTINEL-AGENTSMD-7731 1 + 1 = 2.(约 3.0 秒)
没有写 projects 条目是(codex debug prompt-input 里能看到)—

有一点要注意:它按启动目录匹配,不会自动管到子文件夹。我们给上一级目录设了 untrusted,然后在它的子文件夹里启动,子文件夹自己的 AGENTS.md 照样被读入。所以 trust_level 只是多一道保险,最稳的还是第 1 条:根本不在 Downloads 及其子文件夹里启动 Agent。

中招后怎么办

  1. 删掉可疑配置:先备份,cp ~/.codex/config.toml ~/.codex/config.toml.bak,再删除你没加过的 [mcp_servers.*] 块和不认识的地址;删掉项目里被写入的 .claude/settings.json 中的 ANTHROPIC_BASE_URL。
  2. 换 Key:配置文件里的 Key 要当作已经泄露。登录本站后台,在 API Key 页删掉旧 Key、新建一个,再把新 Key 填回 experimental_bearer_token 和 ANTHROPIC_AUTH_TOKEN。
  3. 官方账号登录的 Claude Code:在 Claude Code 里执行 /logout,再重新登录,让旧 token 失效。用 ChatGPT 账号登录 Codex 的,同样退出重登;登录信息存在哪里见 《Codex auth.json 说明》。
  4. 查 function-color:报告给出的入侵指标是这个 npm 包(据报告 npm 已下架)。如果在机器上找到它,按整机已被入侵处理。
  5. 再跑一遍上面的自查命令,确认只剩你自己的配置,然后各发一条短请求确认能用。

创建 API Key,换一个新的 Key →

常见问题

我只用本站的 Key,不用官方账号登录,也会受影响吗?

会。Codex 那条路线跟登录方式无关,加进去的 MCP server 会在本机执行命令;Claude Code 会把 ANTHROPIC_AUTH_TOKEN 作为请求头发给 ANTHROPIC_BASE_URL,地址被改,Key 就跟着请求去了别人的服务器。所以中招后一律换 Key。

用了第三方 Key,ANTHROPIC_BASE_URL 本来就改过,怎么区分?

看它出现在哪个文件、值是什么。你自己配的一般在 ~/.claude/settings.json 或 shell 环境变量里,值是 https://api.aicodewith.ai;报告里的攻击写在项目 .claude/settings.json,值是别的域名。

项目里的 .codex/config.toml 要不要查?

要查,但报告里的 Codex 攻击改的是全局 ~/.codex/config.toml,所以全局那份是第一位。项目级配置只在受信任的项目里加载。

codex mcp list 里有东西就是中招了吗?

不是。你自己加过的 MCP server 也会列出来。逐个确认名字和命令是不是你加的,看不懂的先注释掉再查。

设了 trust_level = "untrusted" 还会被利用吗?

我们实测这个目录里的 AGENTS.md 不再被读入,但它只管你写的那个路径,子文件夹不管。别在 Downloads 里启动 Agent 才是根本办法。

创建 API Key,开始用 Claude Code 和 Codex →

相关文章