Node.js 十月安全更新深度分析:Brotli RCE、TLS 校验绕过与 10 项漏洞修复

2026 年 10 月 21 日的 Node.js 安全更新列出 10 项具名漏洞,最高等级为 High。其中包括 Brotli 解码器可能导致远程代码执行、TLS 主机名校验绕过,以及启动快照导致随机数缓存重复使用等问题。
这次需要注意的不只是网站接收请求的入口。后端主动访问远程资源、复用 HTTP 连接、生成单文件可执行程序,也可能涉及不同的漏洞条件。本文结合官方公告、发布说明和公开修复代码,分析应该检查哪些实际路径。
信息截至:2026 年 10 月 21 日 23:50,UTC+8。 查证时修复版本已经可用。下文风险场景根据公开资料和代码路径推导,不是已确认的受害案例,也不是本文复现成功的攻击结果。
更新重点与修复版本
Node.js 官方安全公告给出的修复版本如下。请在正在使用的分支安装相应修复版本,或该分支后续已经包含修复的版本。
按官方列出的具名问题统计,共 4 项 High、3 项 Medium、3 项 Low。这次发布还更新了依赖组件和证书数据,因此不能把全部发布内容等同于这十项 CVE。
Node.js 18、20 等旧分支已经在官方维护状态表中标为 EOL。相关系统需要规划迁移至受支持分支;如果依赖供应商提供延长维护或回补补丁,应取得对应公告和软件包修订号作为依据。
十项漏洞分别影响哪些分支?
下表按官方安全公告整理。它描述的是公告列出的分支,不表示每个历史版本、每种配置都能以同样方式被利用。公告没有逐项给出所有漏洞最早引入的版本。
| 漏洞 | 等级 | 公告列出的分支 | 主要问题 |
|---|---|---|---|
| CVE-2026-111497 | High | 22/24/26 | Brotli 解码器越界写入,可导致远程代码执行 |
| CVE-2026-105482 | High | 22/24/26 | DNS 名称中的 NUL 字符可能导致解析名称被截断 |
| CVE-2026-105483 | High | 24/26 | 全角数字表示的 IP 可能绕过 TLS 主机名校验 |
| CVE-2026-106069 | High | 22/24/26 | 可被宽松解析为 IP 的主机名可能绕过 TLS 校验 |
| CVE-2026-105481 | Medium | 22/24/26 | Keep-alive 连接可能把请求发出前的数据当作响应 |
| CVE-2026-106072 | Medium | 22/24/26 | 非标准 IPv4 主机名可能让 DNS 类型的证书标识被用于 IP 端点 |
| CVE-2026-106074 | Medium | 22/24/26 | 启动快照或 SEA 保存随机数缓存,使不同进程重复输出相同值 |
| CVE-2026-106070 | Low | 26 | ZIP 头校验失败后,后续读取可能返回攻击者可控的前缀数据 |
| CVE-2026-106071 | Low | 26 | Permission Model 的通配符路径匹配可能授予过多权限 |
| CVE-2026-106073 | Low | 22/24/26 | fs.realpathSync 缺少必要的 Permission Model 检查 |
提交数量不能直接当作漏洞数量。TLS 的 106069 和 106072 由同一个修复提交处理,但官方对二者给出的严重等级不同。
Brotli RCE:后端向外抓取内容也需要排查
CVE-2026-111497 的关键,是应用是否将不可信的 Brotli 压缩数据交给存在漏洞的解码器。官方确认其可能导致远程代码执行;这不足以证明任何 Node.js 网站都能被一个通用 HTTP 请求直接攻破。
Brotli 上游补丁调整了块切换的错误处理,使无效数据流更早被识别,并将错误向调用方传递。问题位于原生解码器对异常输入的处理,仅在 JavaScript 外层添加异常捕获,不能替代运行时修复。
容易漏掉的路径是服务器主动发起出站请求。修复版内置的 Undici fetch 源码显示,当响应内容编码为 br 时,会调用 Brotli 解码器。
因此,接受用户提供的网址、导入远程内容、读取可由攻击者控制的响应,以及处理外来压缩文件,都是值得排查的场景。这是依据数据流推导的检查范围,不代表每个场景都已证实可成功利用。
如果服务只是把内容压缩成 Brotli 后发给浏览器,也不能据此确认触发了解码漏洞。排查需要弄清数据的提供方和解压方,而不是只搜索配置中是否出现 Brotli。
DNS 与 TLS:名称解析和身份校验需要保持一致
这组问题共同涉及一个边界:同一份输入经过不同组件处理后,可能被理解为不同的名称或地址。
NUL 截断可能造成校验值与解析值不一致
CVE-2026-105482 涉及名称中的 NUL,即数值为零的字符。修复代码将 DNS 解析入口改为拒绝包含 NUL 的字符串,覆盖 callback 和 Promise 解析流程。
如果业务代码对完整字符串做访问限制,后续解析层却只使用截断后的部分,就可能出现校验落差。能否进一步构成 SSRF 等应用层问题,仍取决于输入来源、限制规则和连接方式,不能只根据 CVE 标题下结论。
TLS 主机名绕过影响的是对端身份确认
105483、106069、106072 涉及全角数字、非标准 IP 写法与证书名称匹配。HTTPS 除了验证证书链,还需要确认对端身份符合预期主机。
在 26.12.1 的最终 TLS 源码中,原字符串不是标准 IP、经名称转换后却变为 IP 的情况会被拒绝;标准 IP 则按 IP 地址类型的证书标识进行匹配。修复收紧了名称转换与身份验证之间的边界。
接受自定义 URL 的代理、远程导入、链接预览和具有出站访问限制的服务,应优先检查这些路径。利用仍需要可达的输入流程及合适的证书、端点等条件,不能扩大描述为所有 HTTPS 连接都已失去保护。
升级后如果原本接受的非标准名称开始报错,应修正输入和证书配置,并保留 TLS 身份验证。
HTTP 连接与随机数快照:Medium 同样有具体影响
Keep-alive 关注响应是否属于当前请求
CVE-2026-105481 涉及 HTTP Agent 重用空闲连接时,新请求还没有发出,操作系统的 Socket 缓冲区里已经存在待处理的数据。
修复提交说明,原有防护依赖事件循环进行 I/O 轮询,可能尚未观察到这些数据。新版在复用之前检查待读状态,必要时销毁连接。
使用连接池的 API 集成需要关注响应与请求的对应关系。不能把这个问题直接改称为已证实的服务端 request smuggling,也不能在缺少证据时宣称能跨账号读取数据。
启动快照可能把未消费的随机数缓存一并复制
CVE-2026-106074 的条件是使用启动快照,或包含相关快照状态的单文件可执行程序 SEA,并把 randomUUID()/randomInt() 尚未消费的缓存保存进去。不同进程从相同状态启动时,可能重播相同值。
补丁在序列化及反序列化的关键阶段清理缓存。它针对特定打包与启动方式的状态复用,不等于所有 Node.js 随机数 API 都失效。
若应用把这些值用作必须不可预测的令牌,安全影响可能更大;作为标识符使用时,也可能遇到碰撞。这是业务场景分析,并不是已经发生令牌泄露的报告。
相关产物需要使用修复后的工具链重新构建。SEA 官方文档介绍了 Node.js 二进制文件与应用数据的打包关系,因此只升级宿主机上的另一份 Node.js,不能证明既有 SEA 已经替换内嵌的旧运行时。
Permission Model 与 ZIP 需要结合使用场景判断
CVE-2026-106071 和 106073 分别涉及通配符授权范围,以及 fs.realpathSync 的权限检查。后者的补丁明确要求先校验解析后的输入路径,避免后续路径遍历被用来探查授权集合之外的路径。
使用 –permission 的工具、文件处理流程或自动化系统应检查这两项。对于 realpath 问题,现有证据不能直接扩展为任意读取所有文件内容。
Permission Model 官方文档还说明,它限制受信任代码意外访问未授权资源,不保证能够隔离恶意代码。需要执行不可信代码的 AI 工具或服务,仍须设计操作系统层面的隔离。
CVE-2026-106070 涉及官方列出的 26.x ZIP 功能。修复改为先验证本地文件头与中央目录的一致性,再缓存文件头和内容偏移,避免校验失败后残留状态被后续读取误用。它关注错误路径和重试,不能自行扩写成任意文件写入漏洞。
npm audit 与运行时更新的职责不同
npm audit检查项目依赖包的已知漏洞。检查通过,不能直接证明正在执行应用的 Node.js 二进制文件、内置原生库和证书数据已经完成本次更新。
三份发布说明还显示,内置 Undici 分别更新至 22.x 的 6.29.1、24.x 的 7.30.1、26.x 的 8.12.2;22.x 和 24.x 更新 OpenSSL,22.x 还更新 SQLite,同时包括 c-ares 与证书相关更新。
这些内容可用于核对官方发行包。项目另外安装的 Undici,与 Node.js 为内置 fetch 提供的版本,需要分别检查;修改 package-lock.json 不会自动替换已经部署的 Node.js 可执行文件。
安全公告还列出与 eMudhra 中间 CA 事件有关的证书更新,说明修复范围也包括运行时携带的信任数据。
如何安排修复顺序,并确认部署完成?
可以按下面顺序排查。这是依据输入可达性整理的运维优先级,不是官方对具体服务的受害判断。
- 解压外来 Brotli 数据,或抓取用户可控来源的服务:优先确认原生解码器与实际 Node.js 已修复。
- 接受自定义主机名、URL 或实施出站访问限制的服务:检查 DNS、TLS 名称转换及校验流程。
- 大量使用 HTTP Agent 连接池的服务:验证升级后的响应对应、错误处理和重试行为。
- 生成快照、SEA 或使用 Permission Model 的工具:重建产物,测试实际启动路径与访问限制。
- 仅在构建阶段使用 Node.js、上线后由其他服务器提供静态文件的网站:排查 CI 和构建环境,并按实际架构确认是否存在公网 Node.js 进程。
请在实际服务的容器、进程启动环境或平台工作负载中检查版本,而不是只看本地终端:
1 | node -p "JSON.stringify({ node: process.version, executable: process.execPath, versions: process.versions }, null, 2)" |
命令只读取版本及可执行文件信息,不会升级系统。输出字段随版本和编译配置而异;发行版回补补丁还需要结合供应商的软件包修订号和公告判断。
部署之后,应确认运行进程已重启或替换、所有副本都加载修复版本、快照与 SEA 已重新生成、关键连接和解压流程通过测试。镜像标签变化或 CI 成功,不能独立证明旧工作负载已经退出流量。
同日的 PHP 漏洞与网站停机事件也体现了运行时更新的重要性。但 PHP 的停机名单不能用来证明这些 Node.js 漏洞已经被利用。是否暂时停服,应结合实际暴露路径、补丁可用性和部署能力判断。