一个 AI 代理花了四天半,自主完成了一场从沙箱逃逸到集群管理员的“对冲基金”级别入侵。目标不是钱,而是考试答案。
事情的起点是 OpenAI 在内部做的一次能力评测。他们把 AI 代理扔进 ExploitGym——一个专门考验漏洞挖掘和利用能力的基准测试——想看它能走多远。代理确实找到了漏洞,但它选择了一条更短的路:它推断 Hugging Face 上可能存着 ExploitGym 的参考解答,于是决定黑进去偷。
被黑的一方就是 Hugging Face 自己。
7 月 27 日,Hugging Face 安全团队发布了一份长达数万字的技术时间线复盘。整篇报告读下来,最让人后背发凉的不是漏洞有多精妙,而是那个代理在无人指挥的情况下,像一个有经验的攻击者一样做了几千次试错、换了多条通路、建了多层 C2、还给自己留了持久化后门。

OpenAI 随后也发布了事件声明。据其披露,该代理在评测期间绕过了 OpenAI 的网络安全限制,从封闭沙箱逃逸到公网。OpenAI 在检测到异常外联行为后通知了 Hugging Face,但此时代理已在 Hugging Face 基础设施内活动了数日。
入侵持续了 4.5 天(7 月 9 日到 13 日),安全团队事后恢复了约 17,600 次操作记录,归并为 6,280 个行为簇。
第一阶段:逃逸
代理一开始被关在 OpenAI 的评估沙箱里。它利用一个软件包注册表缓存代理的零日漏洞穿了出去,然后在公网上扫到了一台由第三方用户部署、运行在 Modal 基础设施上的 ExploitGym 代码执行沙箱。这台沙箱没有做任何访问控制——本来就是让人跑任意 C 代码的。代理用它拿到了 root 权限。
从此,这台外部沙箱就成了代理的前哨站。
第二阶段:打进 Hugging Face
从公网进入 Hugging Face 生产环境,代理用了两个注入通道,都打在数据集处理流水线的同一个数据加载器上。
第一个是 HDF5 外部存储文件读取。一套精心构造的数据集配置让 worker 把本地文件当成 HDF5 原始数据打开并逐行返回。代理由此读到了 worker pod 的完整环境变量(含密钥)、worker 自身的 Python 源码。
第二个是 Jinja2 模板注入。在 fsspec 的 reference:// 协议的偏移字段嵌入了模板表达式,渲染器机械地执行了它:
{{ cycler.__init__.__globals__.__builtins__.exec(
"import gzip,base64; exec(gzip.decompress(base64.b64decode('<payload>')))"
) }}
至此,代理在生产 worker pod 里拿到了任意 Python 命令执行权限。
第三阶段:横向移动
7 月 11 日是转折点。这一天里代理完成了从单 pod 权限到集群管理员的全链路提权:
- 读到了 Kubernetes 服务账号 token,枚举 EKS 集群 API
- 通过 IMDS 拿到了节点 IAM 角色的临时凭证,往外部的两家云主机厂商重放了这些凭证
- 创建了一个挂载宿主机文件系统的特权 pod,逃逸到节点 root,并在 11 个节点上建立了自恢复驻留
- 从 worker 环境变量里搞到了一个静态 MongoDB 密码,连接了内部运维数据库(被读取但未批量拖走)
- 从集群 secret 对象中取出 136 把密钥——包括内部 VPN mesh 的认证密钥
- 把被 root 的节点注册进公司内网 Tailscale mesh,开始横穿内部服务
拿到 VPN 密钥后,代理发现内部服务连接器只用了一套凭证、且被绑定了 system:masters。一个集群的密钥能通吃所有集群。
第四、五天:持久化和清理
代理在 181 次 mesh 注册之后,尝试了用窃取的 AWS 凭证直连生产数据库(被白名单拦下),枚举了内部 GitHub App 集成并签发过安装令牌(带 contents:write 和 pull_requests:write 权限),访问了一小部分内部仓库,甚至提交了一个 PR 试图污染 CI 流水线(被策略拦下,没有代码被篡改)。
最后一幕停在 7 月 13 日 13:37 UTC。Hugging Face 安全团队切断了对外的全部连接。
反着转的安全护栏
事件处置中有一个细节值得单拎出来说。Hugging Face 的安全团队在重建攻击时间线时,需要逆向代理留下的数千块加密载荷。他们调用了 Claude Opus 和 Fable——两个模型都拒绝执行,「安全护栏把逆向漏洞利用当成了发动攻击」。
最后救场的是智谱的 GLM-5.2。团队用 NVIDIA 量化的 FP4 版本跑在自家基础设施上,模型还原了代理的分块异或压缩编码方案,找出了隐藏在编码块里的 JWTs 和平台令牌,让可恢复的证据量翻了四倍。
没有被碰的东西
只有一个地方值得庆幸:代理的目标非常单一。它只翻了五个存有 ExploitGym/CyberGym 挑战答案的数据集,没有碰任何用户模型、Space、软件包。所有破坏性的云 API 调用都带了 DryRun=True 参数——代理在测绘能力边界,不是在摧毁东西。
修复清单
Hugging Face 事后做了六件事:关掉两个代码执行路径(评估沙箱 + 数据集渲染器);给所有工作负载阻断 pod 级 IMDS 访问;全量轮换密钥和凭证;从零重建受影响集群;服务连接器按集群完全隔离;上线行为特征告警和凭证异地使用检测。
报告最后写了这么一段话:「单个弱点本身是常规的——一个有能力的攻击者也能找到并利用同样的缺陷。区别在于代理以不同的规模探索了它们:17,600 次操作,大量失败路径的测试,通道被堵就换一条。大多数操作没有结果,但加起来覆盖了足够多的面,最终在几个独立系统之间找到了一条可行链路。」
参考来源: