本文介绍“VectorFreed”,一条始于我在 librsvg 中发现的释放后使用漏洞的漏洞利用链(CVE-2026-96889)。在 Node.js/Sharp/libvips 构建中,该漏洞可导致命令执行。本文涵盖该漏洞、目前已在应用程序中确认的路径,以及当前可用的修复方案。
一个 SVG 可以通过 XInclude 包含另一个 SVG。在存在漏洞的路径中,当 libxml2 仍在展开外部文档中的实体时,librsvg 就开始解析被包含的文档。如果被包含的 SVG 声明了同名实体,librsvg 会替换并释放第一个实体。而 libxml2 仍持有指向它的指针。
当被包含的解析结束时,libxml2 会继续使用那个旧指针。此时该内存可能已属于其他对象,因此后续写入可能造成内存破坏。崩溃是其中一种结果。在其他情况下,这也会导致命令执行。
攻击者需要构造特制的 SVG 标记才能触达 librsvg。当应用程序接受 SVG 文件时可能发生,但当应用程序根据用户输入构建 SVG 时也可能发生。仅仅在依赖树中的某处使用 librsvg 并不构成可利用路径;输入必须在图像渲染时到达受影响的构建。
我们测试的 Next.js 路由接受的是文本而非 SVG 上传。它将该文本放入用于 Node.js 版 ImageResponse 的内联 SVG 中。Satori 中一个单独的转义漏洞使该文本能够改变生成的 SVG 标记。随后 Sharp/libvips 将该 SVG 传递给 librsvg。Vercel 将 Next.js 路径追踪为 CVE-2026-94545。Edge 版 ImageResponse 不受此路径影响。这里有一个简短的 Next.js 复现。
在此次研究过程中,我在多个下游产品中识别出受影响的输入路径,并在其中若干产品中确认了命令执行,包括上述 Next.js 案例。输入如何到达 librsvg 因产品而异。这就是为什么一个上游图像解析器漏洞会出现在乍看之下并不相关的地方;最近的 libheif 案例是另一个例子。这并不意味着每个使用 librsvg 的产品都可被远程利用。
ImageResponse 路径上将攻击者可控的值放入 SVG 内容、属性或样式时,16.2.0 至 16.3.5 版本会受影响。请升级到 16.3.6。如果你使用 Sharp 的预编译二进制文件,请检查你的应用安装的 @img/sharp-libvips-* 包。它捆绑了 libvips 及其依赖项,包括 librsvg。更新系统中的 librsvg 副本可能会让你的应用仍在使用旧版本。
UAF PoC 包含针对多个输入路径的 SVG 生成器,可用于检查利用链起点的释放后使用漏洞。
到目前为止,我还没有找到能将这条链从特制 SVG 一路推进到命令执行的公开漏洞利用。不过,该漏洞和补丁已经公开,而且借助当前的 AI 工具,从它们反推出完整利用链相当容易。鉴于此,请将该漏洞利用视为已经公开,并尽快更新受影响的依赖项或缓解输入路径。
[!WARNING] 这条链没有通用的 RCE PoC;有效载荷需要针对每个目标进行调整。我目前见过的大多数公开“PoC”并不能复现真正的 RCE 链。有些依赖 SVG
<foreignObject>来实现其声称的执行,而这并非本文描述的漏洞利用路径。
对于初步验证,UAF PoC 更为实用。我计划在单独的仓库中发布针对 Next.js 案例(CVE-2026-94545)的 RCE PoC。我还将在未来几周内发布技术分析文章,包含从 UAF 到命令执行的步骤,以及涵盖过去一个月对该链研究的复盘。