
Documenta a cadeia de RCE use-after-free do VectorFreed no librsvg (CVE-2026-96889) com um PoC gerador de SVG e orientações de remediação para librsvg, Next.js e Satori.
Este documento apresenta o "VectorFreed", uma cadeia de vulnerabilidades que começa com um use-after-free que eu (@rafabd1) encontrei no librsvg (CVE-2026-96889). Em uma build de Node.js/Sharp/libvips, esse bug levou à execução de comandos. Ele aborda o bug, os caminhos confirmados em aplicações até agora e as correções disponíveis no momento.
Um SVG pode incluir outro SVG por meio de XInclude. No caminho vulnerável, o librsvg começa a analisar um documento incluído enquanto o libxml2 ainda está expandindo uma entidade no documento externo. Se o SVG incluído declarar uma entidade com o mesmo nome, o librsvg substitui e libera a primeira entidade. O libxml2 ainda mantém um ponteiro para ela.
Quando a análise do documento incluído termina, o libxml2 continua com esse ponteiro antigo. A memória já pode pertencer a outra coisa nesse momento, então escritas posteriores podem corrompê-la. Um crash é um dos resultados. Em outros casos, isso também levou à execução de comandos.
O atacante precisa de marcação SVG elaborada para alcançar o librsvg. Isso pode acontecer quando uma aplicação aceita um arquivo SVG, mas também pode acontecer quando a aplicação constrói um SVG a partir da entrada do usuário. Apenas usar o librsvg em algum lugar da árvore de dependências não estabelece um caminho explorável; a entrada precisa alcançar uma build afetada quando a imagem é renderizada.
A rota do Next.js que testamos aceitava texto em vez de um upload de SVG. Ela colocava esse texto dentro de um SVG inline para a versão Node.js do ImageResponse. Um bug de escaping separado no Satori permitia que o texto alterasse a marcação SVG gerada. O Sharp/libvips então passava esse SVG para o librsvg. A Vercel rastreou o caminho do Next.js como CVE-2026-94545. A versão Edge do ImageResponse não é afetada por esse caminho. Aqui está uma breve reprodução no Next.js.
Durante esta pesquisa, identifiquei caminhos de entrada afetados em vários produtos downstream e confirmei a execução de comandos em vários deles, incluindo o caso do Next.js descrito acima. Como essa entrada alcança o librsvg varia de produto para produto. É por isso que um bug em um parser de imagens upstream pode aparecer em lugares que não parecem relacionados à primeira vista; o recente caso do libheif é outro exemplo. Isso não significa que todo produto que usa o librsvg seja explorável remotamente.
ImageResponse do Node.js. Atualize para a 16.3.6.Se você usa os binários pré-compilados do Sharp, verifique o pacote @img/sharp-libvips-* que sua aplicação instalou. Ele empacota o libvips e suas dependências, incluindo o librsvg. Atualizar a cópia do librsvg do sistema pode deixar sua aplicação usando a versão antiga.
O PoC de UAF inclui um gerador de SVG para vários caminhos de entrada e pode ser usado para verificar o use-after-free no início da cadeia.
Até agora, não encontrei um exploit público que leve essa cadeia do SVG elaborado até a execução de comandos. No entanto, o bug e os patches já são públicos e, com as ferramentas de IA atuais, é relativamente fácil reconstruir a cadeia completa a partir deles. Diante disso, trate o exploit como se já fosse público e atualize as dependências afetadas ou mitigue o caminho de entrada o quanto antes.
[!WARNING] Não existe um PoC universal de RCE para essa cadeia; o payload precisa ser ajustado para cada alvo. A maioria dos "PoCs" públicos que vi até agora não reproduz a cadeia de RCE real. Alguns dependem do
<foreignObject>do SVG para a execução alegada, o que não é o caminho de exploit descrito aqui.
Para validação inicial, o PoC de UAF é mais prático. Pretendo publicar um PoC de RCE para o caso do Next.js (CVE-2026-94545) em um repositório separado. Também publicarei o write-up técnico nas próximas semanas, com os passos do UAF até a execução de comandos e um post-mortem cobrindo este último mês de pesquisa sobre a cadeia.