Moderate firefox Logic Error 🔧 Commit mapped

Overview

Moderate
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Impactmoderate
DescriptionSite isolation issue in the Networking: HTTP component
ComponentNetworking
Bug ClassLogic Error
Tracker2075726
Fix commitf49bcdf82726 (firefox) +90/-0
CISA KEVNot listed
CreditedMozilla
Disclosed2026-10-27

Changed Functions

FunctionChangeNotes
onStartRequest
netwerk/test/browser/browser_alt_data_cross_origin.js
modified
onDataAvailable
netwerk/test/browser/browser_alt_data_cross_origin.js
modified
onStopRequest
netwerk/test/browser/browser_alt_data_cross_origin.js
modified
add_task
netwerk/test/browser/browser_alt_data_cross_origin.js
modified

Files Changed

  • netwerk/test/browser/browser_alt_data_cross_origin.js
diff --git a/netwerk/test/browser/browser_alt_data_cross_origin.js b/netwerk/test/browser/browser_alt_data_cross_origin.js
index 43ce432ca16..b7076dd6e27 100644
--- a/netwerk/test/browser/browser_alt_data_cross_origin.js
+++ b/netwerk/test/browser/browser_alt_data_cross_origin.js
@@ -64,6 +64,57 @@ async function writeAltDataTask(url, altType, altContent) {
   os.close();
 }
 
+// Content-process task: like writeAltDataTask, but the channel claims
+// `forgedOrigin` as its loading and triggering principal, as a compromised
+// content process could. The document's cookie jar settings are reused so the
+// load shares a cache entry with `forgedOrigin` iframes in this document.
+async function writeForgedAltDataTask(url, altType, altContent, forgedOrigin) {
+  const { NetUtil } = ChromeUtils.importESModule(
+    "resource://gre/modules/NetUtil.sys.mjs"
+  );
+  const forged =
+    Services.scriptSecurityManager.createContentPrincipalFromOrigin(
+      forgedOrigin
+    );
+
+  const chan = NetUtil.newChannel({
+    uri: url,
+    loadingPrincipal: forged,
+    triggeringPrincipal: forged,
+    securityFlags: Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT,
+    contentPolicyType: Ci.nsIContentPolicy.TYPE_SCRIPT,
+  });
+  chan.loadInfo.cookieJarSettings = content.document.cookieJarSettings;
+
+  const handle = await new Promise(resolve => {
+    chan.asyncOpen({
+      QueryInterface: ChromeUtils.generateQI([
+        "nsIStreamListener",
+        "nsIRequestObserver",
+      ]),
+      onStartRequest() {},
+      onDataAvailable(request, stream, offset, count) {
+        const s = Cc["@mozilla.org/scriptableinputstream;1"].createInstance(
+          Ci.nsIScriptableInputStream
+        );
+        s.init(stream);
+        s.read(count);
+      },
+      onStopRequest(request) {
+        resolve(
+          request
+            .QueryInterface(Ci.nsICacheInfoChannel)
+            .getCacheEntryWriteHandle()
+        );
+      },
+    });
+  });
+
+  const os = handle.openAlternativeOutputStream(altType, altContent.length);
+  os.write(altContent, altContent.length);
+  os.close();
+}
+
 // Content-process task: cache-only read of `url` preferring alt-data. Returns
 // { altType, buffer, status, partitionKey }.
 async function readAltDataTask(url, altType) {
@@ -171,3 +222,42 @@ add_task(async function test_cross_origin_alt_data_is_rejected() {
     );
   });
 });
+
+// A content process must not be able to bind alt-data to another origin by
+// claiming that origin's principal for the load that writes it.
+add_task(async function test_forged_principal_alt_data_is_rejected() {
+  const url = RESOURCE_URL + "?forged";
+  await BrowserTestUtils.withNewTab(PAGE_A, async browser => {
+    await SpecialPowers.spawn(
+      browser,
+      [url, ALT_TYPE, ALT_CONTENT, new URL(IFRAME_B).origin],
+      writeForgedAltDataTask
+    );
+
+    await SpecialPowers.spawn(browser, [IFRAME_B], async iframeUrl => {
+      const iframe = content.document.createElement("iframe");
+      const loaded = new Promise(resolve =>
+        iframe.addEventListener("load", resolve, { once: true })
+      );
+      iframe.src = iframeUrl;
+      content.document.body.appendChild(iframe);
+      await loaded;
+    });
+
+    const res = await SpecialPowers.spawn(
+      browser.browsingContext.children[0],
+      [url, ALT_TYPE],
+      readAltDataTask
+    );
+    ok(
+      Components.isSuccessCode(res.status),
+      "the read is a cache hit (LOAD_ONLY_FROM_CACHE)"
+    );
+    is(
+      res.altType,
+      "",
+      "alt-data written under a forged principal must NOT be served"
+    );
+    is(res.buffer, ORIGINAL, "the read gets the original script instead");
+  });
+});
Loading diff…