
Prueba de concepto y fuzzer GLSL para CVE-2026-9999 en el backend ANGLE/Metal WebGL de Chrome, con fingerprinting de compilación, shaders seleccionados y captura de artefactos de fallo.
| Campo | Valor |
|---|---|
| CVE | CVE-2026-9999 |
| Proveedor / producto | Google Chrome |
| Afectado | Chrome < 148.0.7778.216, solo macOS [1] |
| Corregido en | 148.0.7778.216 [1] |
| Impacto | Ejecución arbitraria de código dentro de un sandbox mediante una página HTML manipulada [1] |
| Severidad en Chromium | Alta [1] |
| CVSS 3.1 (CISA-ADP) | 8.8 ALTA — CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H [1] |
| Evaluación CVSS de NVD (NIST) | Aún no proporcionada [1] |
| CWE | CWE-269 — Gestión inadecuada de privilegios (enriquecimiento de CISA-ADP) [1] |
| CISA SSVC (2026-05-29) | exploitation: none, automatable: no, technicalImpact: total [1] |
| Publicado / última modificación | 2026-05-28 / 2026-07-21 [1] |
| Causa raíz | No pública — la incidencia 513364480 de Chromium muestra "Se requieren permisos" [1] |
Implicación en la cadena de ataque: la ejecución de código "dentro de un sandbox" [1] significa que un atacante obtiene el control de un proceso en sandbox (muy probablemente el proceso de GPU). Una toma completa del navegador requeriría además un escape de sandbox independiente que no forma parte de este CVE.
Lo siguiente es una inferencia del registro público, no hechos confirmados:
Por lo tanto, el harness ejercita exactamente esos patrones y luego muta GLSL a gran escala para buscar un fallo en el lado del renderizador (pérdida de contexto WebGL = fallo del proceso de GPU o muerte por watchdog).
| Archivo | Propósito |
|---|---|
cve-2026-9999-poc.html | Harness de PoC autocontenido (sin dependencias): fingerprinting de build, 8 shaders seleccionados de estrés del traductor, fuzzer de GLSL con captura de artefactos de fallo |
README.md | Este archivo |
El archivo Chrome for Testing de Google ofrece builds fijadas a una versión que no se autoactualizan. Encuentra el build vulnerable más reciente (todo lo anterior a 148.0.7778.216 está afectado [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
Descarga para tu arquitectura (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
Descomprime en una carpeta de laboratorio (p. ej. ~/lab/, no /Applications) y ejecútalo desde ahí.
Si un build específico no está en Chrome for Testing, usa el archivo de snapshots de Chromium (commondatastorage.googleapis.com/chromium-browser-snapshots/Mac/ para Intel, .../Mac_Arm/ para Apple Silicon), indexado por posición de commit — mapea la versión vulnerable a una posición de rama mediante chromium-history, y luego obtén el snapshot más cercano. Los snapshots tampoco se autoactualizan.
Termina los agentes de actualización de Keystone y bloquea googleupdate.googleapis.com, o el build de prueba se parcheará silenciosamente durante la noche. No es necesario para builds de Chrome for Testing.
Sin Metal, Chrome renderiza WebGL por software (SwiftShader) y el backend ANGLE Metal nunca se toca. En la consola de la página del PoC, ejecuta:
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
También puedes confirmarlo en chrome://gpu. Los invitados de Parallels/VMware Fusion con virtualización de GPU suelen funcionar; las configuraciones mínimas de QEMU/UTM a menudo recurren a SwiftShader.
cd <repo dir>
python3 -m http.server 8000
# then browse to http://localhost:8000/cve-2026-9999-poc.html
1) Run curated triggers. Ocho shaders ejercitan los patrones del traductor descritos en §2 (indexación constante fuera de límites, dimensionado de arrays con desbordamiento de enteros, indexación dinámica de matrices, estrés de desenrollado de bucles, arrays de arrays, discard/swizzle, casos límite del preprocesador, UBOs sobredimensionados). Observa los resultados [!!] y los eventos de pérdida de contexto.2) Fuzz. Los shaders GLSL mutados se compilan, enlazan, dibujan y se leen de vuelta en un bucle. Observa el registro en busca de CONTEXT LOST.localStorage. Recupéralo:
localStorage.getItem("cve20269999_poc_fs"); // crashing fragment shader
localStorage.getItem("cve20269999_crashes"); // crash event log