All writeups
Mozilla FirefoxGraphics, WebRender
sec-moderate CVE-2026-74970 RESOLVED FIXED

Fission site-isolation bypass via missing PipelineId namespace check

Vendor
Mozilla Firefox
Component
Core / Graphics: WebRender
Class
Site-Isolation Bypass
CWE
862, 284, 346
CVSS
5.4 Medium (Mozilla)
Fixed in
Firefox 154, ESR 153.1; Thunderbird 154, 153.1
Interaction
Compromised content process

Summary

Under Fission each content process owns a PipelineId namespace. WebRenderBridgeParent::AddPipelineIdForCompositable, which runs in the GPU process, validated the pipeline against the root guard and this bridge's own set but never checked that the PipelineId's namespace belonged to the sending process, unlike the image, font, and blob key paths in the same file. A compromised content process could therefore register a PipelineId in another process's namespace and overwrite that origin's async image pipeline in the shared manager.

Root cause

The MatchesNamespace check that the resource-key paths enforce is missing on the PipelineId path, and on RemovePipelineIdForCompositable. AddAsyncImagePipeline guards uniqueness only with MOZ_ASSERT, a no-op in release builds, so the shared AsyncImagePipelineManager silently overwrites the victim's pipeline instead of rejecting the duplicate.

Proof of concept

  • The threat model is an already-compromised content process. The PoC is a content-side patch guarded by XRE_IsContentProcess that forges the PipelineId namespace, plus an HTML test case with a WebGL canvas and a cross-origin out-of-process iframe.
  • Launch with the forged namespace and load the test page.
  • The GPU-process parent accepts and registers a PipelineId whose namespace belongs to no such process.
GPU PROCESS AsyncImagePipelineManager (shared) AddPipelineIdForCompositable, MatchesNamespace MISSING CONTENT PROCESS A compromised CONTENT PROCESS B victim origin forged PipelineId namespace = B overwrite B's image pipeline
Process A forges a PipelineId in B's namespace. With the ownership check missing, the shared manager in the GPU process overwrites B's image pipeline.
# illustrative log from a vulnerable build with the research patch applied, not a live capture
# 999999 is an arbitrary forged probe value chosen for this test, not a captured victim namespace
$ MOZ_POC_FORGE_WR_NAMESPACE=999999 ./mach run --temp-profile poc.html
[POC-2056558] ACCEPTED cross-namespace PipelineId:
  sender-namespace=4  pipeline-namespace=999999  (should have been rejected)
Animated demonstration of the site-isolation bypass: a compromised process forges a PipelineId in the victim origin's namespace and overwrites the victim's rendered image pipeline
What the bypass does: a compromised process A forges a PipelineId in victim origin B's namespace. Because the GPU process never checks who owns the namespace, it accepts the registration and overwrites B's async image pipeline, so A can potentially influence what B renders across the origin boundary. Conceptual illustration of the impact, not a live capture; what the research patch demonstrated directly is the cross-namespace registration being accepted, shown in the log above.

Tools

  • A local Firefox source build with a small research patch, guarded by XRE_IsContentProcess, that forges the outgoing PipelineId namespace and logs the accepted registration in the GPU process.
  • An HTML test case with a WebGL canvas and a cross-origin out-of-process iframe, so Fission places the iframe in a separate content process.
  • Firefox headless to load and capture the test page rendering on a stock build.

Impact

Demonstrated: a compromised content process can register a PipelineId in another process's namespace and have it accepted, silently overwriting the victim's entry in the shared pipeline manager, a Fission site-isolation authorization bypass. Inferred from that overwrite, but not separately captured here: cross-origin rendering confusion in the victim tab. This is not memory corruption; downstream consumers are null-guarded and reference-counted, so it does not yield code execution. The AddAsyncImagePipeline uniqueness guard is a MOZ_ASSERT, which is compiled out in release builds but would abort the process in a debug build, so a debug-build crash is possible where a release build silently overwrites instead.

Fix

Enforce the same namespace ownership check on the PipelineId path that the resource-key paths already use, rejecting any PipelineId whose namespace does not belong to the sending process.

if (!MatchesNamespace(aPipelineId)) {
  return IPC_FAIL(this, "PipelineId namespace does not belong to the sending process");
}
View on Mozilla Bugzilla Proof of concept code