官方让你升级 Node.js,但这句建议在 Debian 上是错的

导语:Vercel 官方账号发推说,Brotli 解码器有个高危 RCE,影响 Node.js 22/24/26,WAF 规则已经上线覆盖全平台。公告里那句”升级到 22.23.4 / 24.22.1 / 26.12.1″,在 Debian 和 Ubuntu 上照着做是无效的。原因藏在两层供应链里:一层在上游,修复代码在 brotli 仓库躺了 8 个月才发版;另一层在下游,Debian 的 nodejs 根本不内置 brotli,它链接的是系统库。


一、8 个月:修复代码就在仓库里,但没人能拿到

先把时间线摆出来。这几行字是我逐条查证过的,不是转述。

2026 年 2 月 27 日 13:10 UTC,google/brotli 仓库收到一个提交,0ed4268a,提交信息是:

Detect and report invalid stream earlier.

改动文件两个:c/dec/decode.c 和 c/include/brotli/decode.h。

注意这个提交的名字。它根本不是个安全修复,是一次内部重构——”更早检测并报告非法流”。它顺带把 Brotli 解码器里那个 BROTLI_FALSE 语义过载、返回值被丢弃的越界写给堵上了。没人给它标 CVE,没人给它写 advisory,它就是一次普通提交,混在一堆日常 commit 里。

从 2 月 27 日到 10 月 21 日,整整八个月,google/brotli 没有发布任何新版本。 仓库上一个 tag 还是 2025 年 10 月 27 日的 v1.2.0。也就是说,这八个月里,主干代码是修好的,但没有任何一个被打过标签的发行版包含这个修复。谁从上游拉 brotli,拿到的都是有洞的 1.2.0。

2026 年 10 月 21 日 19:26 到 19:27 UTC,brotli 终于连发三个版本:v1.0.10、v1.1.1、v1.2.1,每个版本的 SECURITY 段落里都写着同一行:

CVE-2026-111497: out-of-bounds write permits remote code execution

同一天,Node.js 项目发布 22.23.4、24.22.1、26.12.1,其对 111497 的修复是把 2 月 27 日那个提交 cherry-pick 过来。

同一天的另一件事更值得琢磨:按 Node.js 官方公告的致谢,这个漏洞的报告人是 OpenAI Codex Security 的 Khai Tran 和 Sylvie Mayer。

换句话说,修 bug 的代码在 Google 自己仓库里躺了八个月,最后是外部的 AI 系统发现了问题、促成了披露,Google 才想起给自己的库发一个安全版本。这不是”补丁来得慢”,这是上游安全流程整体失灵:修复没有打标、没有发布、没有通告,三个月后 CVE 记录才在 CVE.org 公开,而 Google 作为 CNA 给这个漏洞标注的 datePublic 是 2 月 27 日——恰好就是那个修复提交的日期。

CVE-2026-111497 在 CVE.org 的官方记录

图:CVE.org 上 CVE-2026-111497 的官方记录,CNA 为 Google LLC,来源 cve.org

二、Google 打 9.2 Critical,Node.js 说 High

看上图右上角那条数据:CNA 是 Google LLC,标题叫 “Out-of-Bounds Write in Google Brotli Decoder”,CVSS 4.0 基础分 9.2,等级 CRITICAL,向量是:

CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N

三个 H 打到底:机密性、完整性、可用性全是 High。这是能崩服务、能改内存、能跑代码的量级。

而 Node.js 官方公告给这个洞的定级是 high——小写,没有任何评分,没有任何攻击细节。

两边的口径其实还有微妙差别。Google 的描述原文是:攻击者可以 “corrupt adjacent decoder state memory, disclose sensitive memory contents, cause a denial of service, or potentially execute arbitrary code”。注意那个 potentially。而 Node.js 的公告标题直接写 “out-of-bounds write permits remote code execution”,把那个限定词丢了。

CWE 也标了两个:CWE-252 未检查返回值、CWE-787 越界写。CWE-252 就是全部故事的核心——DecodeBlockTypeAndLength 返回的布尔值被过载成了”流非法”和”需要更多输入”两种含义,调用方没检查。

顺便说一句,这批公告里另外九个 CVE 更尴尬:截至目前它们在 CVE.org 上仍然是 RESERVED 状态,没有发布记录、没有分数,NVD 里也没有条目。谁是这些编号的 CNA 都没公开。也就是说官方公告给了十个标题十个等级,但只有这一个能查到权威评分。

三、”升级 Node.js”在哪些机器上根本不成立

这是我觉得最该被讲出来的一层。

