← 返回所有文章
发布于 · 作者 Renaud Deraison

最后一步是一句提示

9 月 18 日,Hacktron 公开了他们一路打进 OpenAI 私有单一仓库的链条。起点是一张上传到公开论坛的图片,以及某个图像解码器里的堆溢出,而它在上游的修复没有带任何 CVE。终点是研究人员向某位员工的 Codex 账号发出一句提示,智能体便开了那个 pull request。没有注入,也没有任何东西失灵;智能体只是照着握有会话的人所要求的去做。Bromure Agentic Coding 把这次写入的决定放在会话之外,放在你的 Mac 上。

这条链的最后一步不需要任何漏洞利用。研究人员手里握着某位员工的编码智能体,于是他 们请它在私有单一仓库里开一个 pull request,它就开了一个。

7 月 25 日 UTC 早上六点,Hacktron 的三位研究人员已经在 OpenAI 的公开社区论坛上拿到 了代码执行。到下午早些时候,一个编号 1186742 的 pull request 已经躺在私有单一仓库 openai/openai 里,而他们没有为此写下一行代码。他们问了一个智能体,智能体就把它提 交了。

Hacktron 在 9 月 18 日公开了这条链, 值得一环一环读下去,因为每一环都很平常。研究人员是 Harsh Jaiswal、Mohan Pedhapati 和 Rahul Maini。 The Hacker News 第二天做了报道。

一张图、一次转换,和一个解析器

入口是论坛的图片上传。Discourse 用一个叫 FastImage 的 Ruby 库检查上传的图片,它只读 文件头中足以判断尺寸与格式的部分。FastImage 不懂 HEIF,也就是 iPhone 照片抵达时所用 的容器,于是 Discourse 把这类文件交给 ImageMagick 的 magick 命令去转换。ImageMagick 用 libheif 解码 HEIC,而那是 C 写的。

入口条件就这么多。一种安全检查器不认识的格式被送去转换器,而转换器调用了一个用 「长度字段畸形即内存安全问题」的语言写成的解析器。Hacktron 在 HEIC 解码里找到一个堆 缓冲区溢出,并由此拿到越界读取与写入的原语。

文书工作比这个缺陷本身更糟。上游前一年就修好了那个溢出,却从未把那次提交标为安全修 复。它没有 CVE、没有公告,也没有任何依赖扫描器读得到的变更日志,所以 Debian 从未回 移,而 Discourse 的 Docker 镜像就这样带着完好无损的缺陷,在 Debian 12 上发布 libheif 1.19.7。全世界没有任何扫描器有理由标记那个版本。Debian 后来发布了 DSA-6417-1,这个问题如今挂着 CVE-2026-32882——在有人真的利用它之后才分配的编号。

没人报过的缺陷,你扫不出来。你能事先决定的,是解析器倒下时,它站在什么里面。

一次上传到一个 PR解析一次 HEIC 上传发到公开论坛不需要账号权限FastImage安全的文件头检查不支持 HEIFmagick改由它来转换ImageMagick 调用 libheiflibheif 1.19.7堆溢出,越界读写上游已修,无 CVE、未回移转进代码执行community.openai.com7 月 25 日 06:00 UTC一个 SSO 缺陷论坛会话变成免交互的账号接管某员工的 Codex已连到 GitHub 组织早已获准写入无需利用一句提示PR #1186742私有单一仓库 openai/openai
链上的每一环都很平常。FastImage 不支持 HEIF,于是文件交给 ImageMagick,ImageMagick 调用 libheif,而 libheif 里有一个堆溢出,它在上游的修复没有带 CVE,也从未抵达 Debian。另一个独立的 SSO 缺陷把论坛上的代码执行变成账号访问,再把账号访问变成私有单一仓库里的一个 pull request。只有最后一步不需要漏洞利用:研究人员向一个早已获准 push 的编码智能体发出一句提示。

漏洞利用花了一个晚上

Hacktron 从 7 月 23 日开始看那条上传流水线。7 月 24 日,他们用 Claude Opus 4.8 去攻 那个溢出;按他们的说法,模型在好几个会话里都很吃力,做不出任何能对付地址空间布局随 机化的东西——那是把进程的内存布局打乱、让攻击者无法预测东西在哪里的防御。把堆溢出变 成在 ASLR 之下依然可靠的执行,正是难的那一部分,也正是这类研究会卡上一周的地方。

Anthropic 当晚发布了 Opus 5。Hacktron 开了一个全新的会话,三小时后就有了一个能对本 机 Mac 运行的 ARM64 漏洞利用。他们请模型把它移植到 Discourse 所用的 x86-64 与 jemalloc 配置,并在第二天早上六点确认了通过图片上传达成的本机代码执行。随后他们让 Claude 对自家的 Discourse Cloud 实例跑自主循环。十点时,它在那里也拿到了代码执行, 并读出 /etc/hosts 作为证明。

