Security Blog

您把工作拆分给了十三个 agent。Paperclip 却没有拆分密钥。

#173

October 2, 2026 · By Marketing team

← All posts

对一个拥有 71,000 星标的 agent 框架的一次扫描发现,其十三个 agent 中有十二个携带同一个明文令牌。一旦您运行的是一支 agent 集群,“密钥放在配置里”就不再是一条捷径,而是一个放大器。

您做了当下流行的事。您没有搭建一个大型 agent,而是组建了一支 agent 集群——一个负责工单分派,一个撰写文案,一个运行设计流水线,十来个 agent,各有各的职责,也各有各的配置。这样看起来更安全。爆炸半径更小。最小权限落实得更彻底。

然后,一次安全扫描逐一检查了一个名为 Paperclip、拥有 71,000 星标的 agent 框架的配置,发现其十三个 agent 中有十二个携带了同一份凭据——一个完全相同的令牌,以明文粘贴进每个 agent 的配置中 [1]。一个 Anthropic API 密钥以明文硬编码在某个设计 agent 的配置里。一个原本只属于某个 agent 的 bot 令牌,对与它无关的 agent 也清晰可读。

十三扇门。同一把钥匙,复制进了其中十二扇。从最薄弱的那个 agent 手中把它偷走,其余十一个便一并到手。

实际发生了什么

Paperclip 为每个 agent 提供一份 MCP server 配置——这份文件告诉 agent 它可以访问哪些工具和服务,以及如何向它们完成身份验证。不知从何时起,密钥以字面文本的形式直接写进了这些文件:一个 n8n JWT、一个 bearer 令牌、一个 Anthropic API 密钥。不是被引用。不是在运行时注入。而是敲进去的——然后,由于启动下一个 agent 只是一次复制粘贴,它就这样在整个集群中被复制开来。

扫描标记了三处问题。十二个 agent 之间共享的明文令牌(评级 HIGH)。设计 agent 配置中明文存放的 Anthropic 密钥(评级 CRITICAL)。以及一个授予了本不应访问它的 agent 的 bot 令牌——典型的最小权限缺失 [1]。值得肯定的是,Paperclip 团队反应迅速:他们迁移到了凭据引用,在跨 agent 读取时对配置做脱敏处理,并开始强制执行绑定同步 [2]。方向是对的。

这不是 Paperclip 的疏忽

有一部分值得细细想。Paperclip 做的是几乎所有框架都会做的事。把密钥放进配置文件,是软件三十年来的认证方式。它之所以行得通,是因为只有一个应用、一份配置、一个知道密钥存放在哪里的操作者。

时代在这一习惯之下改变了。多 agent 系统不是“一个应用加一份配置”——而是十几个进程,每个各有一份文件,每一份都是上一份的副本。当泄漏点只有一处时,明文写在配置里尚可容忍。到了十三处,同样的捷径就意味着一次泄漏等于十三次泄漏——而“是哪个 agent 干的?”没有答案,因为日志里的那个令牌属于它们全体。

凭据引用——Paperclip 上线的修复——确实更好。但请注意它改变了什么,又没改变什么。引用最终仍会在 agent 运行的地方解析为真实的密钥;agent 本身,或任何攻陷了它的东西,仍然能读到解析后的值。而且该框架自己的缺陷跟踪器已经显示出下一种失效模式:引用与其绑定失去同步,于是配置看起来已被填充,校验却悄然失败 [3]。密钥向后挪了一层。它并没有离开这栋楼。

这不只是 Paperclip 的问题

同一周,同一个根因,不同的代码仓库。一个被广泛使用的编码 agent 被报告会把原始的 .env 值——密码、令牌、API 密钥——直接打印到对话输出中。另一个 agent runner 被发现会把完整的父级环境传给子进程,于是每个服务商的密钥对子进程都可见 [4]。一个语音 hook 把完整转录(连同其中的凭据)写进了任何人可读的 /tmp [5]。彼此独立的团队,独立的威胁模型,共享着同一个假设:密钥放在 agent 看得见的地方没有问题。攻击者要做的,不过是证明这个假设不成立。

为此而生,有意为之

Clavitor 从相反的假设出发:agent 根本不持有凭据。它请求执行某个动作;请求被拦截,对照一个 agent 读不到的密钥完成认证,然后才被放行。没有可以粘贴令牌的配置,因为配置里没有令牌。没有东西需要在十三个 agent 之间复制,因为 agent 的环境中从不存放值得偷走的东西。

每个 agent 只能触及自己被指名授权的范围——而不是整个密钥库——因此 bot 令牌不会落到一个从未请求过它的 agent 手里。每个动作都被记录到实际执行它的具体主体上,而不是记到十二个 agent 共用的某个令牌上——所以“是哪一个干的?”有答案。

需要诚实说明的边界:这并不能让 agent 免于被攻陷。一个被攻陷的 agent 仍然可以在当下执行它被授权执行的动作。它做不到的是带着密钥走开、变成其余十二个——因为它手里根本没有可以带走的密钥。

教训不是“轮换该令牌”

Paperclip 会轮换令牌、完成迁移、关闭 issue。很好——他们应该这样做。但轮换不是教训。教训是:一旦您拥有的是一支 agent 集群而不是一个应用,“密钥放在配置里”就不再是一条捷径,而是一个放大器。把密钥弄得稍微难读一点,并不能修复一个放大器。要修复它,就得确保密钥从一开始就不曾落到 agent 手中。

我们写下了我们认为一个凭据工具在 agent 时代应当遵守的规则——其中包括:密钥绝不存在于代码运行的地方,以及 agent 只能触及被指名授权的范围。用您自己的方案对照检查一遍:clavitor.ai/rules。

Clavitor(@clavitorai)是为 AI agent 而建、同时也是防备 AI agent 的凭据保险库。clavitor.ai

来源

[1] Paperclip agent framework —— 凭据卫生检查结果(CFG-H1 共享明文令牌、CFG-C1 硬编码的 Anthropic 密钥、CFG-H2 授权范围错误的 bot 令牌):https://github.com/paperclipai/paperclip

[2] Paperclip —— 在生命周期流程中强制执行 agent 密钥绑定同步(已合并):https://github.com/paperclipai/paperclip/pull/8307

[3] Paperclip —— secret_ref 环境条目可能与 secret_bindings 记录失去同步,配置看似已填充但校验悄然失败(#8309):https://github.com/paperclipai/paperclip/issues/8309

[4] Chetter —— runBatchAgent 继承完整的 runner 环境,使服务商 API 密钥暴露给子进程(#56):https://github.com/flatout-works/chetter/issues/56

[5] Claude Code voice hook —— 完整转录(含凭据)被写入任何人可读的 /tmp(#58):https://github.com/rodlaneedu-hash/claude-code-voice-hook/issues/58