Node.js 官方公告说的是”升级到 22.23.4 / 24.22.1 / 26.12.1″。这句话在官方二进制分发、自编译、容器镜像上都成立。但 Debian 和 Ubuntu 不一样——Debian 的 nodejs 包是用 --shared-brotli 编译的。

这不是我推测的。Debian 源码包里 debian/rules 的 DEB_CONFIGURE_EXTRA_FLAGS 里明明白白列着 --shared-brotli(和 --shared-zlib、--shared-cares、--shared-zstd 排在一起)。同样机制的一串依赖还有十来个。

Debian 安全追踪器在这个问题下面甚至直接写了一句 Notes:“nodejs uses system provided brotli library”。

Debian 安全追踪器中 CVE-2026-111497 的状态

图:Debian 安全追踪器 CVE-2026-111497 页面,截图时间 2026-10-23,来源 security-tracker.debian.org

看这张表的 Status 列——brotli 和 nodejs 两个源包全线 vulnerable:

源包发布版版本状态
brotlibookworm1.0.9-2vulnerable
brotlitrixie1.1.0-2vulnerable
brotliforky, sid1.2.0-4vulnerable
nodejsbookworm18.20.4+dfsg-1~deb12u2vulnerable
nodejstrixie20.19.2+dfsg-1+deb13u2vulnerable
nodejssid24.22.0+dfsg+~cs24.19.2-2vulnerable

而下面那张表里,brotli 和 nodejs 两行的 Fixed Version 列都写着 (unfixed)。紧急度一栏,Debian 填的是 “unimportant”。

所以在 Debian 和 Ubuntu 上,今天执行 apt upgrade nodejs,你拿到的是 24.22.0——比修复版本 24.22.1 还低一个补丁号,而且它链接的 libbrotli 1.1.0 依然在 1.0.3 至 1.2.0 这个受影响区间里。Brotli 的修复只可能来自 brotli 库的更新,而 Debian 仓库里目前没有这个版本。

Homebrew 是同一个坑。它编译 node、node@24、node@22 三个 formula 时同样加了 --shared-brotli,链的是它自己的 brotli formula。在那边正确的操作是 brew upgrade brotli node,先升库再升 node。

已经做完的:Bun 1.4.4 内置的是 brotli v1.2.1。Cloudflare Workers 跑的是 workerd 不是 Node.js,node:zlib 里的 Brotli 由 Cloudflare 自己实现,官方至今没有就这个 CVE 发出任何声明——没人知道它到底受不受影响。

四、爆炸半径:默认就在解压 Brotli

漏洞本身的技术细节上一轮已经讲透了,这里只讲一件事:你的代码大概率根本没主动调用过 Brotli,但数据照样会流到那个解码器里。

Node.js 官方公告的原话是:Node.js 自己不会解码 Brotli,必须是你的代码或者某个库把 Brotli 数据喂给它。问题是”喂”这件事,在现代 Node 服务里是默认行为。

入站方向。 Express 5.3.0 依赖 body-parser 2.x,而 body-parser 从 2.0.0 开始支持 Brotli,其 inflate 选项默认就是 true。这意味着一个普通的 Express 5 应用,任何人发一个带 Content-Encoding: br 的 POST,请求体都会自动被解压、喂进那个有洞的解码器。JSON 解析、form 解析、raw、text,全中。

Express 4 不一样——它用的 body-parser 1.x 没有 Brotli 支持,所以只发 Accept-Encoding: br 的普通 GET 打不到它。

出站方向,这个面更大。 Node.js 内置的 fetch()(undici)、axios(除非显式 decompress: false)、got(decompress 默认 true)、node-fetch(compress 默认 true),全部默认解压 Content-Encoding: br 响应。

于是这些场景全都在射程内:

  • 链接预览、URL 缩略图服务
  • 抓取器、爬虫、聚合器
  • 调用不受你控制的第三方 API
  • webhook 发送端
  • AI agent 和 MCP server 里那些”去抓个网页看看”的动作

最后一条是这次最扎眼的。Convika 在核查时直接点了这句:一个由 AI 编码代理给你写的应用,可能压根不知道自己坐在第一行或第三行里。

真要临时挡一下,body-parser 的 inflate: false 可以关掉压缩体解析。但这是缓解,不是修复。排查的话直接搜代码:

grep -rE "express.json|express.urlencoded|express.raw|bodyParser|fetch(|axios|got|node-fetch|zlib.brotli" src/

五、WAF 挡得住的那一半,和挡不住的那一半

