
Documente la chaîne RCE use-after-free de VectorFreed dans librsvg (CVE-2026-96889) avec un PoC de générateur SVG et des conseils de remédiation pour librsvg, Next.js et Satori.
Ce document présente « VectorFreed », une chaîne de vulnérabilités qui commence par un use-after-free que j'ai (@rafabd1) découvert dans librsvg (CVE-2026-96889). Dans une build Node.js/Sharp/libvips, ce bug a conduit à une exécution de commandes. Il couvre le bug, les chemins confirmés dans les applications à ce jour, et les correctifs disponibles dès maintenant.
Un SVG peut inclure un autre SVG via XInclude. Dans le chemin vulnérable, librsvg commence à analyser un document inclus alors que libxml2 est encore en train de développer une entité dans le document externe. Si le SVG inclus déclare une entité portant le même nom, librsvg remplace et libère la première entité. libxml2 détient toujours un pointeur vers celle-ci.
Lorsque l'analyse du document inclus se termine, libxml2 poursuit avec cet ancien pointeur. La mémoire peut déjà appartenir à autre chose à ce moment-là, de sorte que des écritures ultérieures peuvent la corrompre. Un crash est l'un des résultats possibles. Dans d'autres cas, cela a également conduit à une exécution de commandes.
L'attaquant a besoin d'un balisage SVG crafté pour atteindre librsvg. Cela peut se produire lorsqu'une application accepte un fichier SVG, mais aussi lorsqu'une application construit un SVG à partir d'une entrée utilisateur. Le simple fait d'utiliser librsvg quelque part dans l'arbre de dépendances n'établit pas un chemin exploitable ; l'entrée doit atteindre une build affectée au moment où l'image est rendue.
La route Next.js que nous avons testée acceptait du texte au lieu d'un upload SVG. Elle plaçait ce texte à l'intérieur d'un SVG inline pour la version Node.js de ImageResponse. Un bug d'échappement distinct dans Satori permettait au texte de modifier le balisage SVG généré. Sharp/libvips transmettait ensuite ce SVG à librsvg. Vercel a suivi le chemin Next.js sous CVE-2026-94545. La version Edge de ImageResponse n'est pas affectée par ce chemin. Voici une courte reproduction Next.js.
Une seconde route Next.js atteignait le même bug librsvg via l'API Image Optimization. Lorsqu'une source d'image contrôlée par l'attaquant était acceptée par l'API, une image craftée pouvait passer le rejet SVG du framework et être ensuite traitée comme SVG par Sharp/libvips. Cela exposait la corruption mémoire en amont à des requêtes non authentifiées sur Linux basé sur glibc, sans utiliser Satori ni ImageResponse.
Vercel a publié ce chemin sous GHSA-2464-fhr4-w9xw, sous le CVE-2026-96889 en amont. L'avis le classe Critique avec un score CVSS de 9.5.
Ghost a un chemin différent. Un utilisateur membre du staff, y compris un Contributor, pouvait créer une carte bookmark pour un site qu'il contrôle. Le traitement de l'image de la carte pouvait alors exécuter des commandes sur le serveur Ghost. Ghost a publié cela sous CVE-2026-105642.
Au cours de cette recherche, j'ai identifié des chemins d'entrée affectés dans plusieurs produits en aval et confirmé l'exécution de commandes dans plusieurs d'entre eux, y compris les deux routes Next.js et le cas Ghost ci-dessus. La manière dont cette entrée atteint librsvg varie d'un produit à l'autre. C'est pourquoi un bug de parseur d'image en amont peut surgir dans des endroits qui ne semblent pas liés au premier abord ; le récent cas libheif en est un autre exemple. Cela ne signifie pas que tout produit utilisant librsvg est exploitable à distance.
ImageResponse) : Les versions 16.2.0 à 16.3.5 sont affectées lorsqu'une application place des valeurs contrôlées par l'attaquant dans du contenu, des attributs ou des styles SVG. Mettez à niveau vers 16.3.6.>= 10.0.0 <= 15.5.27 et > 16.0.0 <= 16.4.0 comme affectées. Mettez à niveau vers 15.5.28 ou 16.4.1. Sharp 0.35.5 ou une version ultérieure contient le correctif en amont.Si vous utilisez les binaires précompilés de Sharp, vérifiez le paquet @img/sharp-libvips-* installé par votre application. Il embarque libvips et ses dépendances, y compris librsvg. La mise à jour de la copie système de librsvg peut laisser votre application utiliser l'ancienne.
Le PoC UAF inclut un générateur SVG pour plusieurs chemins d'entrée et peut être utilisé pour vérifier le use-after-free au début de la chaîne.
Le PoC RCE Next.js ImageResponse d'EQSTLab est un exemple fonctionnel de cette chaîne pour sa version épinglée de Node.js/Sharp. Il génère et envoie automatiquement la charge utile. Un exploit fonctionnel est désormais public, alors mettez à jour les dépendances affectées ou atténuez le chemin d'entrée dès que possible.
[!WARNING] Il n'existe pas de PoC RCE universel pour cette chaîne. L'exemple d'EQSTLab cible sa version épinglée ; d'autres cibles peuvent nécessiter des charges utiles différentes. Les PoC qui reposent sur le
<foreignObject>SVG pour l'exécution de commandes ne démontrent pas la chaîne décrite ici.
Pour une validation initiale sur d'autres cibles, le PoC UAF est plus pratique. Je publierai également l'analyse technique dans les semaines à venir, avec les étapes allant de l'UAF à l'exécution de commandes et un post-mortem couvrant ce mois de recherche sur la chaîne.