你的 Node.js 版本受 Brotli RCE 漏洞影响吗?2 分钟快速自查

Node.js 内置 Brotli 解码器曝出远程代码执行漏洞 CVE-2026-111497(Node2Shell),已被列入 CISA KEV。本文提供 2 分钟自查命令、可达性矩阵、升级与临时缓解方案。

用 Apifox,节省研发团队的每一分钟

你的 Node.js 版本受 Brotli RCE 漏洞影响吗?2 分钟快速自查

免费使用 Apifox

相关推荐

最新文章

API

一体化协作平台

API 设计

API 文档

API 调试

自动化测试

API Mock

API Hub

立即体验 Apifox
目录

立即运行以下命令。如果你的版本号低于下表中的安全基线,说明你的环境受 Node.js Brotli 远程代码执行漏洞(CVE-2026-111497)影响,且攻击者已经在利用该漏洞。

node -v
发布分支 受影响版本 修复起始版本 最新版本(2026 年 11 月 5 日)
26.x 低于 26.12.1 26.12.1 26.13.0
24.x 低于 24.22.1 24.22.1 24.22.2
22.x 低于 22.23.4 22.23.4 22.23.4
25.x、20.x 及更早版本 已停服(End-of-Life):未修复且未评估 无可用修复 迁移至 24 或 26

若需第二个验证信号,可以直接查询二进制文件:

node -p "require('node:zlib').constants.BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH"

本次修复新增了该常量。我们在三个受支持分支的 9 个官方 macOS 构建版本上运行了该命令:所有已修复构建均输出 -17,所有旧版本构建均输出 undefined。请优先以 node -v 为准,因为向后移植补丁的 Linux 发行版可能不会同步添加该常量。

不要依赖 process.versions.brotli。它在 24.21.0 与 24.22.1 上均输出 1.2.0,在 22.23.3 与 22.23.4 上均输出 1.1.0。Node.js 仅拣选(cherry-pick)了修复提交,并未修改上报的 Brotli 版本号,因此该字段无法反映是否已打补丁。

AI Coding 交流群

如果你也在用 AI 写代码,或者正在研究 Cursor、Claude Code 这些工具,欢迎加入以下交流群。群里平时会聊一些 AI 编程的实际用法、开发工作流,还有各种新工具和新玩法。

AI Coding 交流群二维码

核心要点速览(TL;DR)

问题 结论
漏洞本质是什么? Node.js 内置 Brotli 解码器中的越界写入漏洞,别称 Node2Shell 或 HTTP2Shell
潜在影响 进程崩溃、内存信息泄露或远程代码执行(RCE)
严重程度 Node.js 官方公告定级为 HIGH;NVD 评分为 9.8 CRITICAL(CVSS 3.1)
是否存在在野利用? 是。CISA KEV 已于 2026 年 10 月 27 日将其列入已知被利用漏洞目录
是否需要认证登录? 不需要,依据 NVD 攻击向量及 Akamai 的技术分析
哪些应用可达? 会解压不可信 Brotli 数据的应用:Express 5 请求体、fetch() 响应、直接调用 node:zlib
修复方式 升级运行时、重新构建容器镜像、重启所有进程
是否有官方临时方案? 官方公告未提供临时绕过方案。下文的缓解措施可降低暴露面,但无法完全替代升级
CVE-2026-111497 时间线:10 月 21 日 Node.js 发布修复、10 月 22 日公布 CVE、10 月 26 日捕获在野利用流量、10 月 27 日列入 CISA KEV、11 月 10 日 KEV 整改截止、11 月 11 日下一轮 Node.js 安全发布

