
Preuve de concept et fuzzer GLSL pour CVE-2026-9999 dans le backend WebGL ANGLE/Metal de Chrome, avec fingerprinting de build, shaders sélectionnés et capture d'artefacts de crash.
| Champ | Valeur |
|---|
| CVE | CVE-2026-9999 |
| Éditeur / produit | Google Chrome |
| Versions concernées | Chrome < 148.0.7778.216, macOS uniquement [1] |
| Corrigé dans | 148.0.7778.216 [1] |
| Impact | Exécution de code arbitraire dans un sandbox via une page HTML spécialement conçue [1] |
| Sévérité Chromium | Élevée [1] |
| CVSS 3.1 (CISA-ADP) | 8.8 ÉLEVÉE — CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H [1] |
| Évaluation CVSS NVD (NIST) | Pas encore fournie [1] |
| CWE | CWE-269 — Gestion inappropriée des privilèges (enrichissement par CISA-ADP) [1] |
| CISA SSVC (2026-05-29) | exploitation: none, automatable: no, technicalImpact: total [1] |
| Publié / Dernière modification | 2026-05-28 / 2026-07-21 [1] |
| Cause racine | Non publique — le ticket Chromium 513364480 affiche « Permissions Required » [1] |
Implication pour la chaîne d'attaque : l'exécution de code « dans un sandbox » [1] signifie qu'un attaquant prend le contrôle d'un processus sandboxé (le plus vraisemblablement le processus GPU). Une prise de contrôle complète du navigateur nécessiterait en outre une évasion de sandbox distincte qui ne fait pas partie de cette CVE.
Ce qui suit est une déduction fondée sur les informations publiques, et non des faits confirmés :
Le harnais exerce donc exactement ces motifs, puis mute le GLSL à grande échelle pour traquer un crash côté moteur de rendu (contexte WebGL perdu = crash du processus GPU ou mise à mort par le watchdog).
| Fichier | Rôle |
|---|---|
cve-2026-9999-poc.html | Harnais de PoC autonome (aucune dépendance) : empreinte de build, 8 shaders de stress du traducteur soigneusement sélectionnés, fuzzer GLSL avec capture des artefacts de crash |
README.md | Ce fichier |
L'archive Chrome for Testing de Google fournit des builds épinglés à une version qui ne se mettent pas à jour automatiquement. Trouvez le build vulnérable le plus récent (toutes les versions inférieures à 148.0.7778.216 sont concernées [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
Téléchargez pour votre architecture (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
Décompressez dans un dossier de laboratoire (par ex. ~/lab/, pas /Applications) puis lancez à partir de là.
Si un build précis manque dans Chrome for Testing, utilisez l'archive d'instantanés Chromium (commondatastorage.googleapis.com/chromium-browser-snapshots/Mac/ pour Intel, .../Mac_Arm/ pour Apple Silicon), indexée par position de commit — faites correspondre la version vulnérable à une position de branche via chromium-history, puis récupérez l'instantané le plus proche. Les instantanés ne se mettent pas non plus à jour automatiquement.
Tuez les agents de mise à jour Keystone et bloquez googleupdate.googleapis.com, sinon le build de test se corrigera silencieusement tout seul pendant la nuit. Inutile pour les builds Chrome for Testing.
Sans Metal, Chrome rend le WebGL par logiciel (SwiftShader) et le backend ANGLE Metal n'est jamais sollicité. Dans la console de la page PoC, exécutez :
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
Vous pouvez aussi le confirmer sur chrome://gpu. Les invités Parallels/VMware Fusion avec virtualisation GPU fonctionnent généralement ; les configurations minimales QEMU/UTM retombent souvent sur SwiftShader.
cd <repo dir>
python3 -m http.server 8000
# then browse to http://localhost:8000/cve-2026-9999-poc.html
1) Run curated triggers. Huit shaders stressent les motifs du traducteur décrits en §2 (indexation constante hors limites, dimensionnement de tableaux par dépassement d'entier, indexation dynamique de matrices, stress de déroulage de boucles, tableaux de tableaux, discard/swizzle, cas limites du préprocesseur, UBO surdimensionnés). Surveillez les résultats [!!] et les événements de perte de contexte.2) Fuzz. Des shaders GLSL mutés sont compilés, liés, utilisés pour le rendu puis relus en boucle. Surveillez le journal pour CONTEXT LOST.localStorage. Récupérez-le :
localStorage.getItem("cve20269999_poc_fs"); // crashing fragment shader
localStorage.getItem("cve20269999_crashes"); // crash event log
Un instantané en direct d'une exécution suspecte est également visible sur
chrome://gpuet dans la Console macOS (rapports de crash du processus GPU).
WEBGL_context_lost ≠ vulnérabilité. Le watchdog GPU de Chrome tue les shaders à exécution longue (le déclencheur loop-unroll-dos et les itérations de fuzz avec d'énormes compteurs de boucles sont conçus pour être lents). Réduisez le bruit : diminuez SH_ITER, ou confirmez que tout crash candidat se reproduit rapidement (< 1 s par itération).EXC_BAD_ACCESS) plutôt qu'une terminaison par le watchdog.Compilez une révision vulnérable de Chromium avec AddressSanitizer :
fetch chromium
cd src
git checkout tags/148.0.7778.215 # last tag before the fix
gn gen out/asan --args='is_asan=true is_debug=false symbol_level=1 dcheck_always_on=true'
autoninja -C out/asan chrome
Exécutez ensuite le shader minimisé qui crashe avec la validation de l'API Metal activée :
MTL_DEBUG_LAYER=1 out/asan/Chromium.app/Contents/MacOS/Chromium poc.html
La trace ASAN nommera la fonction ANGLE/Metal exacte et confirmera si le crash correspond au composant de la CVE [1].
(En aval : une fois que le commit de correction pour 148.0.7778.216 est visible, faites un diff de third_party/angle/src/libANGLE/renderer/metal/ pour identifier la véritable cause racine et remplacez l'approche de fuzzing par un déclencheur déterministe.)
exploitation: none [1].Testez uniquement sur des machines que vous possédez ou que vous êtes explicitement autorisé à tester. Le harnais compile intentionnellement des shaders hostiles pour faire crasher un processus graphique — attendez-vous à des terminaisons du processus GPU. Tenez le build de navigateur vulnérable à l'écart des réseaux de production.
[1] NVD — CVE-2026-9999 : https://nvd.nist.gov/vuln/detail/CVE-2026-9999 * Avis de l'éditeur (blog Chrome Releases, mise à jour du canal stable) : https://chromereleases.googleblog.com/2026/05/stable-channel-update-for-desktop_0877304591.html * Ticket Chromium 513364480 (accès restreint) : https://issues.chromium.org/issues/513364480