
Documenta la catena RCE use-after-free di VectorFreed su librsvg (CVE-2026-96889) con un PoC di generazione SVG e indicazioni di remediation per librsvg, Next.js e Satori.
Questo documento introduce "VectorFreed", una catena di vulnerabilità che inizia con un use-after-free che io (@rafabd1) ho trovato in librsvg (CVE-2026-96889). In una build Node.js/Sharp/libvips, questo bug ha portato all'esecuzione di comandi. Copre il bug, i percorsi finora confermati nelle applicazioni e le correzioni attualmente disponibili.
Un SVG può includere un altro SVG tramite XInclude. Nel percorso vulnerabile, librsvg inizia ad analizzare un documento incluso mentre libxml2 sta ancora espandendo un'entità in quello esterno. Se l'SVG incluso dichiara un'entità con lo stesso nome, librsvg sostituisce e libera la prima entità. libxml2 ne conserva ancora un puntatore.
Quando l'analisi del documento incluso termina, libxml2 prosegue con quel vecchio puntatore. A quel punto la memoria potrebbe già appartenere a qualcos'altro, quindi scritture successive possono corromperla. Un crash è uno dei risultati. In altri casi, questo ha portato anche all'esecuzione di comandi.
L'attaccante ha bisogno di markup SVG appositamente costruito per raggiungere librsvg. Ciò può accadere quando un'applicazione accetta un file SVG, ma può anche accadere quando l'applicazione costruisce un SVG dall'input dell'utente. Il semplice utilizzo di librsvg da qualche parte nell'albero delle dipendenze non stabilisce un percorso sfruttabile; l'input deve raggiungere una build interessata quando l'immagine viene renderizzata.
La route di Next.js che abbiamo testato accettava testo invece di un upload SVG. Inseriva quel testo all'interno di un SVG inline per la versione Node.js di ImageResponse. Un bug di escaping separato in Satori permetteva al testo di modificare il markup SVG generato. Sharp/libvips passava poi quell'SVG a librsvg. Vercel ha tracciato il percorso Next.js come CVE-2026-94545. La versione Edge di ImageResponse non è interessata da questo percorso. Ecco una breve riproduzione per Next.js.
Una seconda route di Next.js raggiungeva lo stesso bug di librsvg attraverso l'API Image Optimization. Quando una sorgente immagine controllata dall'attaccante veniva accettata dall'API, un'immagine appositamente costruita poteva superare il rifiuto degli SVG del framework e successivamente essere gestita come SVG da Sharp/libvips. Questo esponeva la corruzione di memoria upstream a richieste non autenticate su Linux basato su glibc senza utilizzare Satori o ImageResponse.
Vercel ha pubblicato questo percorso come GHSA-2464-fhr4-w9xw, sotto il CVE upstream CVE-2026-96889. L'advisory lo classifica come Critical con un punteggio CVSS di 9.5.
Ghost ha un percorso diverso. Un utente dello staff, incluso un Contributor, poteva creare una bookmark card per un sito che controllava. L'elaborazione dell'immagine della card poteva quindi eseguire comandi sul server Ghost. Ghost ha pubblicato questo come CVE-2026-105642.
Durante questa ricerca, ho identificato percorsi di input interessati in molteplici prodotti downstream e ho confermato l'esecuzione di comandi in diversi di essi, incluse entrambe le route di Next.js e il caso Ghost sopra. Il modo in cui quell'input raggiunge librsvg varia da prodotto a prodotto. Ecco perché un bug upstream in un parser di immagini può saltare fuori in luoghi che a prima vista non sembrano correlati; il recente caso libheif è un altro esempio. Non significa che ogni prodotto che utilizza librsvg sia sfruttabile da remoto.
ImageResponse): Le versioni dalla 16.2.0 alla 16.3.5 sono interessate quando un'applicazione inserisce valori controllati dall'attaccante in contenuti, attributi o stili SVG. Aggiorna alla 16.3.6.>= 10.0.0 <= 15.5.27 e > 16.0.0 <= 16.4.0 come interessate. Aggiorna alla 15.5.28 o alla 16.4.1. Sharp 0.35.5 o successivo contiene la correzione upstream.Se utilizzi i binari precompilati di Sharp, controlla il pacchetto @img/sharp-libvips-* installato dalla tua app. Esso include libvips e le sue dipendenze, tra cui librsvg. Aggiornare la copia di sistema di librsvg potrebbe lasciare la tua app con quella vecchia.
La PoC UAF include un generatore SVG per diversi percorsi di input e può essere usata per verificare la use-after-free all'inizio della catena.
La PoC RCE di EQSTLab per Next.js ImageResponse è un esempio funzionante di quella catena per la sua build Node.js/Sharp fissata. Genera e invia automaticamente il payload. Un exploit funzionante è ora pubblico, quindi aggiorna le dipendenze interessate o mitiga il percorso di input il prima possibile.
[!WARNING] Non esiste una PoC RCE universale per questa catena. L'esempio di EQSTLab prende di mira la sua build fissata; altri target potrebbero richiedere payload diversi. Le PoC che si basano su SVG
<foreignObject>per l'esecuzione di comandi non dimostrano la catena qui descritta.
Per una validazione iniziale su altri target, la PoC UAF è più pratica. Pubblicherò anche il write-up tecnico nelle prossime settimane, con i passaggi dalla UAF all'esecuzione di comandi e un post-mortem che copre quest'ultimo mese di ricerca sulla catena.