ELLIO 报告称,在修复发布五天后的 10 月 26 日,其传感器便捕获到了漏洞利用流量。捕获到的载荷针对 x86-64 架构上的 Node.js 24.22.0。虽然该载荷的最终阶段在 ELLIO 的测试中未能成功执行,但 ELLIO 已在官方原版 24.22.0 构建上独立验证了代码执行。CISA 要求美国联邦机构在 11 月 10 日前完成整改,并将其勒索软件利用状态标为“未知(Unknown)”。Akamai 的遥测数据显示,截至 10 月 26 日,61% 的网络仍在运行受影响版本。

Node2Shell 原理解析:Brotli 漏洞究竟做了什么

Node2Shell 是随 Node.js 运行时分发的 Brotli 解码器中的一个越界写入(out-of-bounds write)漏洞。畸形的压缩数据流会导致解码器向一个 8 字节内部缓冲区的末尾之外写入数据,从而破坏进程内存。其后果可能是进程崩溃、内存泄露,或者在服务器上执行攻击者控制的代码。

根本原因在于错误分类不当。无效的块切换(block switch)被误判为“需要更多输入”,而非“数据已损坏”,导致流式解码器持续向这个小型缓冲区追加字节。

该漏洞存在于 Google Brotli 库的 1.0.3 至 1.2.0 版本中,因此不仅限于 Node.js。Node.js 通过将上游提交 0ed4268a 拣选合入 24.22.1 版本及其同批发布版本修复了内置副本。该漏洞由 OpenAI Codex Security 研究员 Khai Tran 与 Sylvie Mayer 报告。

常规依赖扫描工具无法发现此问题,因为解码器内置于运行时而非 npm 依赖包中。我们在未打补丁的 Node.js 24.15.0 上对 Express 5 测试项目运行 npm install 时,报告的漏洞数量为 0。

哪些调用路径会触发漏洞

存在漏洞的运行时只是一半条件,另一半条件是存在将不可信 Brotli 数据传入解码器的调用路径。我们在 Node.js 24.22.1 上对各条常见路径进行了实测:向服务端发送带有 Content-Encoding: br 的无害非法请求体(纯文本 not-valid-brotli),并向各客户端返回合法的 Brotli 压缩响应。

调用路径 测试版本 是否触发解码器? 实测表现
Express 5 express.json() 5.3.0 (body-parser 2.4.0) 是(默认开启) 返回 400,“Decompression failed”
Express 4 express.json() 4.22.3 (body-parser 1.20.9) 否 返回 415,不支持的编码格式
Koa @koa/bodyparser 6.1.0 是(默认开启) 返回 500,日志打印 BrotliDecoder 错误
注册了 @fastify/compress 的 Fastify 9.3.0 是(注册插件后) 返回 400,FST_CP_ERR_INVALID_CONTENT
原生 Fastify 5.12.8 否 返回 400,无效 JSON
裸 node:http 服务端或 http.get 24.22.1 否 原始字节直接透传
内置 fetch() 24.22.1 是(始终开启) 自动解压响应内容
axios、got、node-fetch 1.21.0、16.2.0、3.3.2 是(默认开启) 自动解压响应内容
zlib.brotliDecompress*、createBrotliDecompress 任意版本 是 这正是底层解码器 API
node:zlib 中 Brotli 解码器可达性路径图:入站方向 Express 5、Koa bodyparser 与注册了 @fastify/compress 的 Fastify 会触发解码,出站方向 fetch、axios 与 got 默认触发解码,而 Express 4、原生 Fastify 与裸 node:http 不会触发

有两项结果值得特别注意。首先,即便请求头显式发送了 Accept-Encoding: identity,内置 fetch() 依然会解压 Brotli 数据,因为它是根据响应头而非请求头来决定是否解压的。这意味着你的应用调用的任何外部服务器都能触达解码器,因此 Webhook 测试器、链接预览器或 URL 导入器全都暴露在风险之下。其次,仅凭返回 400 状态码并不能证明安全:Express 5 与原生 Fastify 都会返回 400,但只有 Express 5 实际运行了解码器。请务必检查具体报错信息。

可以用以下三条命令排查代码库中的可达路径:

