
VectorFreed librsvg use-after-free RCE 체인(CVE-2026-96889)을 SVG 생성기 PoC 및 librsvg, Next.js, Satori에 대한 완화 지침과 함께 문서화합니다.
이 문서는 librsvg에서 제가(@rafabd1) 발견한 use-after-free로 시작되는 취약점 체인인 "VectorFreed"를 소개합니다(CVE-2026-96889). Node.js/Sharp/libvips 빌드에서는 이 버그가 명령 실행으로 이어졌습니다. 이 문서는 버그, 지금까지 애플리케이션에서 확인된 경로, 그리고 현재 사용 가능한 수정 사항을 다룹니다.
SVG는 XInclude를 통해 다른 SVG를 포함할 수 있습니다. 취약한 경로에서 librsvg는 libxml2가 외부 문서의 엔티티를 아직 확장하고 있는 동안 포함된 문서의 파싱을 시작합니다. 포함된 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-* 패키지를 확인하세요. 이 패키지는 librsvg를 포함하여 libvips와 그 의존성을 번들로 제공합니다. 시스템의 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에서 명령 실행까지의 단계와 이 체인에 대한 지난 한 달간의 연구를 다루는 사후 분석을 포함한 기술 문서를 앞으로 몇 주 안에 게시할 것입니다.