Vercel 这次的动作值得单独说一句:漏洞公布当天,Vercel 就上线了 WAF 规则,自动应用到每一个项目,零配置、不额外收费,被拦的请求能在项目的 Firewall 面板里看到。这种响应速度是云厂商的正常水平,值得肯定。

但他们自己在公告里写得很清楚,两个限制:

第一,WAF 只覆盖经过 Vercel 网络的流量。你的函数去 fetch 别人服务器拿回来的响应,WAF 一层都碰不到。而 CVE-2026-111497 最危险的那条路径恰恰是出站解压。

第二,原文那句话很硬:“reduces exposure but does not replace patching”——降低暴露面,但不替代打补丁。

而且要说清楚,WAF 在这里能起作用的原因有点反常识:畸形 Brotli 流在 HTTP 层是完全合法的,攻击特征在应用层。OX Security 的原话是,畸形输入在 HTTP 层完全合规,WAF 对内存安全漏洞无能为力。Vercel 能拦,是因为他们知道这个 CVE 的具体 payload 特征,做的是针对已知利用模式的规则匹配。

换句话说,这是一次针对已知威胁情报的临时缓解,不是通用防护。换一种构造方式,规则就未必覆盖。

顺便,OX Security 和 Vercel 都在同一时间发了同一条警告:别去 clone 社交媒体上的 exploit 和”修复脚本”。这两天满地都是假 PoC。

六、处置清单

按”你的 Node 从哪来”来分,比按新闻标题来分靠谱:

  1. 官方二进制 / 自编译 / 容器镜像 → 升到 22.23.4 / 24.22.1 / 26.12.1,重启进程。26.x 在 10 月 28 日转 LTS,24.x 从 10 月 20 日起是维护 LTS
  2. Node 20.x 和 25.x → 没有任何补丁,必须先迁到 22 或 24。20.x 今年 4 月 30 日就 EOL 了
  3. Debian / Ubuntu → apt upgrade nodejs 没用,Brotli 修复要等 Debian 打包 brotli 1.0.10/1.1.1/1.2.1。在此之前,body-parser 的 inflate: false 是唯一能立刻做的缓解;同时用上面的 grep 确认你的服务有没有出站 fetch
  4. Homebrew → brew upgrade brotli node,顺序不能反,然后重启 Node 进程
  5. Express 5 应用 → 优先确认有没有直接吃 POST 压缩体;没有的话风险主要在出站
  6. 自建 Next.js → Vercel 公告里点名了:Next.js 的图片优化不拦 Brotli 响应,所以自建部署是暴露的
  7. Node 之外还在用 Brotli 的 → 任何链接 1.0.3 至 1.2.0 的 brotli 库或二进制(不只是 Node)都需要单独排查,升到 1.0.10 / 1.1.1 / 1.2.1

七、总结

这个 CVE 的技术部分并不复杂,一个返回值没检查,一个布尔值被过载成两种语义。真正难看的是流程。

第一,上游修复没有打标。 一个顺带修掉高危漏洞的提交,在主干里躺了八个月,期间没有一个发行版包含它。八个月后一次性爆发式地打三个 tag 补 SECURITY 说明,说明维护者知道问题严重,但这个”知道”来得太晚,而且是外部逼出来的。

第二,披露来源已经变了。 报告人是 OpenAI Codex Security 的两位研究员。上周 PHP2Shell 是 AI 深度参与发现和 exploit 开发,这周 Node.js 的 Brotli 越界写由 AI 报给 Node.js 项目,再往后连 CA 私钥都能被一句 CTF 提示词恢复。开源安全的发现端正在被 AI 重写,而发布端的流程还停留在人工排期和邮件协调的年代——这个剪刀差只会越拉越大。

第三,官方给的处置建议不一定在你的机器上成立。 “升级 Node.js”这句话隐含了一个假设:你的 Node.js 自带那个有洞的 brotli。但 Debian 用 --shared-brotli 链系统库,Homebrew 同理,而这两个发行渠道都还没打出修复版本。依赖管理里最容易被忽略的一层,恰恰是决定你的补丁到底生不生效的那一层。

一个连”apt upgrade 修好了”都做不到的漏洞,才是这次真正值得记下来的东西。


素材出处:CVE.org / CVE AWG 官方 CVE-2026-111497 记录(CNA: Google LLC)|Node.js October 2026 Security Releases|google/brotli GitHub 仓库提交记录与 Release(0ed4268a、v1.2.1 / v1.1.1 / v1.0.10)|Debian 安全追踪器 security-tracker.debian.org|Debian nodejs 源码包 debian/rules|OX Security 技术分析|Vercel 安全公告

© 版权声明
THE END
喜欢就支持一下吧
点赞10 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容