High firefox Logic Error 🔧 Commit mapped

Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
Impacthigh
DescriptionInformation disclosure in the Graphics: ImageLib component
ComponentImageLib
Bug ClassLogic Error
Tracker2050626
Fix commit27a3a8689a00 (firefox) +36/-15
CISA KEVNot listed
Creditedsatyamasd
Disclosed2026-07-21

Changed Functions

FunctionChangeNotes
if
image/imgRequest.cpp
modified
GetHadCrossOriginRedirects
image/imgRequestProxy.cpp
modified
if
image/imgRequestProxy.cpp
modified

Files Changed

  • image/imgRequest.cpp
  • image/imgRequest.h
  • image/imgRequestProxy.cpp
  • testing/web-platform/meta/fetch/images/canvas-remote-read-remote-image-redirect.html.ini
diff --git a/image/imgRequest.cpp b/image/imgRequest.cpp
index a7f7a8d8036..5b3676a9afa 100644
--- a/image/imgRequest.cpp
+++ b/image/imgRequest.cpp
@@ -622,6 +622,22 @@ bool imgRequest::HadInsecureRedirect() const {
   return mHadInsecureRedirect;
 }
 
+bool imgRequest::HadCrossOriginRedirects() const {
+  // While the channel is still around (during the load) read the authoritative
+  // value from it; afterwards fall back to the value latched in OnStopRequest.
+  // Ignore internal redirects (e.g. a service worker substituting a same-origin
+  // response for a cross-origin request): those are not cross-origin data flow
+  // and must not taint. Real cross-origin redirects (incl. bounce-backs) count.
+  if (mTimedChannel) {
+    bool allRedirectsSameOrigin = false;
+    return NS_SUCCEEDED(
+               mTimedChannel->GetAllRedirectsSameOriginIgnoringInternal(
+                   &allRedirectsSameOrigin)) &&
+           !allRedirectsSameOrigin;
+  }
+  return mHadCrossOriginRedirects;
+}
+
 /** nsIRequestObserver methods **/
 
 NS_IMETHODIMP
@@ -817,6 +833,18 @@ imgRequest::OnStopRequest(nsIRequest* aRequest, nsresult status) {
     progressTracker->SyncNotifyProgress(progress);
   }
 
+  // Store whether the load involved a cross-origin redirect before we drop the
+  // timed channel. Internal redirects (e.g. a service worker serving a
+  // same-origin response for a cross-origin request) are ignored so we don't
+  // over-taint; real cross-origin redirects (incl. bounce-backs) still count.
+  if (mTimedChannel) {
+    bool allRedirectsSameOrigin = false;
+    mHadCrossOriginRedirects =
+        NS_SUCCEEDED(mTimedChannel->GetAllRedirectsSameOriginIgnoringInternal(
+            &allRedirectsSameOrigin)) &&
+        !allRedirectsSameOrigin;
+  }
+
   mTimedChannel = nullptr;
   return NS_OK;
 }
diff --git a/image/imgRequest.h b/image/imgRequest.h
index 33497c94782..febd6d65529 100644
--- a/image/imgRequest.h
+++ b/image/imgRequest.h
@@ -165,6 +165,10 @@ class imgRequest final : public nsIThreadRetargetableStreamListener,
 
   nsITimedChannel* GetTimedChannel() const { return mTimedChannel; }
 
+  /// Returns true if any redirect in the chain that loaded this image was
+  /// cross-origin.
+  bool HadCrossOriginRedirects() const;
+
   imgCacheValidator* GetValidator() const { return mValidator; }
   void SetValidator(imgCacheValidator* aValidator) { mValidator = aValidator; }
 
@@ -285,6 +289,8 @@ class imgRequest final : public nsIThreadRetargetableStreamListener,
   bool mIsCrossSiteNoCORSRequest;
 
   bool mShouldReportRenderTimeForLCP;
+  // True if any redirect in the chain that loaded this image was cross-origin.
+  bool mHadCrossOriginRedirects = false;
   // SVGs can't be OffMainThread for example
   bool mOffMainThreadData = false;
 
diff --git a/image/imgRequestProxy.cpp b/image/imgRequestProxy.cpp
index 1067f9ba827..9a41d868e02 100644
--- a/image/imgRequestProxy.cpp
+++ b/image/imgRequestProxy.cpp
@@ -873,17 +873,8 @@ imgRequestProxy::GetImagePrincipal(nsIPrincipal** aPrincipal) {
 
 NS_IMETHODIMP
 imgRequestProxy::GetHadCrossOriginRedirects(bool* aHadCrossOriginRedirects) {
-  *aHadCrossOriginRedirects = false;
-
-  nsCOMPtr<nsITimedChannel> timedChannel = TimedChannel();
-  if (timedChannel) {
-    bool allRedirectsSameOrigin = false;
-    *aHadCrossOriginRedirects =
-        NS_SUCCEEDED(timedChannel->GetAllRedirectsSameOriginIgnoringInternal(
-            &allRedirectsSameOrigin)) &&
-        !allRedirectsSameOrigin;
-  }
-
+  *aHadCrossOriginRedirects =
+      GetOwner() ? GetOwner()->HadCrossOriginRedirects() : false;
   return NS_OK;
 }
 
diff --git a/testing/web-platform/meta/fetch/images/canvas-remote-read-remote-image-redirect.html.ini b/testing/web-platform/meta/fetch/images/canvas-remote-read-remote-image-redirect.html.ini
deleted file mode 100644
index 33630ce7eba..00000000000
--- a/testing/web-platform/meta/fetch/images/canvas-remote-read-remote-image-redirect.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[canvas-remote-read-remote-image-redirect.html]
-  [Load a no-cors image from a same-origin URL that redirects to a cross-origin URL that redirects to the initial origin]
-    expected: FAIL
-
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/testing/web-platform/meta/fetch/images/canvas-remote-read-remote-image-redirect.html.ini b/testing/web-platform/meta/fetch/images/canvas-remote-read-remote-image-redirect.html.ini
deleted file mode 100644
index 33630ce7eba..00000000000
--- a/testing/web-platform/meta/fetch/images/canvas-remote-read-remote-image-redirect.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[canvas-remote-read-remote-image-redirect.html]
-  [Load a no-cors image from a same-origin URL that redirects to a cross-origin URL that redirects to the initial origin]
-    expected: FAIL
-
Loading diff…