# 直接调用解码器
grep -rnE "brotliDecompress|createBrotliDecompress" src/

# 会自动解压请求体的解析中间件
npm ls express body-parser @koa/bodyparser @fastify/compress

# 基础镜像与锁定的版本号
grep -rnE "^FROM .*node" --include='Dockerfile*' .

只要新增一处 fetch() 调用,上述排查结论就会改变,因此“当前不可达”依然意味着必须打补丁。

如何修复 CVE-2026-111497

请直接升级到所属分支的最新构建版本,而不只是最低修复版本。截至 11 月 5 日,以下渠道均已提供修复构建:

安装方式 执行操作
nvm nvm install 24 && nvm alias default 24
Homebrew brew upgrade node(或 node@24、node@22)
Docker FROM node:24.22.2-slim,随后执行 docker build --pull
Linux 发行版软件包 遵循所属发行版的安全公告,发行版可能会在旧版本号下向后移植补丁
CI 流水线 更新 .nvmrc、engines 与 node-version,然后重新构建
Serverless 在已部署函数中打印 process.version 进行核验,不要默认平台已自动升级

接着补上最容易被忽略的两个漏洞点:

  • 重启所有进程。 正在运行的进程会将旧版二进制文件保留在内存中,因此在磁盘上完成升级后,必须通过 pm2、systemd 或容器编排器重启进程才能生效。
  • 重新构建已交付的制品。 旧镜像中依然包含旧版运行时,而按摘要(digest)锁定的镜像需要进行镜像扫描,因为镜像标签本身不会反映底层变更。

最后,在已部署容器内部、CI Runner 以及开发机上分别运行本文开头的自查命令。如需查看各受支持分支的最新安全构建版本,可运行:

curl -s https://nodejs.org/dist/index.json | jq -r '[.[] | select(.security == true and (.version | test("^v(22|24|26)\\.")))] | group_by(.version | split(".")[0]) | .[] | max_by(.date) | "\(.version)  \(.date)"'

如果你仍在运行 Node.js 20 或 25,官方不会为你提供任何修复构建,请尽快制定停服版本迁移计划并升级至受支持分支。

今天无法打补丁时的 Node.js Brotli 临时缓解措施

以下措施只能争取时间,无法替代运行时升级。

  1. 在边缘层拒绝 br。 在反向代理或负载均衡器上拦截 Content-Encoding: br,注意不区分大小写,并匹配类似 gzip, br 的组合列表。
  2. 在应用层拒绝 br。 将以下中间件放在所有请求体解析器之前。在我们的 Express 5 测试中,它会直接返回 415:
app.use((req, res, next) => {
  const encoding = req.headers['content-encoding'] || '';
  if (/\bbr\b/i.test(encoding)) return res.status(415).end();
  next();
});
  1. 关闭自动解压。 express.json({ inflate: false }) 对相同请求同样返回 415。不过这也会一并拒绝 gzip 请求体,启用前请先确认客户端行为。
  2. 控制出站响应解压。 axios 支持配置 decompress: false,在我们的测试中它会保留未解码的原始字节。内置 fetch() 没有标准的关闭开关,因此需要通过白名单和出站流量规则(egress rules)限制其可访问的目标主机。
  3. 缩减爆炸半径。 隔离 Node.js 服务,并限制核心转储(core dumps)的读取权限——ELLIO 指出进程崩溃可能会在转储文件中暴露内存数据。

密切关注 ELLIO 率先观测到的特征:突发的 Brotli 编码请求体扫描(用于探测哪些主机开启了解码)。如果 JSON API 出现异常的 Content-Encoding: br 流量,或者工作进程崩溃率突然飙升,都值得立即深入排查。

证明升级后 API 行为一致:交给编程智能体执行回归验证

运行时版本跨越可能会改变 TLS、DNS 和 HTTP 行为,而 10 月的安全发布同时涉及了这三块。无需手动比对差异,可以让编程智能体在升级前后运行 Apifox CLI 并输出对比报告。

