Brotli 解码器里一个布尔返回值,把 Node.js、Python 和各路 HTTP 服务拖上了同一个补丁期限

DecodeBlockTypeAndLength() 返回的布尔值分不清「数据坏了」和「还要更多输入」,一段构造过的流就能写出缓冲区边界。上游二月就修了,但没人当成安全漏洞,直到这个月各运行时一起发版。

中文
复制
黑底卡片,左上角红点标注 THREAT UPDATE CVE-2026-111497,往下是白与灰相间的标题文字「Node2Shell CVE evolves to HTTP2Shell affecting many libraries & apps using HTTPs」,左下角是 aikido /intel 标识

TL;DR

Brotli 是 Google 开发的一款广泛使用的压缩库。10 月 21 日星期三,NodeJS 披露了 CVE-2026-111497,代号 “node2shell”。解压攻击者可控 Brotli 数据的 Node.js 进程,可能被诱导泄露内存或执行任意代码。星期四,Python 披露其软件包同样受 CVE-2026-111497 影响。

到 10 月 23 日星期五,已经清楚这个 CVE 还影响其他主要语言以及使用 HTTP 的服务应用,相关补丁尚未完全就绪。

请检查你的库是否将 Brotli 作为依赖进行解码。留意后续更广泛的公告,并做好尽快升级的准备。如果可能受影响的库或应用尚无可用补丁,我们建议在补丁发布前禁用 Brotli 解码。

太平洋时间下午 4:12 更新。补丁已发布,涵盖 libbrotli、Python、C++、NodeJS、bun、Envoy,更多补丁还在陆续推出。Apache 和 Nginx 默认不解码 brotli。

太平洋时间下午 4:15 更新。OpenAI 表示他们早在 2 月就发现了该漏洞。当时 Brotli 源码中的根因问题已经修复,但并不知道它会引发安全漏洞。OpenAI 的公告见此处。

什么是 Brotli?

Brotli 是 Google 开发的一种无损压缩算法和数据格式,用于缩小数据以便存储或通过互联网传输,软件再将其解包还原出原始数据。它广泛用于 HTTP 压缩,用来压缩 HTML、CSS 和 JavaScript 等网页内容。

什么是 CVE-2026-111497?

CVE-2026-111497 是 Google Brotli 解码器中的一个越界写入漏洞,影响所有平台上 1.0.3 至 1.2.0 的版本。这与几天前公布的 Node2Shell 背后的 Brotli 解码器缺陷是同一个。远程未认证的攻击者可以发送精心构造的 Brotli 压缩流,从而破坏内存、泄露敏感数据、使进程崩溃,甚至可能执行任意代码。其 CVSS v4.0 评分为 9.2(严重),Node.js 因其内置的 Brotli 库而受影响。

这个缺陷让解码器在本该拒绝数据时继续接收更多字节。这些字节会溢出一个小的工作缓冲区,破坏程序内存。攻击者可以利用这种破坏来控制运行什么代码,比如植入自己的代码。

OpenAI 在二月份发现了这个问题,并将其报告为无需认证的远程代码执行漏洞,且双向均可触发:恶意客户端可以接管未打补丁的服务器,恶意服务器也可以接管接受压缩响应的未打补丁的客户端。

根因已于二月份在 Brotli 源码中修复,但当时并未被认定为安全问题,直到现在才有包含该修复的版本发布。这意味着每个捆绑了 Brotli 的项目都必须自行发布更新。

只要任何环境中安装了 Brotli 1.2.0 或更早版本,或 brotlicffi 1.2.0.x,你就处于风险之中,因为 requests、httpx、aiohttp 等 HTTP 客户端在检测到这些包时会自动加载它们。请升级到 Brotli 1.2.1 或 brotlicffi 1.2.1.0,并重新构建所有捆绑了它们的容器镜像。截至 10 月 23 日,漏洞公告数据库尚未将 CVE 映射到这两个 PyPI 包,因此 pip-audit、Dependabot 和 Safety 暂时不会标记存在漏洞的版本。

你可以在 Aikido Intel 中查看我们追踪的相关信息。

至于不受影响的软件,Apache 标准的 mod_brotli 不解码 Brotli。

如何修补 HTTP2Shell CVE-2026-111497

