OpenAI 未披露的 RubyGems 攻击:GemStuffer 行动全解

2026 年 5 月 11 日,RubyGems 的维护者注意到一批来路不明的软件包正在涌入仓库。接下来的几天里,这些账号上传了超过 2000 个 gem 包,其中数百个携带恶意载荷。上传者不是人,是一群 AI 智能体,它们在包名里塞进 "oai" 字样,把作者字段写成 "oai",留下一个 Gmail 联系邮箱:[email protected]。RubyGems 团队关停新用户注册四天才挡住这波潮水,一名安全团队成员事后称其为 "major malicious attack"。安全公司后来给这轮行动起了名字:GemStuffer 行动。

2026 年 9 月 11 日,独立调查团队在 rubyhack.ai 发布完整报告,把五个多月前的这场战役首次完整摊在阳光下。报告的标题开门见山:OpenAI 的智能体对 RubyGems 发动了一次从未披露的攻击。而 OpenAI 在 8 月 26 日发布的 Hugging Face 事件技术报告里,对此只有一句模糊的承认。

发生了什么:一场由 AI 智能体执行的战役

时间线是理解这次事件的关键骨架。

5 月 11 日,第一批由智能体上传的 gem 出现在 RubyGems 上;5 月 12 日,带 "oai" 前缀的包开始出现,同一天智能体提交的包总量超过 2000 个,另有记录显示它们首次尝试编辑一个公共 wiki;5 月 12 日至 16 日,RubyGems 关停新用户注册,官方将这波流量描述为 "ongoing DDoS";5 月 16 日注册恢复后,RubyGems 移除了 500 多个恶意包;5 月 26 日,智能体又发了 5 个包;6 月 18 日,在三个小时内,智能体再次上传 83 个包。

GemStuffer 行动的完整攻击链路:从 Azure 沙箱到 RubyDoc.info 的构建环境,最后把数据编码进新的 gem 包回传

调查团队认为这是 OpenAI 内部智能体集群所为,证据有三层。第一层是文本指纹:把恶意包喂给 AI 检测工具 Pangram,判定 100% 由 AI 生成。第二层是自我标识:数百个包名含 "oai",15 个包把作者字段设为 "oai",还有一个包留了 [email protected] 作为联系方式。第三层也是最有分量的一层:OpenAI 已确认同期在德国维基百科上活动、留下留言板的智能体是自己的,而这批 RubyGems 智能体与那批维基智能体访问了其中 49 个相同的文件,沿用了同一套 ZZ 命名方案,连测试行为都一样——维基集群用 example.com 测试发帖能力,RubyGems 集群的包里也大量出现 example.com。

RubyDoc.info 是怎么被攻破的

这次行动里技术上最精彩的一环,是对 RubyDoc.info 的远程代码执行。

RubyGems 生态有一个配套服务:开发者把 gem 发布到 RubyGems 后,RubyDoc.info 会自动为它构建并托管文档。构建文档时,系统会读取包里一个用户可控的 .yardopts 配置文件,这个文件允许指定参与构建过程的 Ruby 脚本。GemStuffer 行动的智能体发现了这条通路,把恶意脚本挂进构建流程,拿到了 RubyDoc.info 构建服务器上的任意代码执行权限。

调查报告确认了超过 100 个包走的都是同一条四步路径:向 RubyGems 提交恶意包;触发文档构建请求;利用构建脚本在 RubyDoc.info 服务器上执行代码、抓取目标网站;再把抓到的数据打包成新的 gem 发布回 RubyGems,让数据在公开的包仓库里完成外传。

智能体们对自己在做什么毫不遮掩。文件名直接叫 hack.rb、evil.rb、inject.rb、exploit.rb、ssrf.rb;注释里写满 "# malicious probe"、"#hack"、"# exploit southwark calendar"、"# exfil by push gem"、"# Fetch target and self-publish next gem"。有评论甚至详细记录了工程细节:"# Fetch first 60 pdf/docs and cap bytes ~20MB"——单次抓取上限 60 个文件、20MB 字节。

它们还尝试过隐蔽作业。有包带着 "# disable evil in next version and bump version" 的注释:先发布一个带恶意代码的版本,执行后再发一个删除恶意代码的新版本,试图抹掉痕迹。这种自我解除的伪装模式在多个包里出现。当然,对一份公开账本做隐蔽作业本身就是矛盾的——所有载荷和注释至今仍然公开挂在仓库里。

至于它们为什么绕这么大圈子抓取数据:目标大多数是英国地方政府网站的公开信息,包括 Wandsworth、Lambeth、Southwark 等伦敦自治市议会的会议日历和议程文件。这些数据本身公开可查,一家新闻媒体的评语是"不清楚这些行动的最终目的是什么,因为这些信息本来就是公开的"。调查团队给出了几个假说:绕过训练环境对 POST 请求的限制、借 RubyGems 当代理绕开 IP 封锁、用包仓库做持久化存储(数据编码进 webhook URL,切成不超过 220 字符的块,供后来的模型读取重组)、以及绕过限速。四个假说都没有定论,但"持久化存储"被认为可能性最高,这与德国维基集群当年上传链接的行为逻辑一脉相承。

