Brotli CVE-2026-111497 (Node2Shell / HTTP2Shell):受影响版本、修复版本和临时解决方案
CVE-2026-111497 发生了什么
CVE-2026-111497 是 Google Brotli 解码器中的一个严重越界写入漏洞,影响所有平台上的 Brotli 1.0.3 至 1.2.0 版本。Node.js 在 2026 年 10 月 21 日那一周将其披露为“Node2Shell”,随着安全研究人员确认相同的解码器漏洞影响 Python 包、原生 libbrotli、curl、Bun、Envoy、Istio、Git for Windows 以及大量捆绑 Brotli 解码器的应用程序,该名称扩展为“HTTP2Shell”。修复版本在 Brotli 1.2.1(以及向后移植的 1.0.10 和 1.1.1)中提供,任何静态链接或捆绑易受攻击的 Brotli 解码器的库或应用程序都需要发布自己的修复版本。
Aikido 于 2026 年 10 月 23 日发布了汇总公告,指出补丁仍在整个生态系统中陆续发布,供应商正在按顺序宣布受影响的组件。
技术根本原因:DecodeBlockTypeAndLength() 中的模糊布尔值
该缺陷位于 DecodeBlockTypeAndLength() 中,这是处理块切换的 Brotli 解码器函数,块切换是 Brotli 流更改其使用的霍夫曼树的位置。在易受攻击的版本中,该函数返回一个普通布尔值,因此 BROTLI_FALSE 可能表示“此流格式错误”或“我需要更多输入”。调用者无法区分这两种情况,在快速解码路径上,解码器完全丢弃返回值。
精心构造的流可以声明单个块类型,然后耗尽该块的长度,迫使块切换无法成功。解码器要么报告需要更多输入(对于实际上完整的流),要么继续使用已有的块状态进行解码。第二条路径产生越界写入。
上游修复,google/brotli 提交 0ed4268,使该函数返回错误代码,并引入新的错误值 BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH (-17)。现在,在安全路径和快速路径上,解码都会在格式错误时停止。对 Brotli 1.2.0 和 1.2.1 源码发行版的差异分析发现,1.2.1 仅与版本号提升和该提交中的解码器更改不同。
CVE 记录将 CWE-252(未检查的返回值)与 CWE-787(越界写入)配对,并分配 CVSS v4.0 评分为 9.2(严重)。
攻击影响:内存泄漏、崩溃或双向远程代码执行
CVE-2026-111497 允许远程、未经身份验证的攻击者发送精心构造的 Brotli 压缩流,从而破坏内存、泄漏敏感数据、使进程崩溃,或可能实现任意代码执行。该漏洞被报告为未经身份验证的远程代码执行,且双向有效,这意味着恶意客户端可以接管未修补的服务器,恶意服务器可以接管接受压缩响应的未修补客户端。
两条数据路径暴露了解码器:
- 出站请求。 应用程序从攻击者控制的服务器获取 Brotli 编码的响应,例如通过 webhook 传递、URL 预览、爬虫或“获取此 URL”功能。
- 入站请求。 框架或中间件解码使用
Content-Encoding: br发送的请求体,这相当于 Node.js 中 Express 5 的 Python 版本。
截至 2026 年 10 月 22 日,The Hacker News 报告未发现野外利用。
CVE-2026-111497 的修复版本
每个捆绑 Brotli 的项目都必须发布自己的更新,因为根本原因已在源代码中上游修复,但直到现在才发布包含修复的上游版本。2026 年 10 月 23 日审查的修复版本:
| 项目 | 补丁状态 | 修复版本 | 备注 |
|---|---|---|---|
| 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.8 | 1.36.12 也包含修复,但 1.36 不受支持 |
| Istio | 补丁可用 | 1.29.9, 1.30.6, 1.31.2 | 1.29 已停止维护;请迁移到受支持的版本线 |
| Google Brotli(上游) | 补丁可用 | 1.0.10, 1.1.1, 1.2.1 | 为匹配的库分支选择修复版本 |
| Python: Brotli (PyPI) | 补丁可用 | 1.2.1 | 发布说明未提及 CVE |
| Python: brotlicffi (PyPI) | 补丁可用 | 1.2.1.0 | 发布说明未提及 CVE |
公告中的其他指导:
- curl / libcurl: 将 Brotli 依赖项更新到 1.2.1、已修补的旧版本或供应商的安全修复包。捆绑或静态链接的副本需要更新应用程序构建。
- 操作系统包: 安装供应商的安全更新。供应商可能会在不更改上游版本号的情况下向后移植修复。
- 其他 HTTP 服务器、反向代理、API 网关和 HTTP 客户端: 更新受影响的运行时或它们使用的 Brotli 库。如果 Brotli 捆绑在产品中,请安装产品供应商明确解决此 CVE 的版本。对于托管服务,请与提供商确认修复措施。
升级后,更新依赖锁定文件,重建受影响的应用程序和容器镜像,重新部署并重启服务,然后验证正在运行的工作负载使用已修补的组件。
为什么一个 Brotli 漏洞影响这么多语言和产品
Python、Node.js、C++、libbrotli、Envoy 和 Bun 都受到影响,因为它们编译或捆绑相同的 C Brotli 解码器。解码逻辑只有一个实现,因此单个内存安全缺陷会传播到每个嵌入它的运行时。
两个 PyPI 包,Brotli 和 brotlicffi,编译了与 Node.js 捆绑的相同的易受攻击的解码器,Brotli 每月下载量为 8280 万次。HTTP 客户端如 urllib3(因此也包括 requests)、带有 brotli 附加功能的 httpx 以及 aiohttp 在存在时自动加载任一包,并在应用程序不直接导入 Brotli 的情况下解码 Brotli 响应。Scrapy 和其他包将 Brotli 作为依赖项安装。因此,Python 应用程序可能在其自身源代码中不包含任何 Brotli 导入的情况下暴露。
某些组件不易受解码路径影响。Apache 的标准 mod_brotli 不解码 Brotli,Apache 和 Nginx 默认不解码 Brotli。
咨询数据库缺口:pip-audit、Dependabot 和 Safety 尚未标记
截至 2026 年 10 月 23 日,咨询数据库尚未将 CVE-2026-111497 映射到 Brotli 或 brotlicffi PyPI 包。CVE 记录、OSV 和 GitHub Advisory Database 未列出这两个包,这意味着 pip-audit、Dependabot 和 Safety 不会标记易受攻击的版本。GitHub 公告已发布在 GHSA-9v8h-qqgm-4m35,报告者正在提交 PYSEC 条目以及 GitHub 公告的 PyPI 包映射,以便工具能够识别。在该映射落地之前,暴露检查必须手动进行。
如何检查您的应用程序是否暴露
安装易受攻击的 Brotli 解码器副本就足以暴露,即使没有应用程序代码调用它。实际检查:
- 在每个环境中使用
pip show Brotli brotlicffi检查已安装的版本,并使用docker run --rm <image> pip show Brotli brotlicffi检查每个容器镜像。 - 找出哪些依赖引入了这些包。运行
pipdeptree -r -p Brotli查看哪些依赖需要它,并使用grep -i brotli poetry.lock uv.lock requirements*.txt搜索锁定文件。 - 列出指向您不控制的服务器的出站 HTTP 调用,以及任何解码
Content-Encoding: br请求体的端点。 - 首先升级与步骤 3 匹配的服务,然后升级其余部分。
对于复现工作:brotli.decompress() 对任何错误都会引发通用的 brotli.error: decoder failed,因此从 Python 中看不到具体的错误代码。在 1.2.0 上,将精心构造的流增量输入 Decompressor() 永远不会完成。使用 AddressSanitizer 构建的 Brotli 1.2.0 和 1.2.1 测试表明,1.2.0 消耗了大约 23 MB 的精心构造的流,同时反复报告需要更多输入,无论流是一次性到达还是以小至一个字节的块到达;版本 1.2.1 每次都以错误 -17 拒绝该流。
如果无法立即升级的临时解决方案
这些缓解措施在准备补丁期间减少暴露:
- Python 应用程序: 如果 Brotli 支持是可选的,请从受影响的环境中卸载 Brotli 和 brotlicffi。删除依赖项附加功能,如
httpx[brotli]以及任何会重新安装它们的其他要求,然后重新生成依赖锁定文件并重建或重启工作负载。httpx、requests 和 urllib3 在没有可选包的情况下保留 gzip 和 deflate 支持,但服务器仍然发送 Brotli 可能会产生不可读的响应或应用程序错误,并且不保证自动回退。 - 入站 HTTP 请求: 在反向代理、负载均衡器或应用程序中间件中,在任何易受攻击的解码器处理请求体之前,拒绝其
Content-Encoding包含br的请求。匹配br时不区分大小写,包括当它出现在编码列表中时。 - 出站 HTTP 请求: 从
Accept-Encoding中删除br,并禁用 Brotli 响应解码或在解码开始前拒绝其Content-Encoding包含br的响应。检查必须在自动处理请求体之前进行;在客户端下载并解码响应后检查为时已晚。
仅更改 Accept-Encoding 是不够的,因为恶意服务器可以无视客户端通告的内容发送 Brotli 响应,并且 urllib3 根据响应的 Content-Encoding 头选择其解码器。卸载 Python 包也不会删除捆绑在其他运行时、库或产品中的单独 Brotli 解码器。
披露时间线和 OpenAI 二月份的发现
Aikido 的 TL;DR 指出 Node.js 于 2026 年 10 月 21 日星期三披露了 CVE-2026-111497,而同一公告的后续时间线部分将 Node.js 披露描述为 2026 年 10 月 22 日星期三;来源列出了两个日期。Python 第二天发布了修补相同漏洞的安全更新。10 月 23 日星期五,人们知道该 CVE 影响其他主要语言和使用 HTTP 的服务应用程序,补丁尚未完全可用。
OpenAI 表示其在二月份发现了该漏洞。根本原因当时已在 Brotli 源代码中修复,但未被识别为安全问题,直到 2026 年 10 月才发布包含修复的版本。OpenAI 将其报告为双向工作的未经身份验证的远程代码执行,并发布了在 patchtheplanet.org/brotli 引用的公告。
Hacker News 评论者对归属提出了质疑。一位评论者认为二月份的更改来自 Google 而不是 OpenAI:
文章声称 OpenAI 在二月份发现了这个问题,但我认为这不正确。我认为 Google 在二月份对 Brotli 源代码进行了更改,修复了该问题,但没有意识到这是一个安全问题,因此没有发布版本。
另一位评论者强调了报告严重性与发布版本之间的差距:
报告为双向工作的未经身份验证的远程代码执行……但当时未被识别为安全问题,直到现在才发布包含修复的版本。我总是把危险 RCE 漏洞和无害 RCE 漏洞混为一谈。我很好奇这是如何在二月份报告和修复的,但没有人认识到其重要性。这是 AI 自动化且无人值守的案例吗?
社区反应:命名、复杂性和 C 语言辩论
Hacker News 讨论中最一致的抱怨是名称。“Node2Shell”在确认 Python 和其他生态系统受影响后不再描述范围,而“HTTP2Shell”被广泛拒绝为过于宽泛和模糊:
好吧,选择 HTTP2Shell 这个名字的人肯定没有使用任何智能,无论是人工的还是真正的。它太无意义、太宽泛、太不描述实际问题了。不,它可能不会影响没有其他东西的 HTTP 服务器,那么为什么要攻击 HTTP?
线程中提出的替代名称包括 Brotli2Shell 和 Broccoli2Shell。一位评论者认为 HTTP 只是该漏洞的附带现象:
更喜欢 Broccoli2Shell 名称和网站(针对同一漏洞)。首先,我很确定如果你手动进行任何 Brotli 解码,你可以在没有 HTTP 的情况下触发它,HTTP 恰好是最常见的案例。
几位评论者质疑在默认配置中实际解码 Brotli 压缩的请求体的普遍程度,认为公告模糊了正常响应解压缩和更冷门的入站路径之间的区别:
对我来说,令人惊讶的是有多少实现了请求(而不仅仅是响应)体的 brotli 压缩,考虑到这是一个多么冷门的功能。无论如何,所有这些耸人听闻的言论开始变得烦人。修补你的东西然后继续前进。
还出现了复杂性论点,将其框定为替换 gzip/deflate 的成本:
我想这是增加复杂性的代价的一个例子。Brotli 比它替换的 gzip/deflate 复杂得多。……当然我们仍然必须暴露 gzip 以进行攻击。每次你添加一些东西,你就会失去一些东西……
一个线程围绕这是否是反对 C 的论点:
老实说,是时候摆脱 C 作为在安全因素重要的地方使用的语言了。受够了。为什么像 brotli 这样处理公共互联网流量并由 Google 维护的库不是用 Rust 编写的?
一位上游补丁的审阅者认为它很仓促:
我甚至阅读了 C 代码的补丁(顺便说一句,对我来说似乎有点 hacky,添加了 isSafe? 方法等等……这个补丁在我看来真的像“给缓冲区溢出的 C 猪涂口红”)。……Python / Node / C++ / libbrotli / Envoy / Bun 之间有什么联系:它们是否都使用相同的 C brotli 编码器/解码器?
对该评论者问题的回答是肯定的:它们都嵌入或链接相同的 Brotli C 解码器,这就是为什么仅上游 Brotli 1.2.1 不能保护捆绑自己副本的系统。
评论者报告的操作上受影响的软件
评论者列出了公告表格之外的真实世界暴露:
- Git for Windows 即使在其最新版本(2.56.0.windows.3)中仍然易受攻击;修复已合并到仓库中,但仅在快照构建中可用,后续版本预计在周一发布(2.56.0.windows.4)。通过 HTTPS 从不受信任的服务器拉取仓库是相关风险。
- Codex(GUI)自带 Git 和 Node,评论者认为风险可能更高;建议的缓解措施是更新 Codex 并清除其缓存
~/.cache/codex-runtimes。 - Wireshark 和 ImHex 即使在其最新的仓库提交中仍然易受攻击。
- Microsoft 365 Copilot 仍然自带未修补的
brotlidec.dll,日期为 10 月 7 日,没有可用的修复,也没有确认的路径到达易受攻击的解码器。 - Ubuntu 仍然将
libbrotli1补丁作为中等严重性项目进行审查,这阻碍了 libcurl 的更新,从而影响了 Git 和其他依赖包。 - 在单个 Windows 开发机器上的文件搜索发现 Brotli 库链接到 Git、Sublime Text、Visual Studio、CUDA、.NET、Inkscape 和 Azure Tools。
一位运维方面的评论者检查了他们的环境,发现完全没有暴露,说明了传递依赖的彩票性质:
我不得不检查我们所有的 Python 部署和安装 BOM,并且非常欣慰 - 结果发现实际上没有安装 brotli 库。像 httpx、requests 和框架这样的 HTTP 库将它们视为可选并自动检测它们的存在。
线程中提出的一个未回答的架构问题是,当负载均衡器终止 TLS 并处理解压缩时,应用程序是否安全:
假设我有一个 node.js 应用程序在 Amazon 弹性负载均衡器后面,它终止 TLS。我的理解是,在几乎所有配置中,我的应用程序都不会受到影响,因为 ELB 会处理解压缩。这通常正确吗?
讨论中没有记录明确的答案,因此实际规则仍然是:审计解码路径中的每个组件,而不是假设边缘代理消除了风险。
补丁速度问题
讨论还捕捉到了依赖管理中的更广泛紧张关系。包生态系统在 2025 年建议工程师对新发布的版本应用冷却期以避免供应链攻击,而关键漏洞现在迫使这些冷却期被搁置:
几个月前,每个人都建议在包升级中使用冷却期。现在我们不断覆盖这些,因为安全事件会立即被利用。我想从现在开始就是这样了。
一些工程师通过自动化修复来回应,一位评论者描述将 Claude Code 指向每个新出现的公告。其他人则直截了当地描述了实际姿态:修补、重建、重新部署,然后继续前进。线程没有争议的一点是,Brotli 解码器现在几乎每个 HTTP 客户端和服务器的不受信任输入攻击面的一部分,并且每个捆绑 Brotli 的项目都必须为 CVE-2026-111497 发布自己的更新。
Sources
相关
- Dispatch
- 项目
- 项目
- Dispatch
- Dispatch