OpenAI 红队发现 Brotli 解码器未认证 RCE(CVE-2026-111497):Node.js、Bun、Python 库均受影响,上游修复迟到 8 个月
OpenAI 红队发现 Brotli 解码器未认证 RCE,Node.js、Bun、Python 库受影响,上游修复迟到 8 个月。

OpenAI 的红队 Codex Security 在 Google 开发的 Brotli 压缩解码器里找到一个无需认证的越界写入漏洞,可导致远程代码执行,编号 CVE-2026-111497。据 Node.js 官方公告,10 月 21 日发布的 22.23.4、24.22.1、26.12.1 三个安全版修复了它;NVD 次日收录,CVSS 4.0 评分 9.2。真正让影响面扩大的却是时间线:根因修复 2 月 27 日就进了 Brotli 主干,但当时没人把它当安全漏洞,修复版拖到 10 月 21 日才发——中间 8 个月,所有内嵌 Brotli 的软件都带着这个洞。
要点
- Node.js 于 10 月 21 日为 26.x、24.x、22.x 三条线发布安全版 26.12.1、24.22.1、22.23.4,官方定级 High,公告致谢 OpenAI Codex Security 的 Khai Tran 与 Sylvie Mayer。
- 修复 commit 0ed4268a 在 2026-02-27 就合入 Brotli 主干,含修复的版本 1.0.10、1.1.1、1.2.1 迟至 10 月 21 日才发布(GitHub 发布记录可查)。
- 影响面不止 Node.js:Bun 1.4.4、Envoy Proxy、Istio 与 PyPI 的 Brotli、brotlicffi 包在 10 月 22 日至 24 日相继确认受影响;修复清单分别由 OpenAI 的 patchtheplanet.org/brotli(Node、Bun、Envoy、Istio、上游 Brotli)与 Aikido(PyPI 两包)汇总。
背景
Brotli 是 Google 开发的 HTTP 压缩格式,Node.js、Bun 以及大量服务器软件把解码器直接编进发行包,这也是一个上游库缺陷能波及整个行业的原因。OpenAI 在 2 月的红队测试中发现这个缺陷并报给上游,根因修复随之合入,但按 Aikido 10 月 24 日更新的说法,它当时没有被当成安全问题处理,也就没有任何一个版本带着修复发布。10 月 21 日 Google Brotli 一次性发出 v1.0.10、v1.1.1、v1.2.1,Node.js 同日发安全公告;10 月 23 日晚 OpenAI 在 X 上公开归因,并上线 patchtheplanet.org/brotli(OpenAI Daybreak 项目),给出受影响软件、修复版本和缓解步骤。AI 挖洞正在成为常规操作:此前 XBOW 用 GPT-5.6 六天拼出 Chrome 全链利用,拿下谷歌 25 万美元满额赏金。
漏洞原理
按 Node.js 官方公告的描述,缺陷出在解码器处理无效块切换的方式:本应判定为格式错误的输入被当成「还需要更多数据」,流式解码器于是持续向一个 8 字节的内部缓冲区追加输入,写成越界。攻击者只要能让应用解压他控制的 Brotli 数据就可能得手——Aikido 列了三条常见路径:Express 5 与 body-parser 2.x 会解压带 Content-Encoding: br 的请求体;fetch() 会自动解压响应,恶意或被入侵的上游服务器借此打到你的服务;以及直接调用 node:zlib 的代码。后果从进程崩溃、内存泄露到执行代码。NVD 记录写明受影响范围是 Google Brotli 1.0.3 至 1.2.0,全平台。
影响面与修复版本
下表汇总的是 10 月 23 日 patchtheplanet 与 10 月 23/24 日 Aikido 给出的修复清单:
| 项目 | 受影响 | 修复版本 |
|---|---|---|
| Node.js | 26.x / 24.x / 22.x 旧补丁级别 | 26.12.1 / 24.22.1 / 22.23.4(10-21) |
| Bun | 1.4.4 之前版本 | 1.4.4(内含 Brotli 1.2.1,10-22) |
| Envoy Proxy | 配置了 Brotli 解压的部署 | 1.40.0 / 1.39.3 / 1.38.6 / 1.37.8 |
| Istio | 配置了 Brotli 解压的网格 | 1.29.9 / 1.30.6 / 1.31.2 |
| Google Brotli 上游 | 1.0.3 – 1.2.0 | 1.2.1(旧线 1.0.10 / 1.1.1) |
| PyPI Brotli 包 | 1.2.0 及更早 | 1.2.1 |
| PyPI brotlicffi 包 | 1.2.0.x | 修复版本号待官方核实 |
Python 是 10 月 23 日至 24 日新确认的一层:requests、httpx、aiohttp 这类 HTTP 客户端在环境里装了 Brotli 或 brotlicffi 时会自动加载解码器,Aikido 给出的数字是 Brotli 包月下载 8280 万。更麻烦的是扫描缺口——截至 10 月 23 日,漏洞库尚未把该 CVE 映射到这两个 PyPI 包,pip-audit、Dependabot、Safety 都查不出来。
各方说法
严重度出现了两套标注:Node.js 官方公告定级 High,NVD 的 CVSS 4.0 第二评分给出 9.2 Critical,两者并存,引用时需各自注明出处。PoC 的进展 Aikido 写得最细:10 月 22 日公开的首个概念验证只在刻意弱化的测试构建上跑到代码执行;同日有研究者称在未修改的 Node.js 24.22.0(Linux arm64)上跑通,但并非每次尝试都成功。Aikido 还汇总称,截至 10 月 22 日没有在野利用的报告。Aikido 的 Dania Durnas 在 10 月 23 日的更新里把事件从 Node2Shell 改口为 HTTP2Shell,理由是所有走 HTTP 的库和应用都可能暴露。Bun 官方 1.4.4 博客只写了「TLS、WebSocket、数据库客户端与包管理器的安全修复」,Brotli 出现在受影响协议列表里,没有点名这个 CVE——Bun 受影响的链条以 patchtheplanet 页面和 Aikido 的说法为准。
缓解与自查
patchtheplanet 给的过渡方案是停用对不可信数据的 Brotli 解压:Envoy 移除 Brotli 解压过滤器(保留 gzip 和 zstd);Python 客户端的 Accept-Encoding 只留 gzip/deflate,并在解码前拒绝 br 响应。Aikido 提醒只改 Accept-Encoding 不够——恶意服务器照样能发 Brotli 响应,urllib3 按响应头选解码器。自查按三步走:node --version 核对主机和容器内的运行时;docker run --rm <镜像> node --version 逐个查镜像;Python 环境查 pip show brotli brotlicffi。Node 侧升级后要重建容器镜像,钉死旧 tag 的镜像不会自动变干净。
编辑判断
这件事对两拨人最急迫:跑 Node/Bun 服务的团队今天就该核对版本并重建镜像;Python 服务要核对 Brotli 与 brotlicffi。诚实地说,坑还不少——扫描器现在查不出 Python 包,brotlicffi 的修复版本号在 Aikido 页面上渲染为占位符,成稿时无法核实;Debian、Alpine 这类发行版包可能链的是系统 Brotli,修复走发行版公告而不是 Node 版本号。这次修复滞留 8 个月,和 Rust 借用检查器那个存活 11 年的 soundness 漏洞 是同一类病:上游修了,下游没人知道要跟着走。另外,PoC 公开后探测器只会来得更快——cohttp 的修复 PR 公开 10 分钟即遭探测(8 月的事)。还没升级又暂时动不了的服务,把 Brotli 从解码路径里关掉是目前唯一靠谱的过渡措施。