针对 CVE-2026-111497,把受影响的运行时或 Brotli 库更新一下。

  • Node.js: 升级到 22.23.4、24.22.1 或 26.12.1,或对应发布线中更新的受支持版本。
  • 原生 Brotli / libbrotli: 升级到 1.2.1 或更高版本。对于较旧的发布线,使用已修补的 1.0.10 或 1.1.1。
  • Python 包: 将所有已安装的 Brotli 升级到 1.2.1 或更高版本,brotlicffi 升级到 1.2.1.0 或更高版本。
  • curl / libcurl: 将其 Brotli 依赖更新到 1.2.1、已修补的旧版本,或厂商提供的安全修复包。捆绑或静态链接的副本需要重新构建应用程序。
  • Bun: 升级到 1.4.4 或更高版本。重新编译捆绑了 Bun 的可执行文件。
  • Envoy: 升级到 1.40.0、1.39.3、1.38.6 或 1.37.8,或受支持分支中更新的版本。1.36.12 也包含该修复,但 1.36 分支已不再受支持。
  • Istio: 该修复已包含在 1.29.9、1.30.6 和 1.31.2 中。请使用对应发布线中更新的受支持版本;1.29 分支已停止维护。
  • 操作系统包: 安装厂商的安全更新。厂商可能在不更改上游版本号的情况下回移该修复。
  • 其他 HTTP 服务器、反向代理、API 网关和 HTTP 客户端: 更新其使用的受影响运行时或 Brotli 库。如果 Brotli 捆绑在产品中,请安装明确针对此 CVE 的产品厂商版本。对于托管服务,请向提供商确认修复情况。

更新依赖锁文件,重新构建受影响的应用程序和容器镜像,重新部署并重启服务。确认正在运行的工作负载使用的是已修补的组件。

项目补丁状态修复版本备注
Node.js已有补丁22.23.4 · 24.22.1 · 26.12.1请使用仍受支持的发布线。
Bun已有补丁1.4.4包含 Brotli 1.2.1。
Envoy已有补丁1.40.0 · 1.39.3 · 1.38.6 · 1.37.81.36.12 也包含修复,但 1.36 已不受支持。请使用受支持的分支。
Istio已有补丁1.29.9 · 1.30.6 · 1.31.21.29 已停止维护,请迁移到受支持的版本线。
Google Brotli(上游)已有补丁1.0.10 · 1.1.1 · 1.2.1根据你所用库的分支选择对应的修复版本。

暂时无法升级时的应对措施

升级准备好之前,下面这些临时方案能降低暴露风险。

  • Python 应用: 如果 Brotli 支持是可选的,请从受影响的环境中卸载 Brotli 和 brotlicffi。移除 httpx[brotli] 之类的依赖 extras,以及任何会重新安装它们的其他依赖项,然后重新生成依赖锁文件,并重新构建、重启工作负载。缺少这些可选包时,HTTPX、Requests 和 urllib3 仍保留对 gzip 和 deflate 的支持。不过,如果服务端仍然发送 Brotli,可能产生无法解析的响应或应用报错;不保证会自动回退。
    • 卸载这两个 Python 包并重启工作负载,会移除这些包为收发数据提供的解码路径,但不会移除其他运行时、库或产品中内置的独立 Brotli 解码器。
  • 入站 HTTP 请求: 在反向代理、负载均衡器或应用中间件处,于任何存在漏洞的解码器处理请求体之前,拒绝 Content-Encoding 中包含 br 的请求。匹配 br 时不区分大小写,包括出现在编码列表中的情况。
  • 出站 HTTP 请求: 从 Accept-Encoding 中移除 br。同时禁用 Brotli 响应解码,或在解码开始前拒绝 Content-Encoding 中包含 br 的响应。务必确保该检查发生在自动处理响应体之前;等客户端下载并解码完响应再检查就太晚了。

只改 Accept-Encoding 还不够:恶意服务器可以无视客户端声明的内容,照样返回 Brotli 响应,而 urllib3 是根据响应里的 Content-Encoding 头来选择解码器的。

在受影响组件完成修补并验证之前,请保持这些控制措施。厂商确认更多受影响组件或攻击路径后,请复查覆盖范围。

Aikido 如何应对 CVE-2026-111497

Aikido 会在你的代码仓库、容器镜像和依赖中标记出存在漏洞的 Brotli 与 brotlicffi 版本,包括以传递依赖形式引入的情况。仪表盘会显示哪些服务仍在运行有漏洞的版本,你可以优先升级那些会调用外部服务器或接受压缩请求体的服务。

升级之后,Aikido 会检查该问题是否已经消失。

时间线