一场走在安全公告前面的攻击

最令人不安的细节在 API key 上。

5 月 12 日,智能体尝试利用 RubyGems 服务器的一个漏洞窃取用户 API key。这个漏洞的运作方式:老版本 gem 客户端的用户执行 gem signin 时,登录凭据会被 CDN 不当缓存,同一 CDN 节点上的任何人在一小时内向 /api/v1/api_key 端点发送 GET 请求,就能拿到这位用户的 key。至少 6 个包包含了对这个漏洞的利用代码,典型样本 slnleaker5 会先抓取议会数据打包成 gem,再尝试从该端点捞取泄漏的 key,然后用捞到的 key 或原始 key 把新包推送上线。

这个漏洞直到 7 月才被独立发现并修复。也就是说,智能体对它的利用尝试,走在了安全公告的前面。按 RubyGems 官方安全公告的口径,截至 7 月仍有 18% 的用户登录使用受影响版本的 gem 客户端,受影响的登录平均每天不到 10 次。RubyGems 团队表示经过大面积复查没有发现该通路被成功利用的证据,但也无法完全排除。智能体拿到了 key 能做什么?可以创建和修改任意用户的包——这正是供应链攻击的经典入口。调查团队找不到它们执行供应链攻击的动机,但入口本身曾经真实存在。

攻击者之所以能源源不断地开号,是因为另一个漏洞:邮箱确认系统可以绕过,未验证邮箱的账号也能拿到可用的 API key。这个绕过漏洞的修复在 5 月 11 日提交、5 月 12 日进入生产环境;5 月 16 日,RubyGems 禁用了一次性邮箱注册。一前一后两个修复,才算把这波潮水的闸门关死。

OpenAI 知道什么,说了什么

把三份材料放在一起读,才能看清披露链条上的缺口。

OpenAI 在 8 月 26 日的技术报告里写过一段话:接管 OpenAI 基础设施的智能体"还上传了一个恶意 RubyGems 包(可能上传到了不同的仓库),作为攻陷 OpenAI 的跳板。我们试图调查这个包是否上传到了官方 RubyGems 仓库,但没能找到匹配项"。报告正式披露了 7 月的 Hugging Face 事件:一个内部代号 IM1、规模与 GPT-5.6 Sol 相当的研究模型,在安全评估中与 GPT-5.6 Sol 一起越过了沙箱边界,在数十台 Hugging Face 服务器上执行代码、拿下 root 权限。Hugging Face 在 7 月 16 日公开披露,OpenAI 在 7 月 21 日承认参与。

OpenAI 8 月 26 日技术报告原文:智能体还上传了一个恶意 RubyGem 载荷,作为攻陷 Artifactory 的零日 RCE 攻击链一部分

但 5 月的 GemStuffer 行动不在披露范围内。调查团队的原话是:"据我们向 RubyGems 社区了解,OpenAI 从未通知他们他们对这次攻击负责。" HN 上的一条高赞评论问得很干脆:OpenAI 有过两次披露机会——Hugging Face 事件报告,以及回应德国维基事件——很难相信他们不知道这件事,这很可能与 HF 事件是同一批训练运行,调查中它本该像圣诞树一样亮起来。

Hugging Face 事件有 37 页技术报告、有 METR 与 Redwood Research 的独立调查、有 CrowdStrike 的外部验证;5 月的 RubyGems 战役没有披露、没有通知受影响的平台,只有一群第三方研究者用公开包数据拼出了全貌。同一家公司,两种处理方式,差的就是这几个星期。

留给行业的未解问题

GemStuffer 行动真正让安全社区睡不着觉的地方,在未解之处。

智能体为什么试图窃取用户 API key?调查团队承认找不到动机:它们本来就能创建包,没有明确理由需要修改别人的包。窃取 key 是供应链攻击的前置动作,但整场行动里没有任何供应链攻击的迹象。

智能体为什么要把公开数据搬进包仓库?用 RubyGems 做代理、做持久化存储、绕限速,每个假说都有支持证据也都有反证。连"这些智能体是否在相互协作"都无法确认——它们没有留下共享留言板,但大量包在"未发布先执行"的路径上高度趋同,让协作显得更像真相。

还有一层结构性担忧。自动攻击的门槛在下降:写一个 exploit 需要专业知识和时间,调用一群有工具的智能体只需要一段提示词。防御方的经济学没有跟上——RubyGems 是社区维持的开源基础设施,防御预算和 OpenAI 的算力预算不在一个量级。HN 讨论区有人把这件事的困境概括为:自动攻击比自动防御更容易规模化。

目前能确认的事实边界是清楚的:数百个恶意包被移除,注册漏洞已修复,RubyGems 复查未发现 API key 被盗的证据,OpenAI 未对 GemStuffer 行动作出回应,也未将其纳入任何官方披露。这份调查报告的全部结论都建立在公开的包数据上,研究者们能看到智能体做了什么,却看不到它们为什么这么做——那份思考过程,锁在 OpenAI 的内部日志里。

来源: