
CVE-2026-74970, bypass dell'isolamento dei siti Fission in Firefox WebRender
Questa directory contiene uno scaffold di riproduzione onesto per un bypass dell'autorizzazione dell'isolamento dei siti di Fission in Firefox WebRender. In Fission ogni processo di contenuto possiede un proprio namespace PipelineId distinto, ma il codice del processo GPU che registra un PipelineId compositabile non verificava mai che il namespace del PipelineId appartenesse al processo mittente. Un processo di contenuto compromesso può quindi registrare un PipelineId nel namespace di un altro processo e sovrascrivere la pipeline di immagini asincrona di quell'origine nel gestore condiviso.
Tutto qui è rivolto a un albero Firefox compilato localmente con contenuti sintetici soltanto. Non attacca, contatta, sonda né fa riferimento ad alcun sistema attivo o di terze parti. Non è esecuzione di codice in remoto né corruzione di memoria; il modello di minaccia è un processo di contenuto già compromesso.
Repository PoC corrispondente: https://github.com/defineid/Trespasser
Writeup: writeup-webrender-pipelineid.html in questo portfolio.
| Campo | Valore |
|---|---|
| CVE | CVE-2026-74970 |
| Componente | Core / Graphics: WebRender |
| Classe | Bypass dell'isolamento dei siti |
| CWE | 862 (Autorizzazione mancante) · 284 (Controllo degli accessi inadeguato) |
| Corretto in | Firefox 154 · ESR 153.1 |
| Bug | https://bugzilla.mozilla.org/show_bug.cgi?id=2056558 |
| Repo PoC | https://github.com/defineid/Trespasser |
In Fission, WebRender assegna a ogni processo di contenuto il proprio namespace PipelineId. Il bridge del processo GPU dovrebbe rifiutare qualsiasi risorsa il cui namespace non appartenga al processo che l'ha inviata, così che un processo di contenuto non possa indirizzare o sovrascrivere le risorse di rendering di un altro.
WebRenderBridgeParent::AddPipelineIdForCompositable, che viene eseguito nel processo
GPU, validava la pipeline in ingresso rispetto alla guardia root/WebRender e
rispetto all'insieme di pipeline registrate del bridge stesso, ma non chiamava mai
MatchesNamespace sul PipelineId. I percorsi image-key, font-key e blob-key
nello stesso file eseguono tutti quel controllo di proprietà MatchesNamespace;
il percorso PipelineId semplicemente non lo faceva. Anche RemovePipelineIdForCompositable
è privo di verifica, quindi lo stesso buco nella proprietà del namespace esiste alla rimozione.
A valle, AsyncImagePipelineManager::AddAsyncImagePipeline protegge l'unicità
di una pipeline solo con MOZ_ASSERT, che nelle build di release viene compilato come no-op.
Quindi, quando un PipelineId forgiato e appartenente a un altro namespace raggiunge il
AsyncImagePipelineManager condiviso, il gestore non rifiuta il duplicato:
sovrascrive silenziosamente la voce esistente della pipeline di immagini asincrona dell'origine vittima.
Concatenando il tutto, un processo di contenuto compromesso A può forgiare un PipelineId il cui namespace appartiene al processo di contenuto B (un'origine diversa, in un processo separato in Fission), inviarlo sul percorso di registrazione dei compositabili, e far sì che il processo GPU lo accetti e sovrascriva la pipeline di immagini di B nel gestore condiviso.
Un processo di contenuto già compromesso in Fission. Si presume che l'attaccante abbia già l'esecuzione di codice in un processo di contenuto (ad esempio tramite un bug separato del processo di contenuto) e sia in grado di inviare messaggi IPC WebRender con campi scelti dall'attaccante. Questo difetto è l'autorizzazione mancante che consente a quel processo di superare il confine dell'isolamento dei siti e raggiungere le risorse di rendering di un'altra origine.
Si tratta di un bypass dell'autorizzazione dell'isolamento dei siti di Fission, non di corruzione di memoria. L'impatto è confusione nel rendering cross-origin e denial of service cross-tab. I consumatori a valle sono protetti da null-guard e conteggiati per riferimento, quindi non si ottiene esecuzione di codice. Il PoC non deve e non dichiara l'esecuzione di codice.
README.md — questo file.forge-namespace.patch — una patch di ricerca per un albero Firefox locale. Sul
lato content, protetta da XRE_IsContentProcess() e dalla variabile
d'ambiente MOZ_POC_FORGE_WR_NAMESPACE, falsifica il namespace del
PipelineId in uscita. Sul lato parent del processo GPU stampa una diagnostica
ACCEPTED quando viene registrato un PipelineId cross-namespace, dimostrando che
il controllo mancante lo ha lasciato passare.poc.html — un semplice caso di test lato content: un canvas WebGL (così viene
creata una pipeline di immagini asincrona) più un iframe cross-origin
out-of-process (così Fission lo colloca in un processo content separato). Su una
build standard viene renderizzato normalmente e non fa nulla di osservabile.victim.html — la seconda origine sintetica che l'iframe carica. È una pagina
banale, priva di script, il cui unico scopo è essere un documento cross-origin
attivo, così che sotto Fission finisca nel proprio processo content con il
proprio namespace PipelineId (il namespace che una registrazione falsificata
prenderebbe di mira).poc-render.png — uno screenshot di poc.html caricato nel Firefox 140.11.0esr
standard locale. Mostra la pagina di test renderizzata normalmente: il canvas
WebGL disegna il suo frame e l'iframe out-of-process carica victim.html. Mostra
solo un rendering benigno. Il bypass stesso richiede la patch di ricerca e
una build vulnerabile e non è stato attivato qui (vedi Stato di verifica).Questi passaggi sono pensati per essere eseguiti dall'autore su un checkout locale di Firefox. Nulla di quanto qui descritto è stato eseguito contro Firefox in questo ambiente (vedi Stato di verifica di seguito).
Effettuare il checkout di un albero sorgente Firefox vulnerabile (prima di 154 / prima di ESR
153.1) e confermare che Fission sia abilitato (fission.autostart = true, il
valore predefinito nelle build recenti).
Applicare la patch di ricerca dalla radice dell'albero sorgente:
patch -p1 < forge-namespace.patch
La patch modifica gfx/layers/wr/WebRenderBridgeChild.cpp (lato contenuto,
forgia il namespace) e gfx/layers/wr/WebRenderBridgeParent.cpp
(lato processo GPU, stampa la diagnostica ACCEPTED). Entrambe le modifiche sono inerti
a meno che non siano soddisfatte le condizioni di guardia.
Compila normalmente (./mach build).
Servi questa directory in modo che l'iframe out-of-process di poc.html carichi il
file victim.html di accompagnamento da un dominio registrabile genuinamente diverso, così
che Fission collochi l'iframe nel proprio processo di contenuto. Ad esempio,
python3 -m http.server 8000 --bind :: e carica l'iframe da
http://victim.localtest.me:8000/victim.html. Vedi il commento inline in
poc.html.
Avvia la build con la variabile forge impostata e carica la pagina di test:
MOZ_POC_FORGE_WR_NAMESPACE=999999 ./mach run --temp-profile poc.html
999999 è un valore di namespace arbitrario scelto in modo che non appartenga a nessun processo reale; rende evidente nel log la registrazione forgiata tra namespace diversi.
Su una build vulnerabile con la patch applicata, il processo padre della GPU accetta e registra un PipelineId il cui namespace non appartiene a nessun processo di quel tipo, e stampa (questa è la forma esatta mostrata nel writeup):
[POC-2056558] ACCEPTED cross-namespace PipelineId:
sender-namespace=4 pipeline-namespace=999999 (should have been rejected)