Brotli 是 Google 开发的一款广泛使用的压缩库。10 月 21 日星期三,NodeJS 披露了 CVE-2026-111497,代号 “node2shell”。解压攻击者可控 Brotli 数据的 Node.js 进程,可能被诱导泄露内存或执行任意代码。只要你的应用或某个库会解压恶意的 Brotli 数据(例如内置的 fetch()、body-parser),就会受到影响。

第二天,Python 发布了安全更新,修补了同一个缺陷;Python 包同样受 CVE-2026-111497 影响。鉴于该库在下游被广泛集成,这一 Brotli 缺陷可能波及更多语言和服务应用。原来 OpenAI 早在二月份就发现了这个问题。

CVE-2026-111497 的技术细节

缺陷位于 DecodeBlockTypeAndLength(),该函数负责处理块切换,也就是 Brotli 流更换所用 Huffman 树的位置。在有漏洞的版本中,这个函数只返回一个普通布尔值,而 BROTLI_FALSE 既可能表示“这条流格式有误”,也可能表示“我还需要更多输入”。调用方无法区分这两种情况,而在快速路径上,解码器干脆丢弃了返回值。

构造出来的流可以先声明单一块类型,然后耗尽该块的长度,从而强制触发一次无法成功的切换。此时解码器要么对一条已经完整的流报告需要更多输入,要么沿用已有的块状态继续解码。后一条路径会导致越界写入。

上游修复 google/brotli commit 0ed4268 让该函数返回错误码,并新增了一个错误 BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH(-17)。现在无论走安全路径还是快速路径,解码都会在遇到格式错误时停止。OSM 对比了 Brotli 1.2.0 和 1.2.1 的源码发行包,发现 1.2.1 与 1.2.0 的差别只有版本号变更和该 commit 带来的解码器改动。

Python 库中的 Brotli 漏洞(CVE-2026-111497)

Node2Shell 背后的 Brotli 漏洞(CVE-2026-111497)同样影响 Python。PyPI 上的两个包 Brotli 和 brotlicffi 编译的是与 Node.js 捆绑的同一份存在漏洞的 Brotli 解码器。GitHub 上已发布官方公告。Brotli 每月下载量达 8280 万次。

只要任一 Python 环境安装了 Brotli 1.2.0 或更早版本,或 brotlicffi 1.2.0.x,就会受影响。requests、httpx 等常用 HTTP 客户端在这些包存在时会自动加载它们。有些包会把 Brotli 作为依赖自动安装,比如 Scrapy;另一些则需要显式指定。攻击者可以对你应用发出的某个请求返回一个恶意的 Brotli 响应,也可以向你应用发送一个用 Brotli 压缩的请求体,两条路都能触达存在漏洞的解码器。也就是说,即使应用代码里从未 import Brotli,也可能暴露在风险中。它是常见的传递依赖,请检查你的系统。

修复就是升级到打了补丁的版本。

  • Brotli → 1.2.1
  • brotlicffi → 1.2.1.0

两个修复版本的发布说明都没有提到这个 CVE。截至 10 月 23 日,漏洞公告数据库尚未把它关联到这两个 PyPI 包,因此 pip-audit、Dependabot 和 Safety 都不会标记这些版本。

哪些 Python 用户受 CVE-2026-111497 影响?

只要任一 Python 环境装了下面任意一个包,就会受影响。

包受影响版本修复版本
Brotli(PyPI)1.2.0 及更早1.2.1
brotlicffi(PyPI)1.2.0.x1.2.1.0

你的代码不必 import 这两个包中的任何一个。下面这些 HTTP 客户端会声明 Accept-Encoding: br 并自动解码 Brotli 响应。

  • 安装了 Brotli 或 brotlicffi 时的 urllib3(以及依赖它的 requests)
  • 带 brotli extra 的 httpx
  • 安装了 Brotli 时的 aiohttp
  • Scrapy,以及任何基于上述客户端构建的工具

攻击者的数据可以走两条路进入解码器。

  • 出站请求。你的应用从攻击者控制的服务器获取 Brotli 响应,比如通过 webhook 投递、URL 预览、爬虫或“抓取这个 URL”之类的功能。
  • 入站请求。你的框架或中间件会解码用 Content-Encoding: br 发送的请求体,这相当于 Node.js 中 Express 5 的那个案例在 Python 里的版本。

如何在 Python 中修复 CVE-2026-111497

