Medium firefox Logic Error 🔧 Commit mapped

Overview

Medium
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Impactmoderate
DescriptionSite isolation issue in the Graphics: WebRender component
ComponentGraphics
Bug ClassLogic Error
Tracker2040119
Fix commit0096399c9459 (firefox) +6/-0
CISA KEVNot listed
CreditedHcamael
Disclosed2026-07-21

Background

`WebRenderBridgeParent`
the parent-process (GPU/compositor) endpoint that services WebRender IPC requests on behalf of a content-process bridge child.
External image
a GPU texture or shared surface, referenced by an opaque wr::ExternalImageId, that WebRender composites without owning the underlying buffer directly.
`OwnsExternalImageId`
a CompositorManager predicate that reports whether a given external image id was actually registered by this manager/compositor.
Site isolation
the security boundary that keeps one content process from reading or manipulating another origin’s graphics resources.

Root Cause Analysis

WebRenderBridgeParent::UpdateSharedExternalImage accepted an attacker-controllable aExtId from a content-process IPC message and used it to update a shared surface without first verifying that the receiving bridge/compositor actually owned that external image id. The violated invariant is that a WebRenderBridgeParent may only manipulate external image ids that belong to its own CompositorManager; nothing enforced that a caller’s aExtId fell within the ids this endpoint had legitimately registered.

The fix inserts an ownership gate — GetCompositorBridge()->GetCompositorManager()->OwnsExternalImageId(aExtId) — that logs a gfxCriticalNote and returns false before any surface bookkeeping runs when the id is not owned. This works because it restores the missing cross-boundary check, so a compromised or malicious content process can no longer address another process’s external image resources through this path.

Key insight
The single core mistake was a missing ownership/authorization check on an IPC-supplied aExtId, letting one bridge act on external images it did not own; the fix adds an explicit OwnsExternalImageId guard that rejects unowned ids before use.

Attack Path

  1. Compromise a content process An attacker running code in a content process gains the ability to craft arbitrary WebRender IPC to the parent.
  2. Forge an external image id The attacker sends an UpdateSharedExternalImage request carrying an aExtId that belongs to a different origin’s compositor rather than its own.
  3. Bypass the ownership boundary Before the fix, UpdateSharedExternalImage never checked ownership, so it proceeded to update the shared surface keyed by that foreign id.
  4. Cross the isolation boundary The operation manipulates a shared external image outside the caller’s process, breaking the site-isolation guarantee for graphics resources.

Impact Assessment

An attacker with a compromised content process can reach across the site-isolation boundary to update external image resources owned by another compositor/origin from within the privileged GPU/compositor parent process. The precondition is prior code execution in a content process capable of sending WebRender IPC. Rated moderate impact and classified as a logic/site-isolation error, not memory corruption per the metadata.

Files Changed

  • gfx/layers/wr/WebRenderBridgeParent.cpp

Audit Directions

  • Unvalidated IPC identifiers
    Audit every parent-side WebRender/compositor handler that consumes an id (ExternalImageId, WrImageKey, surface handles) from a content process for a matching ownership or scope check before use.
  • Ownership-gate parity
    Compare sibling methods on WebRenderBridgeParent and CompositorManager to confirm each mutation path that touches shared surfaces enforces the same OwnsExternalImageId-style predicate.
  • Site-isolation resource boundaries
    Review shared-surface and texture-sharing code for places where a resource is looked up by caller-supplied key without confirming the caller’s process actually registered it.
diff --git a/gfx/layers/wr/WebRenderBridgeParent.cpp b/gfx/layers/wr/WebRenderBridgeParent.cpp
index 4f6de1027bd..6a00d9bc1a7 100644
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -990,6 +990,12 @@ bool WebRenderBridgeParent::UpdateSharedExternalImage(
     return true;
   }
 
+  if (!GetCompositorBridge()->GetCompositorManager()->OwnsExternalImageId(
+          aExtId)) {
+    gfxCriticalNote << "We do not own extId:" << wr::AsUint64(aExtId);
+    return false;
+  }
+
   auto key = wr::AsUint64(aKey);
   auto it = mSharedSurfaceIds.find(key);
   if (it == mSharedSurfaceIds.end()) {
Loading diff…