
CVE-2026-74970, bypass de isolamento de site do Fission no Firefox WebRender
Este diretório contém um scaffold de reprodução honesto para um bypass de autorização de isolamento de site do Fission no WebRender do Firefox. Sob o Fission, cada processo de conteúdo possui um namespace de PipelineId distinto, mas o código do processo GPU que registra um PipelineId compositável nunca verificava se o namespace do PipelineId pertencia ao processo remetente. Um processo de conteúdo comprometido pode, portanto, registrar um PipelineId no namespace de outro processo e sobrescrever o pipeline de imagem assíncrona daquela origem no gerenciador compartilhado.
Tudo aqui tem como alvo uma árvore do Firefox compilada localmente com conteúdo sintético apenas. Nunca ataca, contata, sonda ou referencia qualquer sistema ativo ou de terceiros. Não é execução remota de código nem corrupção de memória; o modelo de ameaça é um processo de conteúdo já comprometido.
Repositório PoC correspondente: https://github.com/defineid/Trespasser
Writeup: writeup-webrender-pipelineid.html neste portfólio.
| Campo | Valor |
|---|---|
| CVE | CVE-2026-74970 |
| Componente | Core / Graphics: WebRender |
| Classe | Bypass de Isolamento de Site |
| CWE | 862 (Autorização Ausente) · 284 (Controle de Acesso Impróprio) |
| Corrigido em | Firefox 154 · ESR 153.1 |
| Bug | https://bugzilla.mozilla.org/show_bug.cgi?id=2056558 |
| Repositório PoC | https://github.com/defineid/Trespasser |
Sob o Fission, o WebRender atribui a cada processo de conteúdo seu próprio namespace de PipelineId. Espera-se que a ponte do processo GPU rejeite qualquer recurso cujo namespace não pertença ao processo que o enviou, de modo que um processo de conteúdo não possa endereçar ou sobrescrever os recursos de renderização de outro.
WebRenderBridgeParent::AddPipelineIdForCompositable, que é executado no processo
GPU, validava o pipeline recebido contra a guarda root/WebRender e
contra o próprio conjunto de pipelines registrados desta ponte, mas nunca chamava
MatchesNamespace no PipelineId. Os caminhos de image-key, font-key e blob-key
no mesmo arquivo realizam todos essa verificação de propriedade MatchesNamespace;
o caminho do PipelineId simplesmente não o fazia. RemovePipelineIdForCompositable
também está sem verificação, de modo que a mesma falha de propriedade de namespace
existe na remoção.
A jusante, AsyncImagePipelineManager::AddAsyncImagePipeline protege a
unicidade de um pipeline apenas com MOZ_ASSERT, que compila para um no-op em
builds de release. Assim, quando um PipelineId forjado, de namespace cruzado, chega ao
AsyncImagePipelineManager compartilhado, o gerenciador não rejeita a duplicata: ele
sobrescreve silenciosamente a entrada de pipeline de imagem assíncrona existente da origem vítima.
Encadeados, um processo de conteúdo comprometido A pode forjar um PipelineId cujo namespace pertence ao processo de conteúdo B (uma origem diferente, em um processo separado sob o Fission), submetê-lo no caminho de registro de compositável, e fazer com que o processo GPU o aceite e sobrescreva o pipeline de imagem de B no gerenciador compartilhado.
Um processo de conteúdo já comprometido sob o Fission. Assume-se que o atacante já possui execução de código em um processo de conteúdo (por exemplo, por meio de um bug separado no processo de conteúdo) e é capaz de enviar mensagens IPC do WebRender com campos escolhidos pelo atacante. Este defeito é a autorização ausente que permite a esse processo atravessar a fronteira de isolamento de site até os recursos de renderização de outra origem.
Este é um bypass de autorização de isolamento de site do Fission, não corrupção de memória. O impacto é confusão de renderização entre origens e negação de serviço entre abas. Os consumidores a jusante são protegidos contra nulos e contados por referência, portanto isso não resulta em execução de código. O PoC não deve e não reivindica execução de código.
README.md — este arquivo.forge-namespace.patch — um patch de pesquisa para uma árvore local do Firefox. No
lado do conteúdo, protegido por XRE_IsContentProcess() e pela variável de ambiente
MOZ_POC_FORGE_WR_NAMESPACE, ele forja o namespace do PipelineId de saída. No lado
pai do processo GPU, ele imprime um diagnóstico ACCEPTED
quando um PipelineId de namespace cruzado é registrado, demonstrando que a
verificação ausente permitiu que ele passasse.poc.html — um caso de teste simples do lado do conteúdo: um canvas WebGL (para que um
pipeline de imagem assíncrono seja criado) mais um iframe cross-origin fora de processo (para que o Fission
o coloque em um processo de conteúdo separado). Em uma build padrão, ele renderiza normalmente
e não faz nada observável.victim.html — a segunda origem sintética que o iframe carrega. É uma página trivial,
sem scripts, cujo único propósito é ser um documento cross-origin ativo, para que,
sob o Fission, ela caia em seu próprio processo de conteúdo com seu próprio namespace
de PipelineId (o namespace que um registro forjado teria como alvo).poc-render.png — uma captura de tela do poc.html carregado no Firefox 140.11.0esr
padrão local. Ela mostra a página de teste renderizando normalmente: o canvas WebGL
desenha seu quadro e o iframe fora de processo carrega o victim.html. Ela
mostra apenas renderização benigna. O bypass em si requer o patch de pesquisa e
uma build vulnerável e não foi acionado aqui (veja o status de verificação).Estes passos devem ser executados pelo autor contra um checkout local do Firefox. Nada aqui foi executado contra o Firefox neste ambiente (veja o status de verificação abaixo).
Faça o checkout de uma árvore de código-fonte vulnerável do Firefox (anterior à 154 / anterior à ESR
153.1) e confirme que o Fission está habilitado (fission.autostart = true, o
padrão em builds recentes).
Aplique o patch de pesquisa a partir do topo da árvore de código-fonte:
patch -p1 < forge-namespace.patch
O patch toca gfx/layers/wr/WebRenderBridgeChild.cpp (lado do conteúdo,
forja o namespace) e gfx/layers/wr/WebRenderBridgeParent.cpp
(lado do processo GPU, imprime o diagnóstico ACCEPTED). Ambas as alterações são inertes
a menos que as condições de guarda sejam satisfeitas.
Compile normalmente (./mach build).
Sirva este diretório para que o iframe fora de processo de poc.html carregue o
victim.html complementar a partir de um domínio registrável genuinamente diferente, para que
o Fission coloque o iframe em seu próprio processo de conteúdo. Por exemplo,
python3 -m http.server 8000 --bind :: e carregue o iframe a partir de
http://victim.localtest.me:8000/victim.html. Veja o comentário inline em
poc.html.
Inicie a compilação com a variável de forja definida e carregue a página de teste:
MOZ_POC_FORGE_WR_NAMESPACE=999999 ./mach run --temp-profile poc.html
999999 é um valor de namespace arbitrário escolhido para não pertencer a nenhum processo real; ele torna o registro forjado entre namespaces óbvio no log.
Em uma build vulnerável com o patch aplicado, o processo pai da GPU aceita e registra um PipelineId cujo namespace não pertence a nenhum processo desse tipo, e imprime (esta é a forma exata mostrada no writeup):
[POC-2056558] ACCEPTED cross-namespace PipelineId:
sender-namespace=4 pipeline-namespace=999999 (should have been rejected)