
Proof-of-concept и GLSL-фаззер для CVE-2026-9999 в бэкенде WebGL ANGLE/Metal в Chrome, с идентификацией сборки, подобранными шейдерами и сбором артефактов краша.
| Поле | Значение |
|---|---|
| CVE | CVE-2026-9999 |
| Вендор / продукт | Google Chrome |
| Затронуто | Chrome < 148.0.7778.216, только macOS [1] |
| Исправлено в | 148.0.7778.216 [1] |
| Воздействие | Выполнение произвольного кода внутри песочницы через специально сформированную HTML-страницу [1] |
| Критичность по Chromium | High [1] |
| CVSS 3.1 (CISA-ADP) | 8.8 HIGH — CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H [1] |
| Оценка CVSS от NVD (NIST) | Пока не предоставлена [1] |
| CWE | CWE-269 — Некорректное управление привилегиями (обогащение от CISA-ADP) [1] |
| CISA SSVC (2026-05-29) | exploitation: none, automatable: no, technicalImpact: total [1] |
| Опубликовано / последнее изменение | 2026-05-28 / 2026-07-21 [1] |
| Первопричина | Не публична — в Chromium issue 513364480 указано «Permissions Required» [1] |
Следствие для цепочки атаки: выполнение кода «внутри песочницы» [1] означает, что атакующий получает контроль над процессом внутри песочницы (вероятнее всего, GPU-процессом). Для полного захвата браузера дополнительно потребуется отдельный побег из песочницы, который не является частью данной CVE.
Ниже приведены выводы из публичных данных, а не подтверждённые факты:
Поэтому харнес отрабатывает именно эти паттерны, а затем массово мутирует GLSL в поисках падения на стороне рендерера (потеря WebGL-контекста = падение GPU-процесса или его остановка watchdog'ом).
| Файл | Назначение |
|---|---|
cve-2026-9999-poc.html | Самодостаточный PoC-харнес (без зависимостей): определение сборки, 8 подобранных шейдеров для нагрузки на транслятор, GLSL-фаззер с сохранением артефактов падения |
README.md | Этот файл |
Архив Chrome for Testing от Google предоставляет сборки с фиксированной версией, которые не обновляются автоматически. Найдите новейшую уязвимую сборку (затронуто всё, что ниже 148.0.7778.216 [1]):
import json, urllib.request
data = json.load(urllib.request.urlopen(
"https://googlechromelabs.github.io/chrome-for-testing/known-good-versions-with-downloads.json"))
key = lambda v: tuple(int(x) for x in v.split('.'))
fix = (148, 0, 7778, 216)
cands = sorted((v["version"] for v in data["versions"]
if "chrome" in v.get("downloads", {}) and key(v["version"]) < fix), key=key)
print(cands[-5:]) # pick the last (newest vulnerable) entry
Скачайте для вашей архитектуры (uname -m):
# Apple Silicon
https://storage.googleapis.com/chrome-for-testing-public/<VERSION>/mac-arm64/chrome-mac-arm64.zip
# Intel
https://storage.googleapis.com/chrome-for-testing-public/<VERSION>/mac-x64/chrome-mac-x64.zip
Распакуйте в лабораторную папку (например, ~/lab/, не в /Applications) и запускайте оттуда.
Если нужной сборки нет в Chrome for Testing, используйте архив снапшотов Chromium (commondatastorage.googleapis.com/chromium-browser-snapshots/Mac/ для Intel, .../Mac_Arm/ для Apple Silicon), индексируемый по позиции коммита — сопоставьте уязвимую версию с позицией ветки через chromium-history, затем возьмите ближайший снапшот. Снапшоты также не обновляются автоматически.
Остановите агенты обновления Keystone и заблокируйте googleupdate.googleapis.com, иначе тестовая сборка незаметно обновит себя за ночь. Для сборок Chrome for Testing не требуется.
Без Metal Chrome рендерит WebGL программно (SwiftShader), и Metal-бэкенд ANGLE не задействуется. В консоли страницы PoC выполните:
const c = document.createElement('canvas'), g = c.getContext('webgl2');
const x = g.getExtension('WEBGL_debug_renderer_info');
console.log(g.getParameter(x.UNMASKED_RENDERER_WEBGL));
// Good: contains "ANGLE Metal Renderer"
// Bad: contains "SwiftShader" -> the vulnerable path is NOT being exercised
Это также можно подтвердить на chrome://gpu. Гостевые системы Parallels/VMware Fusion с виртуализацией GPU обычно работают; минимальные конфигурации QEMU/UTM часто откатываются на SwiftShader.
cd <repo dir>
python3 -m http.server 8000
# then browse to http://localhost:8000/cve-2026-9999-poc.html
1) Run curated triggers. Восемь шейдеров нагружают паттерны транслятора, описанные в §2 (выход за границы массива при индексации константой, переполнение целых чисел при расчёте размера массивов, динамическая индексация матриц, нагрузка на развёртку циклов, массивы массивов, discard/swizzle, граничные случаи препроцессора, слишком большие UBO). Следите за результатами [!!] и событиями потери контекста.2) Fuzz. Мутированные GLSL-шейдеры компилируются, линкуются, отрисовываются и считываются в цикле. Следите в логе за CONTEXT LOST.localStorage. Получите его:
localStorage.getItem("cve20269999_poc_fs"); // crashing fragment shader
localStorage.getItem("cve20269999_crashes"); // crash event log
Живой снапшот подозрительного запуска также виден на
chrome://gpuи в консоли macOS (отчёты о падении GPU-процесса).