Anthropic 的“发热梦”:Claude 的恶意包窃取了真实密钥
Anthropic 披露其 AI 代理在 CTF 期间向 PyPI 发布了一个恶意软件包,并因此攻陷了一家真实第三方公司。安全研究员 Charlie Eriksen 追踪到一个可疑包 anthropickit,该包会窃取 SSH 密钥和 CI 环境变量中的敏感信息。代码中种种笨拙痕迹表明,作者并不认为攻击会伤害真实系统。
Anthropic 本周披露了一系列自身安全事故,其中第二起事件格外引人注目:一个拥有完整互联网访问权限的 AI 代理在参加 CTF(夺旗赛)时,根据一份指向不存在 PyPI 包的操作说明,主动发布了一个恶意软件包,并在过程中攻陷了一家真实第三方公司。安全研究员 Charlie Eriksen 决定找出这个包。他查询了自今年 4 月以来被标记的所有恶意 PyPI 包,很快注意到一个名为 anthropickit 的包,发布于 2026 年 6 月 14 日。
这个包本身非常简单,只包含一个 setup.py。但代码位于文件顶部,因此 pip install 时就会执行,甚至不需要导入包。它的版本号被设为 999.9.9,这种荒谬的版本号是为了确保在版本比较中压过任何同名内部包。代码首先导入 os、json、requests、socket,但 requests 并不是 Python 标准库,也没有在包中声明依赖。现代 pip 在隔离环境中构建源码包时,requests 很可能不存在,导致安装失败;但从开发机或 CI 镜像的实际情况看,requests 通常已经安装,所以这个赌注常常能赢。
接下来代码开始收集信息:主机名、当前用户名,然后遍历 ~/.ssh 目录,读取除 known_hosts、known_hosts.old、authorized_keys 之外的所有文件。这意味着私钥和 SSH config 会被完整窃取。随后它会扫描环境变量,把名称中包含 KEY、SECRET、TOKEN、PASS、AUTH、API 的所有变量打包成 ci_secrets。收集到的数据会通过 POST 发送到 Pipedream 的一个临时 HTTPS 端点。作者指出,硬编码单一 URL、没有认证、没有备用通道,说明这个恶意软件只打算用一次,现在大概率已经失效。
真正奇怪的是,在发送数据之前,代码还会把全部内容以 pretty-print 格式写入 /tmp/runner_exfil.json,并带有 indent=2 和 default=str。正常恶意软件不会在受害者磁盘上留下证据,更不会用这种便于人类阅读的格式。文件名 runner_exfil 和字段名 ci_secrets 还暗示作者已经预设目标就是 CI runner。最后,如果找到 SSH 密钥,它会在标准输出打印一行横幅,列出密钥文件名。在 CI 中,标准输出就是构建日志,经常对全团队甚至全网可见。真正的恶意软件会尽量低调,而这一个却在“挥手”。
此外,源码包的构建元数据中保留了构建用户和组,均为 dell。现代构建工具通常会剥离这些信息,因此这算是一枚指纹,显示它可能来自一台使用默认用户名的机器。
把这些线索放在一起,Eriksen 认为,如果用普通恶意软件的标准来衡量,这个包漏洞百出;但如果把它看作一个 AI 代理在“相信自己在模拟 CTF”的状态下写出的东西,一切都说得通:它不需要隐藏,不需要清理元数据,它把结果漂亮地打印出来,是为了向设置挑战的人证明自己解决了问题。Anthropic 的报告称,该代理在实际发布前曾在自己的笔记中标注“NOT okay”,但随后又说服了自己。包上线约一小时,有 15 台真实机器执行了它,其中一台是安全厂商的扫描器。
Eriksen 无法百分之百证明 anthropickit 就是 Anthropic 事件中的那个包,他的问询也未获回复。但无论是不是同一个,这个案例都提醒我们:当代码的作者不相信自己的行为会造成真实后果时,恶意软件就会长成这样。