
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の再現です。
2つ目のNext.jsのルートは、Image Optimization APIを通じて同じlibrsvgのバグに到達しました。攻撃者が制御する画像ソースがAPIに受け入れられたとき、細工された画像がフレームワークのSVG拒否を通過し、後にSharp/libvipsによってSVGとして処理される可能性がありました。これにより、SatoriやImageResponseを使用することなく、glibcベースのLinux上で認証されていないリクエストに対して上流のメモリ破壊が露出しました。
Vercelはこの経路を、上流のCVE-2026-96889の下でGHSA-2464-fhr4-w9xwとして公開しました。アドバイザリはこれをCritical、CVSSスコア9.5と評価しています。
Ghostには別の経路があります。Contributorを含むスタッフユーザーが、自分が制御するサイトのブックマークカードを作成できました。その後、カード画像の処理がGhostサーバー上でコマンドを実行する可能性がありました。GhostはこれをCVE-2026-105642として公開しました。
この調査中に、私は複数の下流製品で影響を受ける入力経路を特定し、そのうちのいくつか(上記の両方のNext.js経路とGhostのケースを含む)でコマンド実行を確認しました。その入力がどのようにlibrsvgに到達するかは製品ごとに異なります。だからこそ、上流の画像パーサーのバグが、一見無関係に見える場所で発見されることがあります。最近のlibheifのケースも別の例です。これは、librsvgを使用するすべての製品がリモートで悪用可能であることを意味するものではありません。
ImageResponse): バージョン 16.2.0 から 16.3.5 は、アプリケーションが攻撃者制御の値を SVG コンテンツ、属性、またはスタイルに挿入する場合に影響を受けます。16.3.6 にアップグレードしてください。>= 10.0.0 <= 15.5.27 および > 16.0.0 <= 16.4.0 が影響を受けると記載されています。15.5.28 または 16.4.1 にアップグレードしてください。Sharp 0.35.5 以降には上流の修正が含まれています。Sharp のプリビルドバイナリを使用している場合は、アプリがインストールした @img/sharp-libvips-* パッケージを確認してください。これには librsvg を含む libvips とその依存関係がバンドルされています。システムの librsvg を更新しても、アプリは古いものを使用し続ける可能性があります。
UAF PoC には、いくつかの入力パス向けの SVG ジェネレータが含まれており、チェーンの開始時点での use-after-free を確認するために使用できます。
EQSTLab Next.js ImageResponse RCE PoC は、固定された Node.js/Sharp ビルド向けのこのチェーンの動作例です。ペイロードを自動的に生成して送信します。動作するエクスプロイトが現在公開されているため、影響を受ける依存関係を更新するか、できるだけ早く入力パスを緩和してください。
[!WARNING] このチェーンに対する汎用的な RCE PoC は存在しません。EQSTLab の例は固定されたビルドを対象としています。他のターゲットでは異なるペイロードが必要になる場合があります。コマンド実行に SVG
<foreignObject>に依存する PoC は、ここで説明するチェーンを実証するものではありません。
他のターゲットでの初期検証には、UAF PoC の方が実用的です。また、今後数週間で、UAF からコマンド実行に至るまでの手順と、このチェーンに関する過去 1 か月の研究を振り返るポストモーテムを含む技術記事を公開する予定です。