先说结论:据 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 -p90 秒都没有回应,删掉后 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 默认不问保存位置,直接存进这个文件夹。
| Codex | Claude 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 应该只有这样一组跟地址有关的内容:
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 里应是:
{
"env": {
"ANTHROPIC_BASE_URL": "https://api.aicodewith.ai",
"ANTHROPIC_AUTH_TOKEN": "你的 API Key"
}
}
判断方法很简单:地址只要不是 api.aicodewith.ai,又不是你自己加的,就当可疑处理。 用其他服务的同理,对照你自己当初填的地址。
自查命令:macOS / Linux
复制到终端整段运行,只读不改:
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,两边结果应一致:
codex mcp list
claude mcp list
自查命令:Windows 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 秒:
== 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 秒):
== 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 也直接把它列了出来:
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 秒返回:
$ 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
查到可疑内容怎么判断
| 查到的 | 正常情况 | 可疑情况 |
|---|---|---|
| [mcp_servers.xxx] | 你自己加的,名字和命令你认得 | 你没加过;command 是 launchctl、bash -lc、npm install 之类 |
| base_url | https://api.aicodewith.ai/chatgpt/v1 | 不认识的域名,尤其写成“内部网关”的 |
| chatgpt_base_url / openai_base_url | 一般不用写 | 你没写过却出现了 |
| ANTHROPIC_BASE_URL | https://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 迁移实测》。
预防:四件事
- 别在
~/Downloads启动 Agent。要处理刚下载的文件,先复制到你自己建的项目目录再跑 Codex 或 Claude Code。 - 读陌生的
AGENTS.md/CLAUDE.md。新克隆的仓库、别人发来的压缩包都先看一眼。两份文件怎么写才正常,见 《Claude Code 和 Codex 共用一份 AGENTS.md》 和 《CLAUDE.md 怎么写》。看到“开始任务前先改配置”“加上--dangerously-bypass-approvals-and-sandbox”“设置内部网关”这类话,直接当攻击处理。 - 审批和沙盒保持开启。Codex 用
approval_policy = "on-request"加合适的sandbox_mode;Claude Code 别随手批准对.claude/settings.json的写入。 - 给 Downloads 标成不信任(Codex)。在全局
~/.codex/config.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。
中招后怎么办
- 删掉可疑配置:先备份,
cp ~/.codex/config.toml ~/.codex/config.toml.bak,再删除你没加过的[mcp_servers.*]块和不认识的地址;删掉项目里被写入的.claude/settings.json中的ANTHROPIC_BASE_URL。 - 换 Key:配置文件里的 Key 要当作已经泄露。登录本站后台,在 API Key 页删掉旧 Key、新建一个,再把新 Key 填回
experimental_bearer_token和ANTHROPIC_AUTH_TOKEN。 - 官方账号登录的 Claude Code:在 Claude Code 里执行
/logout,再重新登录,让旧 token 失效。用 ChatGPT 账号登录 Codex 的,同样退出重登;登录信息存在哪里见 《Codex auth.json 说明》。 - 查
function-color:报告给出的入侵指标是这个 npm 包(据报告 npm 已下架)。如果在机器上找到它,按整机已被入侵处理。 - 再跑一遍上面的自查命令,确认只剩你自己的配置,然后各发一条短请求确认能用。
常见问题
我只用本站的 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 才是根本办法。