他们对这件事的意义很谨慎,而这个保留应当放进任何一种解读里:

这并非完全自主的黑客行动。要引导会话、验证结果并处理披露,人类的专业知识依然不可 或缺。

说得对。三位熟练的研究人员把工具对准了目标,而他们的本事并没有一夜之间改变。缺陷也 没变。在那两个会话之间,唯一的新变量是模型,而它把一件屡试屡败的利用工作压到了三小 时。这件事所属的整场行动,让 Hacktron 花掉不到三千美元的 token 费用,以及几个小时的 人力。

这个数字就是规划的输入值。一个从未拿到 CVE、蹲在某个文件转换器传递依赖里的缺陷,如 今只要一台笔记本的价钱就能变成可靠的原语。等公告是一种指望,而没有人能靠把变更日志 读得更快来跑赢那个时钟。

最后一步是一句提示

论坛上的代码执行,并没有给 Hacktron 任何 OpenAI 在意的东西。做到那件事的是第二个问 题。OpenAI 把单点登录接成了这样:只要论坛会话被攻陷,任何用过论坛的员工,其 ChatGPT 与 Codex 账号就会在毫无交互的情况下被接管。用 Hacktron 的话说,正是这个 SSO 问题,把 论坛的失守变成了对 ChatGPT 与 Codex 的访问。

某位员工的 Codex 连着公司的 GitHub 组织,于是研究人员做了最显而易见的事。他们向那个 账号发出一句提示,请它在内部单一仓库开一个 pull request,PR 1186742 便出现在 openai/openai 里。接着他们就收手,没有去读任何源码,提交了报告。

把这一步再读一遍。某个握有有效会话的人请智能体做一件平常的事,智能体就用它本来就有 的写入权限做了。没有注入,没有越狱,没有畸形输入。所有人建起来的每一道控制,都坐在 那个会话的后面:登录、组织成员身份、仓库权限。攻击者一旦握有那个会话,就等于全都握 有。

编码智能体是一份长期有效的仓库写入授权,附着在一段对话上。任何够得着那段对话的人, 都继承那份授权。浏览器里的 Codex 如此,笔记本上的 Claude Code、Codex CLI 或 Gemini CLI 也如此——在那里,智能体在 ~/.git-credentials 里带着真的 ghp_ 令牌,在环境里 带着真的 GH_TOKEN。在笔记本上,入口还会变多:仓库里一个被投毒的文件、一条 issue 评论、包的 postinstall 脚本、一个被劫持的终端。

OpenAI 大约用十四小时修补了论坛。报告在那天早上送进去,OpenAI 在同一天 UTC 22:49 确 认修复完成。Discourse 在周末推出自己的修复,并于 7 月 28 日发布公告 GHSA-vhm9-85gw-x335,赏金共计 6,500 美元。这个形状里落在你自己桌上的那一块,是智能 体。

写入是在哪里被决定的

Bromure Agentic Coding 把「谁可以 push」的答案留在你的 Mac 上,留在智能体的会话 之外,因为会话正是攻击者想够到的东西。那里会发生两件事。

第一,智能体的环境里没有任何可继承的令牌。工作区的虚拟机拿到的是一个诱饵:ghp_ 加 上 36 个字符,形状做得让 gh 和 git 都不会有意见,并且由你真正的令牌经 HKDF-SHA256 与每次安装专属的盐派生而来,因此它在不同会话之间看起来从不轮换。你真正的令牌加密存 放在宿主机上,宿主机代理会在请求离开虚拟机之后,于线路上把它替换进去,而且只在目的 地与该令牌所签发的主机相符时才替换。正如手册所说:虚拟机内部没有任何文件、环境变量 或进程会含有真的 API 密钥、OAuth 令牌、AWS 机密或 SSH 私钥。把那个诱饵带到它不该去的 地方,代理会回 HTTP 451 而一个字节都不转发,并暂停虚拟机,在 Security Timeline 写下 一行红色记录。

第二件,正是这个故事所要的。每一份 git 托管服务的凭据都带着一条写入策略,在 Guardrails 面板里按工作区设置,而新工作区的默认值是写入前先询问。读取一声不响就 过去了。git push 在线路上以 git-receive-pack 的样子抵达,算作写入;对 pull request API 的 POST 也一样。当其中一个抵达时,代理会扣住请求,在你的 Mac 上弹出一 个对话框,上面载的是原样的操作而不是摘要:方法与路径。你可以选允许 15 分钟、 允许一次、允许本会话其余时间,或不允许。拒绝会以一个普通的 API 错误抵达 智能体,它能据此回报,而不是一条挂住的连接。

