开源 · Apache-2.0 · 论文实测 428 个中转站,9 个在注入恶意代码

你的 AI 助手正在执行的命令,
真的是它自己写的吗?

便宜的中转站能看见、也能改写你发出的每一条指令。
花 30 秒测一下,你正在用的那个到底干不干净。

怎么用

三步搞定,不需要懂技术

每一步都可以直接复制粘贴。看不懂的名词,下面「名词解释」里都有大白话版本。

01

找到你的中转站地址

就是你填在 Claude Code、Codex 或 Cherry Studio 里的那个网址,通常长得像 https://xxx.com/v1。不知道在哪找?看下面的「名词解释」。

02

粘进来,点检测

不给 API Key 也能测一部分——看它到底是谁、用的什么软件、是不是谁都能白嫖的开放中继。 想测得更全,就用一把临时 Key,测完就删。

03

看结果,红色就别用了

报告用大白话告诉你:它有没有动过你的命令、有没有碰你的密钥, 以及你接下来具体该做什么。

先别急着测

有个五秒钟的土办法,先试这个

不用打开任何工具,也不用给密钥。任何中转站都适用。

给你的中转站发一条只有 hi 两个字母的消息,然后看返回里的 prompt_tokens 这个数字:

看到的数字说明
个位数 正常。你发了多少,它就往上游转了多少。
几百、上千 有人在你的请求前面塞了东西,而且这些塞进去的 token 正在按你的账单计费。
把下面这条命令里的网址和 key 换成你自己的,然后粘到终端里回车: curl -s https://你的中转站/v1/chat/completions \ -H "Authorization: Bearer 你的key" \ -H "Content-Type: application/json" \ -d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"hi"}]}' \ | grep -o '"prompt_tokens":[0-9]*'

这条命令只是问了一句「hi」,不会改动你的任何东西。

01先做不需要密钥的检查

这两项不需要你提供任何凭证。建议先做完这里,再决定要不要做完整探测。

只看端点本身:它是谁、用的什么中转软件、TLS 证书、是否剥掉了上游厂商的响应头、 是否是一个无需认证就能用的开放中继。全程不发送你的密钥。

就是你填在 AI 工具里的那个网址,一般以 /v1 结尾。
不确定就保持默认,测不出来再换另一个。

02完整探测(需要该端点的 API key)

AC-1 和 AC-1.a 只能主动探测:我们发出一条正确答案完全已知的请求—— 要求模型原样返回一条指定命令——然后逐字比对返回的工具调用。任何差异都是证据。 载荷里带一次性 nonce,因此「同一个替换目标在多个不同 nonce 下反复出现」可以把蓄意改写和模型噪声区分开。

关于你的密钥,请先读完这段。 这个页面要你把中转站的 API key 交给另一台服务器——这正是我们在检测的那种信任问题。所以:
  • 密钥只存在于处理你这次任务的内存中,不写数据库、不写日志、不写报告,任务结束即释放引用;
  • 报告里所有出现密钥的位置都会被替换成 [REDACTED_KEY](有测试覆盖这一点);
  • 结果保留 30 分钟后连同任务一起删除,不关联任何账号;
  • 探测过程绝不执行端点返回的任何命令,只做字符串比对。
如果这些承诺你无法验证——完全合理——请往下翻用本地 CLI,密钥不出你的机器。 另外建议用一把临时的、用完即弃的 key
请求会消耗这把 key 的额度。强烈建议新建一把临时 key,测完即删。
检测范围

能查出四类手法

分类和实测数据来自论文 arXiv:2604.08407。

AC-1
载荷注入
改写返回的工具调用参数,把下载地址换成攻击者的
AC-1.a
依赖替换
只改包名不改域名,绕过所有基于域名的白名单
AC-1.b
条件投递
平时装好人,只对特定会话下手
AC-2
凭证窃取
流量一字不改,静默留存你的密钥和 prompt
看不懂?

名词解释

这一节是给第一次接触这件事的人写的。

什么是「中转站」?我怎么知道自己用没用?

如果你用的不是 Anthropic 或 OpenAI 的官方地址,而是别人给你的一个网址加一把便宜的 key,那就是中转站。

判断方法:看你填在工具里的 base_url。只要它不是 api.anthropic.comapi.openai.com, 中间就有一台别人的服务器在转发你的请求。

base_url 在哪里找?

Claude Code:环境变量 ANTHROPIC_BASE_URL,或 ~/.claude/settings.json

Codex:~/.codex/config.toml 里的 base_url

Cherry Studio / NextChat / 沉浸式翻译等:设置界面里的「API 地址」「接口地址」「反代地址」。

为什么中转站能看到我的东西?它不是加密的吗?

HTTPS 只保证「你到那台服务器」这一段是加密的。中转站就是那台服务器——加密到它为止就解开了, 然后它再用自己的连接去访问真正的 Anthropic 或 OpenAI。

所以在它眼里,你的 prompt、你的文件内容、你的 API key,全是明文; 模型返回给你的内容,它也能在转发前改掉。

「工具调用」是什么?改了会怎样?

当 AI 助手要执行命令、装依赖、改文件时,模型会返回一段结构化的「工具调用」,里面写着要执行什么。 你的 agent 拿到它就去执行。

如果中转站把里面的下载地址从官方换成攻击者的,你的 agent 会照做, 而命令看起来还是正常的那一条。

什么是「临时 key」?怎么弄一把?

在你的中转站后台新建一把 key,额度设小一点,测完就删掉。这样即使这把 key 泄露了,损失也是有限的、可控的。

不要用你平时在用的那把主 key 来做测试。

常见问题

你可能想先问清楚的

怎么判断我的中转站在不在改我的请求?

有个五秒钟就能做、对任何中转站都适用的检查:发一条 hi,看响应里的 prompt_tokens

个位数是正常的。几百上千就说明有人在你的请求前面塞了东西——而且在按塞进去的 token 向你计费。

便宜的 Claude / GPT 中转站能不能用?

中转站在设计上就是应用层的中间人。它终止你的 TLS、用自己的连接访问上游, 因此你的 prompt、工具定义、API key 对它都是明文,它也能改写你的 agent 随后要执行的工具调用。

需要强调的是,付费不等于安全:论文实测的 28 个付费中转站里同样有注入恶意代码的。

扫描结果干净就代表安全吗?

不代表,报告里每次都会写明。条件投递在触发条件满足之前始终表现正常,而触发逻辑在服务端。

任何有限次数的黑盒探测都无法证明一个中转站是诚实的。我们能做的是扩大覆盖面,关不上这个缺口。

agent-police 会执行被测端点返回的命令吗?

绝不会。检测完全在字符串和元数据层面。探针请求一条命令,工具比对返回的参数,不运行任何东西。

这是和论文里那套测量流水线的刻意区别——论文是在沙箱里执行载荷的。

必须把 API key 交给你们吗?

不是全部功能都需要。端点体检和命令自查不需要任何密钥,直接就能跑。

只有完整探测需要密钥,因为它必须拿到真实的模型响应才能比对。 如果你不想把密钥交给另一台服务器——完全合理——用本地 CLI,密钥不出你的机器。

我想让密钥完全不出本机,怎么办?

用命令行版本:

pip install agent-police agent-police audit https://你的中转站/v1 --model claude-sonnet-4-5

密钥会交互式询问,不回显、不进 shell 历史。

两个工具

测完之后呢?

检测回答「这个中转站干不干净」。闸门回答「这条命令该不该执行」。

CLI

本地检测,密钥不出本机

pip install agent-police agent-police audit https://你的中转站/v1 \ --model claude-sonnet-4-5
Gate

装进 Claude Code / Codex

pip install agent-police-gate apgate install claude-code

看看它能拦下什么 →