
librsvg の use-after-free RCE チェーン(CVE-2026-96889)を、SVG ジェネレーター PoC と librsvg、Next.js、Satori 向けの緩和ガイダンスとともに解説します。
本ドキュメントでは「VectorFreed」を紹介します。これは、私(@rafabd1)が librsvg で発見した use-after-free(CVE-2026-96889)から始まる脆弱性チェーンです。Node.js/Sharp/libvips ビルドでは、このバグがコマンド実行につながりました。本ドキュメントでは、このバグ、これまでにアプリケーションで確認された経路、そして現在利用可能な修正について説明します。
SVG は XInclude を通じて別の SVG をインクルードできます。脆弱な経路では、libxml2 が外側のドキュメントでエンティティを展開している間に、librsvg がインクルードされたドキュメントのパースを開始します。インクルードされた SVG が同じ名前のエンティティを宣言している場合、librsvg は最初のエンティティを置き換えて解放します。libxml2 は依然としてそのポインタを保持しています。
インクルードされたパースが終了すると、libxml2 はその古いポインタで処理を続行します。その時点でメモリはすでに別の何かに属している可能性があるため、その後の書き込みでメモリを破壊する可能性があります。クラッシュはその結果の一つです。他のケースでは、これがコマンド実行にもつながりました。
攻撃者は librsvg に到達するために細工された SVG マークアップを必要とします。これはアプリケーションが SVG ファイルを受け入れるときに発生する可能性がありますが、アプリケーションがユーザー入力から SVG を構築するときにも発生する可能性があります。依存関係ツリーのどこかで librsvg を使用しているだけでは、悪用可能な経路が確立されるわけではありません。画像がレンダリングされるときに、入力が影響を受けるビルドに到達する必要があります。
私たちがテストした Next.js のルートは、SVG アップロードではなくテキストを受け入れました。それは、Node.js 版の ImageResponse 用のインライン SVG 内にそのテキストを配置しました。Satori の別のエスケープバグにより、テキストが生成された SVG マークアップを変更できるようになりました。その後 Sharp/libvips がその SVG を librsvg に渡しました。Vercel は Next.js の経路を CVE-2026-94545 として追跡しました。ImageResponse の Edge 版はこの経路の影響を受けません。以下が短い Next.js の再現です。
この調査中に、私は複数の下流製品で影響を受ける入力経路を特定し、そのうちのいくつか(上記の Next.js のケースを含む)でコマンド実行を確認しました。その入力がどのように librsvg に到達するかは製品ごとに異なります。だからこそ、上流の画像パーサーのバグが、一見無関係に見える場所で発生することがあるのです。最近の libheif のケースも別の例です。これは、librsvg を使用するすべての製品がリモートで悪用可能であることを意味するものではありません。
ImageResponse 経路の SVG コンテンツ、属性、またはスタイルに配置する場合に影響を受けます。16.3.6 にアップグレードしてください。Sharp のプリビルドバイナリを使用している場合は、アプリがインストールした @img/sharp-libvips-* パッケージを確認してください。それは libvips とその依存関係をバンドルしており、librsvg も含まれます。システムの librsvg のコピーを更新しても、アプリは古いものを使い続ける可能性があります。
UAF PoC には、いくつかの入力経路用の SVG ジェネレータが含まれており、チェーンの最初にある use-after-free を確認するために使用できます。
これまでのところ、細工された SVG からコマンド実行までこのチェーンを完全にたどる公開エクスプロイトは見つかっていません。しかし、バグとパッチはすでに公開されており、現在の AI ツールを使えば、それらから完全なチェーンを逆にたどるのはかなり簡単です。それを踏まえ、エクスプロイトがすでに公開されているものとして扱い、影響を受ける依存関係を更新するか、入力経路を緩和することをできるだけ早く行ってください。
[!WARNING] このチェーンには汎用的な RCE PoC はありません。ペイロードはターゲットごとに調整する必要があります。これまでに見たほとんどの公開「PoC」は、実際の RCE チェーンを再現していません。中には、主張されている実行を SVG の
<foreignObject>に依存しているものもありますが、それはここで説明されているエクスプロイト経路ではありません。
初期検証には、UAF PoC の方が実用的です。私は Next.js のケース(CVE-2026-94545)の RCE PoC を別のリポジトリで公開する予定です。また、今後数週間で技術的な解説記事を公開し、UAF からコマンド実行までの手順と、このチェーンに関する過去 1 か月の調査を振り返るポストモーテムを掲載する予定です。