Low firefox Logic Error 🔧 Commit mapped

Overview

Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Impactlow
DescriptionMitigation bypass in the DOM: Push Subscriptions component
ComponentCore
Bug ClassLogic Error
Tracker2042021
Fix commitf370a45646ee (firefox) +37/-11
CISA KEVNot listed
CreditedIbuki Sato
Disclosed2026-10-27

Changed Functions

FunctionChangeNotes
if
testing/web-platform/tests/push-api/resources/permission-helper.js
modified

Files Changed

  • testing/web-platform/meta/push-api/cross-origin-nested.tentative.https.sub.window.js.ini
  • testing/web-platform/meta/push-api/cross-origin-same-site-request.tentative.https.sub.window.js.ini
  • testing/web-platform/tests/push-api/resources/cross-origin-nested-child.sub.html
  • testing/web-platform/tests/push-api/resources/cross-origin-nested-parent.sub.html
  • testing/web-platform/tests/push-api/resources/cross-origin-serviceworker-iframe.sub.html
  • testing/web-platform/tests/push-api/resources/permission-helper.js
diff --git a/testing/web-platform/meta/push-api/cross-origin-nested.tentative.https.sub.window.js.ini b/testing/web-platform/meta/push-api/cross-origin-nested.tentative.https.sub.window.js.ini
index 39d84ee1d27..89fef93cffd 100644
--- a/testing/web-platform/meta/push-api/cross-origin-nested.tentative.https.sub.window.js.ini
+++ b/testing/web-platform/meta/push-api/cross-origin-nested.tentative.https.sub.window.js.ini
@@ -1,2 +1,13 @@
 [cross-origin-nested.tentative.https.sub.window.html]
-  max-asserts: 2
+  expected: TIMEOUT
+  [third party iframe]
+    expected: TIMEOUT
+
+  [nested first party iframe]
+    expected: NOTRUN
+
+  [third party worker]
+    expected: NOTRUN
+
+  [nested first party worker]
+    expected: NOTRUN
diff --git a/testing/web-platform/meta/push-api/cross-origin-same-site-request.tentative.https.sub.window.js.ini b/testing/web-platform/meta/push-api/cross-origin-same-site-request.tentative.https.sub.window.js.ini
new file mode 100644
index 00000000000..85c7a1fc9e9
--- /dev/null
+++ b/testing/web-platform/meta/push-api/cross-origin-same-site-request.tentative.https.sub.window.js.ini
@@ -0,0 +1,4 @@
+[cross-origin-same-site-request.tentative.https.sub.window.html]
+  expected: TIMEOUT
+  [same-site cross-origin iframe]
+    expected: TIMEOUT
diff --git a/testing/web-platform/tests/push-api/resources/cross-origin-nested-child.sub.html b/testing/web-platform/tests/push-api/resources/cross-origin-nested-child.sub.html
index b353030a740..c748d4265b0 100644
--- a/testing/web-platform/tests/push-api/resources/cross-origin-nested-child.sub.html
+++ b/testing/web-platform/tests/push-api/resources/cross-origin-nested-child.sub.html
@@ -1,6 +1,8 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
 <title>Push subscription nested iframe first party child</title>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
 <script src="/notifications/resources/helpers.js"></script>
 <body>
 <script type="module">
@@ -9,5 +11,8 @@ import { permissionTest } from "./permission-helper.js"
 await unregisterAllServiceWorker();
 const registration = await navigator.serviceWorker.register("../noop-sw.js");
 
-permissionTest('https://{{hosts[][]}}:{{ports[https][0]}}', "child", registration);
+test_driver.set_test_context(window.top);
+await test_driver.bless("Triggering a subscription", () => {
+  permissionTest('https://{{hosts[][]}}:{{ports[https][0]}}', "child", registration);
+});
 </script>
diff --git a/testing/web-platform/tests/push-api/resources/cross-origin-nested-parent.sub.html b/testing/web-platform/tests/push-api/resources/cross-origin-nested-parent.sub.html
index 5d95e1dbddf..5997b79ab70 100644
--- a/testing/web-platform/tests/push-api/resources/cross-origin-nested-parent.sub.html
+++ b/testing/web-platform/tests/push-api/resources/cross-origin-nested-parent.sub.html
@@ -10,6 +10,8 @@ import { permissionTest } from "./permission-helper.js"
 
 // Grant the permission so that we can confirm the permission being denied
 // regardless of the actual permission status.
+// Note that this will not set the permission for the current iframe if
+// running on a browser engine with partitioned storage.
 test_driver.set_test_context(window.top);
 await test_driver.set_permission({ name: "notifications" }, "granted");
 
@@ -18,7 +20,9 @@ const registration = await navigator.serviceWorker.register("../noop-sw.js");
 
 const firstPartyOrigin = 'https://{{hosts[][]}}:{{ports[https][0]}}';
 
-permissionTest(firstPartyOrigin, "parent", registration);
+await test_driver.bless("Triggering a subscription", async () => {
+  await permissionTest(firstPartyOrigin, "parent", registration);
+});
 
 const nestedChild =
   `${firstPartyOrigin}/push-api/resources/cross-origin-nested-child.sub.html`;
diff --git a/testing/web-platform/tests/push-api/resources/cross-origin-serviceworker-iframe.sub.html b/testing/web-platform/tests/push-api/resources/cross-origin-serviceworker-iframe.sub.html
index d6b61be73fe..30dd304d91c 100644
--- a/testing/web-platform/tests/push-api/resources/cross-origin-serviceworker-iframe.sub.html
+++ b/testing/web-platform/tests/push-api/resources/cross-origin-serviceworker-iframe.sub.html
@@ -16,6 +16,8 @@ navigator.serviceWorker.addEventListener("message", ev => {
 
 // Grant the permission so that we can confirm the permission being denied
 // regardless of the actual permission status.
+// Note that this will not set the permission for the current iframe if
+// running on a browser engine with partitioned storage.
 test_driver.set_test_context(window.top);
 await test_driver.set_permission({ name: "notifications" }, "granted");
 
diff --git a/testing/web-platform/tests/push-api/resources/permission-helper.js b/testing/web-platform/tests/push-api/resources/permission-helper.js
index 27a16b7c4e0..e59448e7f53 100644
--- a/testing/web-platform/tests/push-api/resources/permission-helper.js
+++ b/testing/web-platform/tests/push-api/resources/permission-helper.js
@@ -1,6 +1,6 @@
 import { createVapid } from "./vapid.js";
 
-export function permissionTest(origin, sender, registration) {
+export async function permissionTest(origin, sender, registration) {
   function ping(message) {
     if (!globalThis.WorkerGlobalScope) {
       window.top.postMessage(message, origin);
@@ -9,13 +9,13 @@ export function permissionTest(origin, sender, registration) {
     }
   }
 
-  (async () => {
-    const vapid = await createVapid();
-    const subscribed = await registration.pushManager.subscribe({
-      applicationServerKey: vapid.publicKey
-    }).then(() => true, _ => false)
-    ping({ sender, subscribed });
-  })();
+  // Wait for subscription before proceeding to worker subscription,
+  // to prevent collision between multiple permission requests.
+  const vapid = await createVapid();
+  const subscribed = await registration.pushManager.subscribe({
+    applicationServerKey: vapid.publicKey
+  }).then(() => true, _ => false);
+  ping({ sender, subscribed });
 
   if (!globalThis.WorkerGlobalScope) {
     const workerUrl = new URL(`./permission-worker.js`, import.meta.url);
Loading diff…