
CVE-2026-2766, mais avec wasm
Statut : PoC de crash validé avec détournement de flux de contrôle démontré
(pc du crash = poison de cellule libérée 0xcdcdcdcdcdcdcdcd sous le shell
de débogage — le moteur saute vers un pointeur lu depuis l'ICScript libéré).
Travail restant : contrôler les octets récupérés. Voir
research/README.md.
Une chaîne de la famille WasmBlazeFox sur un bug de 2026 : CVE-2026-2766, « JIT miscompilation / use-after-free in the JavaScript Engine: JIT component », corrigé dans Firefox 148 (MFSA 2026-13). Le final est le même que CVE-2024-29943-but-with-wasm : transformer la primitive en contrôle d'un pointeur de code, et le diriger vers une page JIT WASM remplie de constantes de shellcode.
D'après les propres commentaires du test de régression de Mozilla (bug 2013583,
test intégré dans hg 457b68097f81) et le SMDOC ICScript Lifetimes dans
js/src/jit/JitScript.h :
removeInlinedChild → l'ICScript de l'enfant est retiré de
inlinedChildren_ mais est toujours référencé par le vecteur
inlinedScripts_ de l'InliningRoot — et, fatalement, par le stub
CallInlinedFunction obsolète toujours présent dans la chaîne IC de
l'appelant.gczeal(14, 1), c'est-à-dire ZealCompactValue à chaque
allocation) déplace/évacue l'ICScript orphelin tandis que la chaîne de stubs
obsolète conserve l'ancienne adresse.0xe5, ce qui donne un crash très lisible.Build vulnérable : mozilla-central rev b3663be61a1a (nightly du 2026-01-15 ;
le correctif est arrivé entre le 2026-01-15 et le 2026-02-09 — la nightly du
09-02 survit). Shell : jsshell Taskcluster linux64-fuzzing-asan-opt pour
cette rev (nécessaire pour gczeal ; les shells release-opt en sont dépourvus).
./js --ion-warmup-threshold=100000 poc.js
== ERROR: AddressSanitizer: SEGV on unknown address 0xe5e5e5e5e5e5e5e5
The signal is caused by a READ memory access.
#0-#3 <unknown module> <- baseline JIT code
#4 EnterJit / MaybeEnterJit <- js/src/jit/Jit.cpp
#10 js::jit::DoCallFallback <- BaselineIC.cpp (the stale IC chain)
rdi = 0xe5e5e5e5e5e5e5e5 <- the freed ICScript
Le déréférencement se produit dans le code JIT baseline qui parcourt la chaîne de stubs obsolète : le contrôle de la cellule récupérée = le contrôle des champs ICEntry/stub auxquels le baseline fait confiance, y compris le pointeur de code du stub vers lequel il saute.
orphaned ICScript (this PoC)
-> compacting GC moves it; stale chain keeps old address
-> reclaim the old cell with controlled bytes (size-class spray)
-> baseline reads fake ICEntry -> fake ICStub -> fake code_ pointer
-> jump into the WASM JIT page shellcode (f64.const immediates,
FuncExport entry-offset overwrite — see the 2024-29943 repo)
Voir research/README.md pour le journal complet
d'armement. Résumé de l'état actuel :
TrailingArray) — récupérable en principe par spray avec des buffers
classés par taille.new Ctor(flag), sans point
de rappel JS entre les deux ; les sprays naïfs ratent soit la fenêtre
(reclaim1/2), soit font disparaître l'état IC à force de tempête de GC
zeal (reclaim3). La chaîne obsolète survit bien à un simple gc()
(purge_check).L'étape WASM elle-même est déjà construite et démontrée dans CVE-2024-29943-but-with-wasm ; seuls les offsets du modèle objet doivent être redérivés pour ce build de l'ère FF149.
poc.js — le test de régression de Mozilla (bug 2013583), vérifié comme
faisant planter le jsshell ASAN du 2026-01-15 comme montré ci-dessus.457b68097f81