
Proof-of-concept e fuzzer GLSL per CVE-2026-9999 nel backend WebGL ANGLE/Metal di Chrome, con fingerprinting delle build, shader selezionati e acquisizione degli artefatti di crash.
| Campo | Valore |
|---|---|
| CVE | CVE-2026-9999 |
| Vendor / prodotto | Google Chrome |
| Interessate | Chrome < 148.0.7778.216, solo macOS [1] |
| Corretta in | 148.0.7778.216 [1] |
| Impatto | Esecuzione di codice arbitrario all'interno di una sandbox tramite una pagina HTML appositamente predisposta [1] |
| Gravità 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] |
| Valutazione CVSS NVD (NIST) | Non ancora fornita [1] |
| CWE | CWE-269 — Gestione impropria dei privilegi (arricchimento da parte di CISA-ADP) [1] |
| CISA SSVC (2026-05-29) | exploitation: none, automatable: no, technicalImpact: total [1] |
| Pubblicata / ultima modifica | 2026-05-28 / 2026-07-21 [1] |
| Causa principale | Non pubblica — l'issue Chromium 513364480 mostra "Permissions Required" [1] |
Implicazione per la catena di attacco: l'esecuzione di codice "all'interno di una sandbox" [1] significa che un attaccante ottiene il controllo di un processo in sandbox (molto probabilmente il processo GPU). Un takeover completo del browser richiederebbe inoltre una separata fuga dalla sandbox che non fa parte di questa CVE.
Quanto segue è un'inferenza basata su documenti pubblici, non fatti confermati:
L'harness quindi esercita esattamente questi pattern e poi muta GLSL su larga scala per cercare un crash lato renderer (WebGL context lost = crash del processo GPU o kill da parte del watchdog).
| File | Scopo |
|---|---|
cve-2026-9999-poc.html | Harness PoC autonomo (nessuna dipendenza): fingerprinting della build, 8 shader curati per stressare il traduttore, fuzzer GLSL con acquisizione degli artefatti di crash |
README.md | Questo file |
L'archivio Chrome for Testing di Google fornisce build ancorate a una versione specifica che non si aggiornano automaticamente. Trova la build vulnerabile più recente (tutto ciò che è inferiore a 148.0.7778.216 è affetto [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
Scarica per la tua architettura (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
Decomprimi in una cartella di laboratorio (es. ~/lab/, non /Applications) e avvia da lì.
Se una build specifica non è disponibile in Chrome for Testing, usa l'archivio degli snapshot Chromium (commondatastorage.googleapis.com/chromium-browser-snapshots/Mac/ per Intel, .../Mac_Arm/ per Apple Silicon), indicizzato per posizione di commit — mappa la versione vulnerabile a una posizione di branch tramite chromium-history, quindi scarica lo snapshot più vicino. Anche gli snapshot non si aggiornano automaticamente.
Termina gli agenti di aggiornamento Keystone e blocca googleupdate.googleapis.com, altrimenti la build di test si auto-patcha silenziosamente durante la notte. Non necessario per le build di Chrome for Testing.
Senza Metal, Chrome esegue il rendering WebGL via software (SwiftShader) e il backend Metal di ANGLE non viene mai toccato. Nella console della pagina PoC, esegui:
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
Puoi anche verificarlo su chrome://gpu. Le macchine virtuali Parallels/VMware Fusion con virtualizzazione GPU di solito funzionano; le configurazioni minimali QEMU/UTM spesso ripiegano su SwiftShader.