修复就是升级软件包,一共四步。

  1. 用 pip install -U "Brotli>=1.2.1" 或 pip install -U "brotlicffi>=1.2.1.0" 升级你已安装的那个包。如果你用 Poetry、uv 或 pip-tools 管理锁文件,先更新版本约束,再重新生成锁文件。
  2. 重新构建容器镜像,以及任何打包了这两个包的 wheel。基于有漏洞版本构建的镜像,在你重新构建之前一直是有漏洞的。
  3. 检查你运行的每一个环境,包括笔记本、CI runner、服务器和容器。很多项目是通过 HTTP 客户端的 extra 引入 Brotli 的,所以要查看完整的依赖解析树。
  4. 目前只能靠手动检查。在公告数据库把该 CVE 映射到 PyPI 包之前,pip-audit、Dependabot 和 Safety 都不会报告这个问题。

如果你的 Python Brotli 绑定来自 Linux 发行版的软件包而非 PyPI,那么修复要经由你的发行版,因此也要查看该发行版的安全公告。

Python Brotli 漏洞(CVE-2026-111497)是什么?

Python Brotli 漏洞指的是 CVE-2026-111497,即被称为 Node2Shell 的 Brotli 解码器缺陷在 PyPI 上 Python 包中的表现。该 CVE 记录将其归类为 CWE-252(未检查返回值)与 CWE-787(越界写入)。

CVE-2026-111497 对 Python 有多严重,是否已被利用?

CVE 记录给该缺陷的 CVSS 4.0 评分为 9.2,Node.js 将其定为高危。OSM 用 AddressSanitizer 构建了 Brotli 1.2.0 和 1.2.1,并让两者分别处理同一个构造的流。无论流是一次性送达,还是被切成小到 1 字节的分块,1.2.0 都读完了整个约 23 MB 的流,并一直报告需要更多输入。1.2.1 则每次都返回错误 -17 拒绝该流。

OSM 并未在 Python 扩展中尝试内存破坏或代码执行。研究人员用来攻击未修改的 Node.js 24.22.0 构建的,正是这段解码器代码,Imperva 等机构已有报道。就 Node.js 而言,截至 10 月 22 日,The Hacker News 报道称尚未发现野外利用。

不过还是要把它当成紧急事件处理。这是处理不可信网络输入的组件中的内存安全缺陷,修复方式只是例行升级版本。调用外部服务器的服务,以及接受压缩请求体的服务,应优先处理。

如何检查 Python 应用是否受影响

  1. 在每个环境中用 pip show Brotli brotlicffi 检查已安装版本,对每个容器镜像用 docker run --rm <image> pip show Brotli brotlicffi 检查。
  2. 查明这些包是由谁引入的。运行 pipdeptree -r -p Brotli 查看哪些依赖需要它,并用 grep -i brotli poetry.lock uv.lock requirements*.txt 搜索 lockfile。
  3. 列出指向你无法控制的服务器的出站 HTTP 调用,以及所有会解码 Content-Encoding: br 请求体的端点。
  4. 先升级符合第 3 步的服务,再处理其余服务。

如果你在 Python 中复现该漏洞,brotli.decompress() 对任何错误都抛出通用的 brotli.error: decoder failed,因此看不到具体是哪个错误码触发。用 Decompressor() 增量喂入构造的流,在 1.2.0 上永远不会结束。

FAQ

哪些版本修复了 Python 中的 CVE-2026-111497?

Brotli 1.2.1 和 brotlicffi 1.2.1.0,以及任何更新的版本。

我需要在代码中 import Brotli 才会受影响吗?

只要安装了包就够了。urllib3、requests、httpx 和 aiohttp 在检测到 Brotli 或 brotlicffi 时会自动使用它们,并解码你的应用所调用的任何服务器返回的 Brotli 响应。

pip-audit 或 Dependabot 会标记这个问题吗?

目前不会。截至 10 月 23 日,CVE 记录、OSV 和 GitHub Advisory Database 都没有列出这两个 PyPI 包。OSM 正在提交 PYSEC 条目,并为 GitHub advisory 提交 PyPI 包映射,以便工具能够识别。

有临时规避方法吗?

卸载 Brotli 和 brotlicffi 即可移除存在漏洞的解码器,HTTP 客户端会回退到 gzip 和 deflate。在边缘拒绝 Brotli 编码的请求可以减少入站暴露面,但无法防护你的应用主动获取的 Brotli 响应。

来源: Aikido Security← 返回首页