
CVE-2026-5281 (Chrome Dawn WebGPU UAF) 분석, 실습 검증 도구, 취약한 빌드와 패치된 빌드에 대한 재현 환경.
이 취약점은 우리가 서비스를 제공하는 고객 중 하나에 영향을 미쳤습니다. 이 저장소는 원래 연구에 대한 우리의 기여입니다. 그룹을 위한 중앙 집중식 출발점으로, 이 구성 요소에 영향을 미치는 유사한 취약점이 다시 나타나면 이미 기반이 마련되어 있도록 합니다. 이 저장소는 버그 뒤에 있는 이론, 원래 연구자의 연구 결과에 대한 문서화된 요약, 그리고 실험실 환경에서 노출을 확인하는 실용적인 도구 세트를 한곳에 모아 놓습니다.
참고: 이 연구의 더 많은 내용을 공유하고 싶지만, 회사 제한으로 인해 더 이상 공개할 수 없습니다. 여기에 포함된 모든 것은 검토되었으며 제가 적용받는 어떤 계약도 위반하지 않습니다. 따라서 저장소는 현재 상태로 보관됩니다.
2026년 4월 1일, Google은 21개의 취약점을 해결하는 Chrome 보안 업데이트를 발표했습니다. 그중 하나인 CVE-2026-5281은 공개 시점에 이미 실제 환경에서 적극적으로 악용되고 있었습니다. 사흘 후, CISA는 이 취약점을 KEV(Known Exploited Vulnerabilities) 카탈로그에 추가하고 연방 기관에 패치를 요구하는 구속력 있는 운영 지시를 발령했습니다. 그 시점에 이미 이 취약점은 우리에게 영향을 미쳤습니다.
이 저장소는 한 가지 이유로 존재합니다. 이런 일이 다시 발생할 때 처음부터 시작하는 대신 출발점을 갖기 위해서입니다. 이 저장소는 다음을 한곳에 모아 둡니다:
취약점이 왜 존재하는지 이해하려면, 그 시스템이 무엇을 하도록 만들어졌고 어떤 가정을 기반으로 설계되었는지에서 출발해야 합니다.
WebGPU는 GPU(Graphics Processing Unit)에서 렌더링 및 계산과 같은 작업을 수행하기 위한 API를 제공합니다. WebGPU는 OpenGL이나 OpenGL ES(Embedded Systems)를 노출하려는 시도가 아닙니다. 이는 Direct3D 12, Metal, Vulkan과 같은 현대 API의 아이디어를 바탕으로 구축된 새로운 API입니다.
WebGPU는 브라우저가 수년간 사용해 온 기존 GPU API인 WebGL을 대체하는 현대적인 API입니다. 핵심 차이점은 WebGPU가 처음부터 안전성과 명시적인 리소스 관리를 염두에 두고 설계되었다는 것입니다. 모든 버퍼, 텍스처, 파이프라인의 수명 주기를 직접 선언해야 합니다. 브라우저는 JavaScript와 GPU 하드웨어 사이에서 검증 계층 역할을 합니다.
이 취약점의 중심에 있는 객체는 생성 순서대로 다음과 같습니다:``` GPUAdapter ← represents a physical GPU or software fallback └─ GPUDevice ← your logical connection to the adapter; owns everything ├─ GPUBuffer ← a chunk of GPU-accessible memory ├─ GPUShaderModule ← a compiled WGSL shader program ├─ GPUComputePipeline ← a shader wired to a pipeline layout ├─ GPUBindGroup ← binds buffers as inputs to a pipeline ├─ GPUCommandEncoder ← records a sequence of GPU commands └─ GPUQueue ← submits recorded commands to hardware
여기서 중요한 규칙: 모든 객체는 GPUDevice가 소유합니다. 해당 버퍼를 참조하는 명령이 디바이스에서 아직 실행 중인 동안 버퍼를 파괴하는 것은 스펙상 명시적으로 금지되어 있습니다. Dawn 구현은 이를 감지하고 거부해야 합니다. CVE-2026-5281은 그렇게 하지 못한 사례입니다.
---
---
---
<div id='whatisdawn'/>
## ***⚙️ Dawn이란 무엇인가?***
- **[Dawn - 오픈소스 WebGPU 구현](https://dawn.googlesource.com/dawn)**
> Dawn은 개발 중인 WebGPU 표준의 오픈소스이자 크로스 플랫폼 구현체입니다. 일부 확장 기능과 함께 WebGPU IDL을 미러링하는 네이티브 C++ API를 제공합니다.
Dawn은 Chrome 내부의 C++ 라이브러리로, WebGPU JavaScript 호출을 플랫폼 네이티브 GPU 명령으로 변환합니다. Windows에서는 D3D12, macOS에서는 Metal, Linux에서는 Vulkan을 대상으로 합니다. Chrome의 JavaScript 엔진과 하드웨어 드라이버 사이에 위치하며, API 호출 검증, 명령 직렬화, 객체 수명 추적, JavaScript로 오류를 다시 전달하는 네 가지 역할을 담당합니다.
CVE-2026-5281은 수명 추적 부분에 존재합니다. 구체적으로는, 해당 버퍼를 참조하는 명령이 하드웨어 큐에서 아직 실행 대기 중인 동안 Dawn이 GPU 버퍼 객체를 얼마나 오래 유지하는지에 관한 것입니다.```
JavaScript (V8)
│ WebGPU API calls
▼
Dawn (C++) - validates, serializes, tracks lifetimes, reports errors
│
▼
D3D12 (Windows) - Metal (macOS) - Vulkan (Linux)
│
▼
GPU hardware driver
│
▼
Physical GPU - shader cores, VRAM
Use-After-Free를 직관적으로 이해하려면 먼저 메모리에서 데이터가 어디에 저장되는지에 대한 명확한 개념이 필요합니다.``` High addresses ┌────────────────────────────────────┐ │ Kernel space │ The OS and drivers live here. │ │ User-mode code cannot touch it. ├────────────────────────────────────┤ │ Stack │ Function call frames. Fast. │ (grows downward) │ Freed automatically when the │ │ function returns. ├────────────────────────────────────┤ │ Heap │ Dynamic allocations - malloc, new, │ (grows upward) │ smart pointers like Ref. │ │ Freed only when you say so. ├────────────────────────────────────┤ │ BSS / Data / Text │ Globals, constants, compiled code. └────────────────────────────────────┘ Low addresses
Dawn의 C++ 객체(예: GPUBuffer를 뒷받침하는 내부 객체)는 힙에 존재합니다. 이들은 참조 카운트 방식으로 관리됩니다. 즉, 스마트 포인터가 객체에 대한 참조를 보유한 대상의 수를 추적합니다. 그 수가 0에 도달하면 소멸자가 실행되고 메모리는 할당자에게 반환됩니다.
GPUBuffer는 동시에 두 가지 표현을 가지는데, 하나는 CPU 측이고 다른 하나는 GPU 측입니다.```
CPU side (Dawn, system RAM)
└─ C++ object - metadata, state flags, and a hardware handle
│
│ handle: ID3D12Resource* (D3D12) - MTLBuffer (Metal) - VkBuffer (Vulkan)
▼
GPU side (driver, VRAM)
└─ Actual memory allocation on the graphics card
JavaScript가 buffer.destroy()를 호출하면 의도된 동작은 객체를 소멸된 것으로 표시하고, 참조 횟수를 줄이고, 하드웨어 핸들을 해제하고, VRAM을 해제하는 것입니다. CVE-2026-5281의 버그는 GPU 명령 큐가 여전히 해당 하드웨어 핸들에 대한 참조를 보유하고 있는 동안 VRAM이 해제되도록 하여, GPU가 더 이상 자신의 것이 아닌 메모리를 적극적으로 읽거나 쓰게 만듭니다.
CWE-416: Use After Free (MITRE)
해제된 메모리를 참조하면 프로그램이 충돌하거나 예기치 않은 값을 사용하거나 코드를 실행할 수 있습니다. 이전에 해제된 메모리를 사용하면 유효한 데이터의 손상부터 임의 코드 실행에 이르기까지 다양한 부정적 결과가 발생할 수 있습니다.
Use-After-Free는 고정된 3단계 패턴을 따르며, 브라우저 보안에서 가장 지속적으로 악용되는 메모리 안전 버그 클래스 중 하나입니다:```
2단계가 끝나면 할당자는 동일한 메모리 영역을 완전히 다른 할당에 넘길 수 있습니다. 공격자가 해제된 영역에 무엇이 들어갈지 제어할 수 있다면(힙 그루밍(heap grooming)이라는 기법), 스테일 포인터가 다시 읽어 들이는 값을 제어할 수 있습니다. 이것이 메모리 안전 버그가 코드 실행으로 이어지는 방식입니다.
GPU 측 UAF는 CPU 측 UAF보다 관찰하기 어렵습니다. 그 이유는 다음과 같습니다.
- '할당자'는 시스템 malloc이 아니라 GPU 드라이버의 VRAM 할당자입니다.
- '스테일 포인터'는 명령 큐가 여전히 참조하는 하드웨어 핸들입니다.
- GPU는 명령을 비동기적으로 실행하므로, CPU는 크래시가 발생하기 훨씬 전에 이미 다음 작업으로 넘어갑니다.
---
---
---
<div id='thevulnerability'/>
## ***🕳️ 취약점***
---
<div id='thevulnerability-whatweknow'/>
### ***📋 공개 소스에서 알려진 사항***
다음 내용은 전적으로 공개적으로 확인된 사실에 근거합니다.
- [NVD: CVE-2026-5281](https://nvd.nist.gov/vuln/detail/CVE-2026-5281)
> Google Chrome 146.0.7680.178 이전 버전의 Dawn에서 발생한 use-after-free 취약점으로 인해, 렌더러 프로세스를 장악한 원격 공격자가 조작된 HTML 페이지를 통해 임의 코드를 실행할 수 있었습니다.
- [The Hacker News: 2026년 4월 1일](https://thehackernews.com/2026/04/new-chrome-zero-day-cve-2026-5281-under.html)
> Google은 CVE-2026-5281에 대한 익스플로잇이 실제로 존재함을 인지하고 있습니다.
- [Help Net Security: 2026년 4월 1일](https://www.helpnetsecurity.com/2026/04/01/google-chrome-zero-day-cve-2026-5281/)
> CVE-2026-5281은 가명의 버그 헌터(86ac1f1587b71893ed2ad792cd7dde32)가 신고했습니다. 이 버그 헌터는 2026년 3월 23일에 배포된 Chrome 업데이트에서 수정된 두 가지 취약점, 즉 WebGL의 힙 버퍼 오버플로(CVE-2026-4675)와 Dawn의 또 다른 use-after-free 버그(CVE-2026-4676)를 이전에 신고한 바 있습니다. 또한 이번에 수정된 Dawn의 세 번째 use-after-free(CVE-2026-5284)도 이 버그 헌터가 신고했습니다.
---
<div id='thevulnerability-executionlayers'/>
### ***🔗 JavaScript에서 하드웨어까지***
Dawn에서 UAF가 어디서 발생할 수 있는지 이해하려면 WebGPU 호출이 JavaScript 한 줄에서 물리적 하드웨어까지 어떻게 전달되는지 정확히 살펴보는 것이 도움이 됩니다.```
JavaScript
↓ navigator.gpu → adapter → device → buffer / pipeline / encoder
↓ queue.submit([commandBuffer]) ← validation happens here
↓ buffer.destroy() ← if this races GPU execution, UAF
Dawn (C++) - validates API calls, serializes commands, tracks lifetimes
↓ translates WebGPU calls to platform-native API calls
D3D12 (Windows)
↓ ID3D12CommandQueue::ExecuteCommandLists()
↓ hardware handle for the buffer passed to the driver
GPU hardware
↓ shader cores execute the queued commands
↓ if the buffer was freed prematurely → they access freed VRAM ← UAF
The fundamental tension is that queue.submit() and buffer.destroy() are both JavaScript API calls that return immediately, but the GPU executes the submitted commands asynchronously, potentially long after both calls have returned. Dawn needs to keep buffer objects alive for the entire duration of GPU execution, not just until the JavaScript call returns.
UAF가 발생하면 GPU는 D3D12가 "Device Removed" 이벤트라고 부르는 상황에 직면합니다. 그 순서는 다음과 같습니다:```
이것은 이 저장소의 자동화된 테스트 러너가 감지하는 내용이기도 합니다. 테스트 러너는 정확히 이러한 콘솔 신호를 감시하여 주어진 Chrome 버전에서 취약점이 트리거될 수 있는지 판단합니다.
---
<div id='thevulnerability-impact'/>
### ***💥 영향 및 악용 요구 사항***
NVD 설명은 한 가지 중요한 제약 조건에 대해 구체적으로 명시합니다. 악용하려면 공격자가 이미 렌더러 프로세스를 손상시킨 상태여야 합니다. 즉, CVE-2026-5281은 처음부터 단독으로 실행되는 원클릭 RCE가 아니라, 체인의 일부가 되는 샌드박스 탈출입니다.
실제로 전체 공격 체인은 대략 다음과 같은 형태를 띱니다:```
Initial access ← some other vulnerability gets code running in the renderer
↓
CVE-2026-5281 ← UAF in Dawn used to escape the renderer sandbox
↓
Arbitrary code ← execution in a higher-privilege Chrome process or OS context
이것이 바로 브라우저 GPU 버그를 고가치로 만드는 악용 모델입니다. 렌더러에 진입하면 Dawn은 하드웨어 수준의 메모리를 처리하면서 이러한 타이밍 창을 만들어내는 비동기적 복잡성을 지니고 있기 때문에 자연스러운 다음 공격 목표 중 하나가 됩니다.
공개 시점에 확인된 영향은 임의 코드 실행이었으며, Vulners 데이터베이스는 데이터 손상과 브라우저 충돌을 추가로 관찰된 영향으로 기록합니다.
CVE-2026-5281은 단독으로 발생하지 않았습니다. 2026년 네 번째 Chrome 제로데이였으며, 이 해는 이미 1분기 종료 전에 2025년의 총 8건의 제로데이 수를 초과할 속도였습니다.
CVE-2026-5281을 보고한 동일한 익명 연구원은 인근 시기에 세 가지 다른 취약점(CVE-2026-4675, CVE-2026-4676, CVE-2026-5284, 마지막 두 개는 Dawn의 UAF이기도 함)도 보고했습니다. 이는 Dawn의 메모리 관리를 특별히 겨냥한 집중적이고 지속적인 연구 노력이 있었음을 시사합니다.
이 저장소의 툴킷은 랩 환경에서 이 취약점의 동작을 기록한 원본 보안 연구를 기반으로 구축되었습니다. 다음은 해당 연구의 요약, UAF를 트리거하는 데 사용된 전략, 그리고 관찰된 결과입니다.
연구원이 UAF를 트리거하기 위해 사용한 접근법은 경합 창(race window)에 도달할 수 있게 하는 세 가지 조건을 동시에 충족하도록 설계되었습니다. 즉, 실행을 지연시킬 만큼 충분한 GPU 큐 압력, destroy와 dispatch 사이의 충분히 촘촘한 타이밍, 그리고 관찰 가능한 손상을 최대화하기 위한 동일한 크기의 버퍼 재할당입니다.
전략은 다섯 단계로 나뉩니다:
단계 1 - 볼륨과 압력: 무작위 크기(WebGPU 사양에서 요구하는 대로 모두 4바이트의 배수)로 할당된 200개의 임시 WebGPU 스토리지 버퍼. 이는 VRAM을 채우기 위한 것이 아니라, GPU가 명령을 즉시 실행할 수 없을 만큼 충분한 대기 작업을 만드는 것입니다.
단계 2 - 컴퓨트 스레드 포화: 32개의 병렬 컴퓨트 파이프라인이 무거운 워크로드로 대기열에 쌓여 있으며, 내부 루프는 1000회 반복되고 디스패치 크기는 4096개 워크그룹입니다. 목표는 GPU 큐를 깊게 백로그 상태로 유지하여 제출과 실행 사이의 창이 경합할 수 있을 만큼 오래 열려 있도록 하는 것입니다.
단계 3 - 함정: 모든 커맨드 버퍼를 제출한 직후, 200개 버퍼 모두에 대해 destroy()가 호출됩니다. 이 시점에서 GPU는 명령을 수신했지만 아직 실행하지 않았습니다. Dawn은 이미 제출 시점 검증(submit-time validation)을 통과했습니다. VRAM은 해제됩니다.
단계 4 - 트리거: 방금 해제된 버퍼와 정확히 동일한 크기를 사용하는 32개의 새 버퍼 할당. VRAM 할당자가 동일한 물리적 주소를 반환한다면(크기가 일치하므로 자주 발생), GPU의 대기 중인 명령은 이제 다른 활성 할당에 속한 메모리를 가리키는 하드웨어 핸들을 갖게 됩니다.
단계 5 - 재사용 명령 제출: 새로 할당된 버퍼를 사용하는 또 한 차례의 커맨드 버퍼 제출. 이 시점에서 큐에는 한때 동일한 메모리를 참조했던 두 세트의 명령이 있으며, GPU는 여전히 첫 번째 세트를 처리 중입니다.
그 결과는 VRAM 계층의 전형적인 UAF입니다. 해제된 메모리를 실행 중인 셰이더가 적극적으로 읽는 것입니다.
연구원은 취약한 Chrome 설치 버전과 패치된 Chrome 설치 버전 양쪽에서 PoC를 실행했으며, 명확한 동작 차이를 관찰했습니다:
| 날짜 | 이벤트 |
|---|
| 2026년 2월 | CVE-2026-2441 패치됨, Chrome CSS 구성 요소의 UAF, 활발히 악용됨 |
| 2026년 3월 10일 | CVE-2026-3909 및 CVE-2026-3910 패치됨, 둘 다 활발히 악용된 제로데이 |
| 2026년 3월 23일 | CVE-2026-4675(WebGL 힙 버퍼 오버플로) 및 CVE-2026-4676(Dawn의 UAF) 패치됨, CVE-2026-5281과 동일한 보고자 |
| 2026년 4월 1일 | Google이 Chrome 146.0.7680.177/178을 출시, 21개의 취약점 패치, CVE-2026-5281 야생에서 악용 확인 |
| 2026년 4월 1일 | CISA가 CVE-2026-5281을 Known Exploited Vulnerabilities 카탈로그에 추가 |
| 2026년 4월 3일 | Google이 35억 Chrome 사용자를 대상으로 한 활발한 악용을 인정 |
취약한 버전 실행 (Chrome < 146.0.7680.178):``` [INFO] CVE-2026-5281 AGGRESSIVE PoC Loaded [INFO] Initializing WebGPU context... [INFO] WebGPU device initialized [INFO] Starting aggressive UAF attacks... [ERROR] UNCAUGHT GPU ERROR: device lost due to internal error [CRASH] GPU DEVICE LOST: destroyed [CRASH] [!!!] CRASH DETECTED! Check console for details.
대상 Chrome 프로세스가 완전히 렌더링을 중지했습니다. OS는 GPU 오류 후 디스플레이 드라이버가 재설정되거나 처리를 중단해야 했던 것과 일치하는 짧은 화면 정지를 경험했습니다. device lost 이벤트는 표준 WebGPU API 검증 오류가 아닌 치명적인 GPU 오류로 매핑되었으며, 이는 손상된 메모리 레이아웃이 Chrome의 JavaScript 측 샌드박싱에 걸리지 않고 하드웨어 계층에 도달했음을 확인해 줍니다.
**패치 적용 실행 (Chrome >= 146.0.7680.178):**```
[INFO] CVE-2026-5281 AGGRESSIVE PoC Loaded
[INFO] Initializing WebGPU context...
[INFO] WebGPU device initialized
[INFO] Starting aggressive UAF attacks...
[INFO] Max attempts reached without crash
[INFO] Either browser is patched or target build not affected
모든 시도에서 충돌, 장치 손실, 치명적 GPU 시그널이 발생하지 않았습니다. 수정 사항이 유효합니다.
다음 캡처는 Intel gen-12lp 내장 GPU가 장착된 Windows 머신에서 취약한 버전과 패치된 Chrome for Testing 설치본을 대상으로 이 툴킷을 실험실에서 테스트하는 동안 촬영되었습니다. 각 도구는 두 대상 모두에 대해 실행되어 동작 차이를 검증했습니다.
01 - 버전 감지기
| 취약한 버전 (< 146.0.7680.178) | 패치된 버전 (>= 146.0.7680.178) |
|---|---|
![]() | ![]() |
02 - 취약점 검사기
| 취약한 버전 | 패치된 버전 |
|---|---|
![]() | ![]() |
03 - 로컬 스캐너
| 취약한 버전 | 패치된 버전 |
|---|---|
![]() | ![]() |
04 - 플릿 스캐너
| 취약한 버전 | 패치된 버전 |
|---|---|
![]() | ![]() |
05 - UAF 트리거
| Chrome | Firefox |
|---|---|
![]() | ![]() |
Firefox는 비교를 위해 포함되었습니다. Firefox는 자체 WebGPU 구현을 사용하며 이 취약점의 영향을 받지 않습니다. Firefox는 버전과 관계없이 모든 시도를 충돌 시그널 없이 완료하며, 이는 예상된 동작입니다.
06 - UAF 트리거 + 자동 러너
| GPU 장치 손실 |
|---|
![]() |
가시적인 충돌 시그널을 얻는 것이 항상 간단한 것은 아닙니다. 하드웨어와 환경에 따라 트리거가 관찰 가능한 결과를 내도록 일부 조정이 필요할 수 있습니다. 우리의 경우 동작은 재현 가능했지만, 작업 부하를 조정하지 않으면 일관되게 드러나지 않았습니다.
통제된 실험실 환경에서 취약한 Chrome 설치본에 대한 서비스 거부(Denial of Service)를 성공적으로 재현했습니다. UAF 트리거는 심하게 백로그가 쌓인 명령 큐가 드라이버가 새 메모리 관리 요청을 처리하지 못하게 하여 GPU를 100% 사용률로 포화시킵니다. 일부 실행에서는 GPU 프로세스가 복구 불가능한 오류 상태에 빠져 다음과 같은 관찰 가능한 영향이 발생했습니다:
GPU 포화와 간헐적 예외는 메모리 손상이 하드웨어 계층에 도달하고 있음을 확인해 줍니다. 해제된 버퍼 핸들이 실행 중인(in-flight) 셰이더 실행에 의해 접근되고, GPU가 오류를 일으키며, D3D12의 TDR 메커니즘이 이를 장치 제거 이벤트로 표면화합니다. 패치된 버전은 동일한 작업 부하를 어떤 종류의 충돌 시그널도 없이 깨끗하게 완료했습니다.
DoS 재현을 통해 취약점이 확인되었습니다. 현재 진행 중인 작업은 패치의 바이너리 수준 분석, 특히 마지막 취약한 빌드와 146.0.7680.178 사이의 Dawn 명령 버퍼 제출 경로를 diff하여 참조 카운팅 수정이 정확히 어디에 어떻게 적용되었는지 파악하는 데 초점을 맞추고 있습니다.
자동 러너에 관해: 원래 연구자는 PoC와 함께 러너 스크립트를 게시했습니다. 우리 버전은 로컬 실험실 환경에서 안정적으로 작동하도록 수정이 필요했으며, 구체적으로 Chrome의 새로운 헤드리스 모드로 전환하고 GPU 충돌 시그널이 GPU 프로세스에서 렌더러로 전파되도록 허용하는 옵션을 추가했습니다. 이 두 플래그가 없으면 Chrome은 GPU 프로세스 충돌을 조용히 흡수하여 취약한 빌드와 패치된 빌드 간의 동작 차이를 JavaScript에서 관찰할 수 없습니다.
리버스 엔지니어링 및 바이너리 diff 작업이 아직 진행 중이므로 자동 러너는 이 저장소에 게시되지 않았습니다. 패치 분석이 완료되면 후속 업데이트에 포함될 예정입니다.