Node.js曝Brotli内存破坏风险,需排查版本
据节选,Node.js的Brotli解码器存在越界写入漏洞,可能导致崩溃、内存泄露或远程代码执行,由OpenAI Codex Security研究人员报告。文中称Imperva已在官方Linux arm64构建上实现代码执行,并提醒Node.js 22、24、26用户升级,20版本不再获修复。
AI 深度解读
据原文,OpenAI Codex Security 报告的 Node.js Brotli 漏洞,已被 Imperva 在官方 Linux arm64 构建上复现代码执行。它和前端、全栈团队的关系很直接:服务端一次 fetch(),或 Express 自动解析请求体,都可能进入有问题的解码器。
处理重点是升级实际部署的 Node.js。读这篇最有用的,是分清哪些入口会受影响、公开实验究竟证明了什么,以及为什么本机升级和平台 WAF 都不能代替运行时排查。以下信息均依据原文,未做额外核验。
没写过解压代码,为什么也会中招
漏洞编号为 CVE-2026-111497。按原文引用的 10 月 21 日 Node.js 安全公告,Brotli 流式解码器把非法块切换误判成了「还需要更多输入」,随后持续向一个只有 8 字节的内部缓冲区追加数据,造成越界写入。
问题出在异常状态处理:本该停止解码,却继续接收字节。内存损坏可能导致进程崩溃、进程内存泄露或远程代码执行。

Brotli 对应 HTTP 中的 Content-Encoding: br。Node.js 内置了 Google 的解码器,并通过 node:zlib 暴露能力,但业务不必直接调用它才会受影响。
原文列出两个入口:
- 内置
fetch()解码远端压缩响应。如果服务访问第三方 API、Webhook URL 或用户提交的 URL,且响应服务器受攻击者控制,就可能进入漏洞路径。 - Express 5 的
express.json()、express.urlencoded()、express.text()和express.raw()会解码 Brotli 请求体。Imperva 复现涉及 Express 5.0.0 至 5.3.0、body-parser 2.0.0 至 2.3.0。
普通 node:http 服务不会自动解码 Brotli 请求体,是否受这条路径影响,要看中间件或业务代码。
排查入口时,既要看收到的请求,也要看服务主动拉取的响应。
修复时间线也有一个细节:原文称,上游代码变更早在 2026 年 2 月就已落入 Brotli 源码,但直到 10 月发布时才被标记为安全修复;10 月 21 日的 Brotli 1.2.1 更新记录列出了该 CVE。代码已经修好,与部署环境已经获得安全更新,是两件事。
官方构建上执行成功,证明到了哪一步
OpenAI 在 10 月 23 日将其描述为可导致未认证远程代码执行的漏洞。同日相关报道指出,Imperva 在官方 Node.js 24.22.0 Linux arm64 镜像上执行了代码,没有使用调试器,也没有定制构建。
这个结果证明,风险可以在标准发布环境中触达。但不能据此推断所有架构和版本都能稳定执行代码。
Imperva 明确表示,其环境需要多次尝试才能执行成功,而且只测试了 24.x 分支上的 arm64。更早的公开概念验证只在刻意弱化的构建上实现代码执行,在标准构建上得到的是崩溃和有限内存读取。
原文还引用报道称,截至 10 月 22 日,没有已报告的在野利用。这个时间范围不能扩大成当前没有攻击,更不能当作等待升级的理由:进程崩溃本身已经可能形成拒绝服务。
评级应以厂商为准。Node.js 将其定为 high,部分媒体给出的 CVSS 9.2 不应替代官方定级。原文也没有提供跨架构成功率或完整利用条件,这些仍是证据边界。
真正需要升级的是部署镜像里的 Node
原文给出的修复版本下限是:
| Node.js 分支 | 修复版本 |
|---|---|
| 22.x | 22.23.4 |
| 24.x | 24.22.1 |
| 26.x | 26.12.1 |
| 20.x | 已结束维护,没有修复版本 |
公告未列出替代缓解方案。同期发布还修复了另外 9 个 CVE,其中 3 个同样为 high,涉及两个 TLS 证书主机名校验绕过,以及 dns.resolve 遇到 NUL 字符时的截断问题。
依赖审计未必能发现容器里捆绑的旧运行时。作者提供的脚本直接读取当前执行它的 Node 版本,适合放入镜像构建检查:
// check-node.mjs: exit 1 if this Node lacks
// the CVE-2026-111497 fix
const fixed = { 22: [23, 4], 24: [22, 1], 26: [12, 1] };
const [maj, min, pat] = process.versions.node
.split('.')
.map(Number);
const f = fixed[maj];
const ok = Boolean(f) &&
(min > f[0] || (min === f[0] && pat >= f[1]));
console.log(process.versions.node,
ok ? 'patched' : 'NOT patched');
process.exit(ok ? 0 : 1);
要看清 fixed 这一行:这是允许表,Node 20 和未来高于 26 的主版本都会失败,不能把所有失败都解释成已经确认存在同一个漏洞。
保存为 check-node.mjs 后,可以运行 node check-node.mjs;检查镜像则使用 docker run --rm -v "$PWD":/w your-image node /w/check-node.mjs。
再搜索项目直接解码 Brotli 的位置:
git grep -nE "BrotliDecompress|brotliDecompress" \
-- '*.js' '*.ts' '*.mjs' '*.cjs'
注意搜索覆盖的文件类型。它有助于找到业务调用,但查不到结果,并不能排除 fetch() 或中间件带来的间接入口。
package.json 的 engines.node 可写为 ^22.23.4 || ^24.22.1 || >=26.12.1。不过 npm 默认只警告版本不匹配,实际门禁仍要靠 CI。还应固定 Dockerfile 基础镜像到修复版本并重新构建,运行中的容器不会自行更换 Node。

我的判断
这篇最有价值的提醒,是把修复对象从项目依赖扩展到了实际运行时。对同时维护 Node 服务、容器和 CI 的团队,这比只搜索一次漏洞包名更接近真实部署情况。
WAF 的边界也解释得清楚。原文称,Vercel 于 10 月 21 日为所有项目部署了入站防护规则,并管理 22.x、24.x 运行时的补丁版本;但规则不覆盖函数通过 fetch() 获取的远端响应,也不能替代修补。Node 20 项目仍需迁移到 22 或 24 后重新部署。Imperva 同样表示,完整修复需要更新 Node.js。
WAF 可以拦截入站攻击,运行时升级负责修掉解码器。
不过,文章没有提供 WAF 与其他缓解措施的对照数据,也没有证明那个检查脚本适合所有团队。它是针对这次公告的实用检查工具,需要持续维护版本表。Codex 获得报告署名也只说明其参与了漏洞发现,原文未交代人工参与程度、审计过程和发现效率,不能据此推导 AI 已能独立完成安全审计。
能拿来做什么
- 给每个仍在部署的镜像标签执行版本检查,同时盘点 CI runner、虚拟机和托管平台运行时,避免只检查开发电脑。
- 审查 Node 服务中访问外部 URL 的
fetch(),以及 Express 请求体解析配置,明确哪里会解码不可信的 Brotli 数据。 - 将版本脚本接入镜像构建,把
engines用作版本声明;升级基础镜像后重新构建、部署,并检查部署产物中的实际版本。 - 使用 Vercel 等平台时,确认项目已经选择修复分支并重新部署;评估 WAF 覆盖范围时,单独检查远端响应这条路径。