
VectorFreed librsvg use-after-free RCE 체인(CVE-2026-96889)을 SVG 생성기 PoC 및 librsvg, Next.js, Satori에 대한 완화 지침과 함께 문서화합니다.
이 문서는 librsvg에서 제가(@rafabd1) 발견한 use-after-free 취약점(CVE-2026-96889)으로 시작되는 취약점 체인인 "VectorFreed"를 소개합니다. 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 라우트는 Image Optimization API를 통해 동일한 librsvg 버그에 도달했습니다. 공격자가 제어하는 이미지 소스가 API에 의해 허용되었을 때, 조작된 이미지가 프레임워크의 SVG 거부를 통과하여 나중에 Sharp/libvips에 의해 SVG로 처리될 수 있었습니다. 이는 Satori나 ImageResponse를 사용하지 않고도 glibc 기반 Linux에서 인증되지 않은 요청에 업스트림 메모리 손상을 노출시켰습니다.
Vercel은 이 경로를 업스트림 CVE-2026-96889에 따라 GHSA-2464-fhr4-w9xw로 게시했습니다. 이 권고는 CVSS 점수 9.5로 Critical로 평가합니다.
Ghost는 다른 경로를 가지고 있습니다. Contributor를 포함한 스태프 사용자가 자신이 제어하는 사이트에 대한 북마크 카드를 만들 수 있었습니다. 그런 다음 카드 이미지를 처리하면서 Ghost 서버에서 명령을 실행할 수 있었습니다. Ghost는 이를 CVE-2026-105642로 게시했습니다.
이 연구 동안 저는 여러 다운스트림 제품에서 영향을 받는 입력 경로를 식별했고, 위의 두 Next.js 라우트와 Ghost 사례를 포함한 여러 제품에서 명령 실행을 확인했습니다. 그 입력이 librsvg에 도달하는 방식은 제품마다 다릅니다. 이것이 업스트림 이미지 파서 버그가 처음에는 관련 없어 보이는 곳에서 나타날 수 있는 이유입니다. 최근의 libheif 사례가 또 다른 예입니다. 이는 librsvg를 사용하는 모든 제품이 원격으로 악용 가능하다는 것을 의미하지는 않습니다.
ImageResponse): 애플리케이션이 공격자가 제어하는 값을 SVG 콘텐츠, 속성 또는 스타일에 넣는 경우 16.2.0부터 16.3.5 버전이 영향을 받습니다. 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에서 명령 실행까지의 단계와 이 체인에 대한 지난 한 달간의 연구를 다루는 사후 분석을 포함한 기술 문서를 앞으로 몇 주 내에 게시할 예정입니다.