npm install -g apifox-cli@latest
apifox auth login --with-token <YOUR_TOKEN>
apifox skill install   # 按提示选择你的编程智能体

向你的智能体发送一段提示词:

在预发布环境(staging)运行项目 <id> 中的 Apifox 测试套件 <id>,并将结果保存到
reports/before。在我完成 Node.js 升级后,为 POST /orders 新增一条测试用例:发送携带
Content-Encoding: br 的纯文本 "not-valid-brotli",断言返回 4xx 状态码,随后检查
GET /health 返回 200。重新运行测试套件并保存到 reports/after,列出所有结果发生变化的请求。

智能体会依次执行以下命令:

apifox run --test-suite <id> --project <id> -e <envId> -r cli,junit --out-dir reports/before
apifox cli-schema get test-case-create
apifox cli-schema validate test-case-create --file case.json
apifox test-case create --project <id> --file case.json
apifox run --test-case <caseId> --project <id> -e <envId> -r cli,json
apifox run --test-suite <id> --project <id> -e <envId> -r cli,junit --out-dir reports/after

新增的那条用例属于健康检查而非漏洞利用载荷:请求体只是普通纯文本,在我们的测试中,它在受影响版本与修复版本上都会触发相同的填充错误(padding error)。但它能捕捉到真实的异常处理缺口——我们的 Koa 测试因为未捕获解码错误而返回了 500,而公开 API 应当返回 4xx。请仅针对预发布环境运行该检查。

你可以通过 apifox run --help 查看所有命令行参数,并结合 CI/CD 流水线指南 将相同的 JUnit 测试集成到流水线中。

为什么接下来的 11 月 11 日同样关键

Node.js 项目已预先预告了下一轮安全发布,将于 2026 年 11 月 11 日当天或之后不久面向 26.x、24.x 与 22.x 推出,最高严重程度同样为 HIGH。目前具体 CVE 细节尚未公开,建议提前盘点运行时资产并准备好补丁日升级流程。

请立即修复 Brotli 漏洞,不要等到 11 月 11 日的窗口才一并处理。该漏洞已有公开细节且存在实时在野攻击,而本周执行的升级正好可以作为下一轮发布的实战演练:同样的资产清单、同样的镜像重建流程、同样的回归测试套件。此前的 PHP2Shell 与 React2Shell 漏洞也呈现出相同的演进规律。

常见问题(FAQ)

CVE-2026-111497 是否正在被在野利用? 是的。CISA 已于 2026 年 10 月 27 日将其归入 Google Brotli 类别并列入已知被利用漏洞(KEV)目录,ELLIO 则在 10 月 26 日前就记录到了在野利用流量。

它到底属于高危(High)还是严重(Critical)? 两个评级都真实有效。Node.js 官方将其定级为 HIGH;NVD 在 CVSS 3.1 下的评分为 9.8 CRITICAL,而 Google 给出的 CVSS 4.0 评分为 9.2。请直接按照“已被在野利用”的最高优先级来制定修复计划。

我正在使用 Express 4,是否安全? 你的入站请求体不会触达该解码器,但出站 fetch()、axios 以及直接调用 node:zlib 依然会触发。此外,同一批安全发布还修复了另外 9 个 CVE,因此无论如何都应尽快升级。

Node.js 20 是否受影响? 官方不会对已停服(End-of-Life)分支进行评估,也不会发布修复补丁。请将 20.x 与 25.x 视为“未修复且未评估”,并尽快完成大版本迁移。

除了 Node.js 之外还有其他组件受影响吗? 有。GitHub 安全公告涵盖了 PyPI 上的 brotli 与 brotlicffi 包,各家厂商也陆续发布了针对 Bun 1.4.4 和 .NET 的修复。由于升级 Node.js 只能更新其自带的解码器副本,请务必分别更新各个运行时与依赖包中的解码器。