CVE-2026-74974
Overview
Background
- `InterceptedHttpChannel`
- the HTTP channel used when a Service Worker intercepts a network request and synthesizes its own response.
- `LoadTainting::Opaque`
- the tainting state marking a cross-origin, no-CORS response whose body must stay hidden from the requesting origin.
- `AllRedirectsSameOrigin` flag
- a channel bit asserting that every hop of a load stayed same-origin, used downstream to decide whether a resource may be exposed cross-origin.
- `StartSynthesizedResponse`
- the
InterceptedHttpChannelmethod that installs a Service-Worker-provided response and optionally follows synthetic redirects.
Root Cause Analysis
When a Service Worker synthesizes a response, InterceptedHttpChannel::StartSynthesizedResponse installs mSynthesizedResponseHead and proceeds without reconciling the channel’s AllRedirectsSameOrigin bookkeeping against the actual tainting of the synthesized load. The invariant that AllRedirectsSameOrigin must be false whenever the load is LoadTainting::Opaque (i.e., a cross-origin no-CORS result) was not enforced along the synthesized-response path, so an opaque cross-origin body could be presented as though all hops were same-origin. Downstream consumers that trust the AllRedirectsSameOrigin flag would then treat the tainted resource as safe to expose, defeating the same-origin policy.
The fix adds an explicit check: if mLoadInfo->GetTainting() == LoadTainting::Opaque, it calls StoreAllRedirectsSameOriginIgnoringInternal(false), forcing the flag to reflect the true cross-origin nature before ShouldRedirect() and later exposure decisions run. This restores the invariant precisely where the Service Worker’s opaque response entered the channel, closing the mismatch.
AllRedirectsSameOrigin bit when a Service Worker synthesized an opaque, cross-origin response, letting tainted data inherit a same-origin trust label; the fix reasserts the invariant by forcing that flag to false for LoadTainting::Opaque loads.Attack Path
- Register a malicious Service Worker An attacker controls a page whose Service Worker can intercept its subresource fetches.
- Fetch a cross-origin target
The page requests a victim cross-origin resource in no-CORS mode, producing a
LoadTainting::Opaqueload. - Synthesize an opaque response
The Service Worker returns the opaque cross-origin response through
StartSynthesizedResponse, whereAllRedirectsSameOriginis left incorrectly asserted. - Consume as same-origin
A downstream consumer that trusts
AllRedirectsSameOrigintreats the tainted body as same-origin and permits reading it. - Exfiltrate cross-origin data The attacker reads the otherwise-protected cross-origin content, achieving a same-origin policy bypass.
Impact Assessment
Files Changed
netwerk/protocol/http/InterceptedHttpChannel.cpp
Audit Directions
- Tainting vs. same-origin flagsAudit every path that sets or trusts
AllRedirectsSameOrigin(or similar same-origin assertions) to confirm it is reconciled againstLoadInfo::GetTainting()for opaque loads. - Service Worker synthesized responsesReview other
InterceptedHttpChanneland Fetch-interception entry points for security-relevant channel bits that are computed from network hops but bypassed when a response is synthesized. - Cross-origin exposure consumersInspect callers that gate exposure or reads on same-origin flags to ensure they also honor tainting, so a single stale flag cannot unlock cross-origin data.
Patch
diff --git a/netwerk/protocol/http/InterceptedHttpChannel.cpp b/netwerk/protocol/http/InterceptedHttpChannel.cpp
index 7af3a4d44fc..f094d87b789 100644
--- a/netwerk/protocol/http/InterceptedHttpChannel.cpp
+++ b/netwerk/protocol/http/InterceptedHttpChannel.cpp
@@ -915,6 +915,10 @@ InterceptedHttpChannel::StartSynthesizedResponse(
mResponseHead = std::move(mSynthesizedResponseHead);
+ if (mLoadInfo->GetTainting() == LoadTainting::Opaque) {
+ StoreAllRedirectsSameOriginIgnoringInternal(false);
+ }
+
if (ShouldRedirect()) {
rv = FollowSyntheticRedirect();
NS_ENSURE_SUCCESS(rv, rv);