这个面板自己对运行位置的描述,就是最要紧的那一句:在代理上强制执行,因此虚拟机里被 攻陷的智能体无法绕过。

不管是谁在驾驶智能体——你、埋在 fixture 文件里的提示注入,或者某个握着从你手上夺走 的会话的人——写入都从同一个代理出去,并以同一种方式被归类。你 Mac 上那个对话框就是授 权,而握有你会话的攻击者,并没有握有你的 Mac。

笔记本上的智能体智能体的会话你、注入,或任何夺走会话的人,都够得着真凭据,伸手可及GH_TOKEN · ~/.git-credentials机器上任何进程都读得到POST /repos/org/repo/pulls → GitHub权限由会话承载Bromure 工作区里的智能体虚拟机内智能体的会话ghp_ + 36 个字符的诱饵没有真东西可继承交换机改道 :80 与 :443宿主机代理为它归类POST /repos/org/repo/pulls = 写入git-receive-pack 也算Mac 上弹出对话框,附上原样调用15 分钟 · 一次 · 本会话 · 不允许权限由 Mac 承载
在开发者的笔记本上,智能体握着真的令牌,所以一句提示就够了,权限由会话承载。在 Bromure 工作区里,虚拟机握的是诱饵,宿主机代理在出去的路上把真令牌替换进去,而护栏在写入抵达 GitHub 之前就先归类它。新工作区的默认值写入前先询问,会在你的 Mac 上弹出一个载着原样方法与路径的对话框。不管握着会话的是谁,他握的都不是那台 Mac。

解析器的问题也会来到你的桌上

这条链的另一半同样可以一般化,而把它算进成本里的人并不多。

编码智能体整天都在读自己没写过的文件:跟着仓库一起来的测试 fixture、附在缺陷报告里 的图片、你贴进对话里的截图、一份规格的 PDF、从发布页抓下来的 tarball、一个字体文件、 前端要播放的视频。处理这些东西,意味着去调用 magick、ffmpeg、pdftotext 或 unzip,或者绑进 Python 的某个图像库,而它们每一个都是吃着别人选定的字节的 C 或 C++ 解析器。那正是让一次论坛上传一路抵达 libheif 的条件。智能体碰上这个条件的次数 比你多,因为它在打开任何东西之前从不犹豫。

检测在这里没有答案。libheif 的缺陷在最要紧的那一刻没有 CVE,所以没有任何扫描器、允 许清单或版本锁定会说半个字。你能挑的只有爆炸半径,仅此而已。

在 Bromure 工作区里,那个解码器跑在 Apple Virtualization.framework 之下的 Ubuntu 客 户机中,那是一道 hypervisor 边界而不是进程沙箱,而且那个客户机被 Bromure 在架构上就 当作不可信。图像解析器里的堆溢出,为攻击者买到的是一台 Linux 虚拟机里的 shell:它的 凭据是诱饵,而它通往互联网的路径是宿主机上一组有次序的规则。虚拟交换机按目的地 IP 与从 DNS 嗅探到的主机名,在 TCP 与 UDP 上匹配那组规则,代理再按 TLS 服务器名与 HTTP 方法匹配一次。把未命中的流量设为拒绝,那个 shell 手上就只剩一张允许清单,别无其 他。交换机把 :80 与 :443 改道进代理本身,所以没有任何代理变量可供 shell 取消。规 则的改动不必重启就会抵达进行中的会话,而每一个判定都会落成 Security Timeline 里的一 行 Firewall 记录。

就当解析器一定会倒

这个缺陷在最要紧的那一刻没有 CVE。按解码器会输来规划,并事先决定它倒下时站在什 么里面。

会话不等于授权

任何够得着那段对话的人,都继承智能体的写入权限。把 push 的决定放到对话够不着的 地方。

别在虚拟机里留下可偷的东西

一个工具会接受的诱饵,在上游一文不值;对把它带去别处的攻击者来说,更是连一文都 不如。

给漏洞利用标个价

三小时,加上几千美元的 token。把公告读得更快,回答不了这个数字。

Hacktron 的文章是好研究,也诚实交代了其中有多少仍得靠人类掌舵。明年还会成立的,是结 尾那一段。这条链上的每一道防御,都坐在一个身份的后面;而当带着那个身份的会话易手之 后,它们就全都不再有任何意见了。有人请智能体做事,智能体就照做了。

如果你的智能体能 push,那就问问 push 的权限住在哪里,以及一个把智能体所有东西都夺走 的攻击者,会不会连那份权限一起夺走。在笔记本上,他会。把这一个决定搬离智能体所在的 机器,这条链的最后一步就有了可以停下来的地方。