Low firefox Logic Error 🔧 Commit mapped

Overview

Low
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
Impactlow
DescriptionSpoofing issue in the DOM: Core & HTML component
ComponentDOM
Bug ClassLogic Error
Tracker2051146
Fix commitec1626bdc1a2 (firefox) +51/-1
CISA KEVNot listed
CreditedRiski Muhammad Ivan
Disclosed2026-09-01

Changed Functions

FunctionChangeNotes
add_task
dom/documentpip/tests/browser/browser_pip_exits_fs.js
modified

Files Changed

  • dom/documentpip/tests/browser/browser.toml
  • dom/documentpip/tests/browser/browser_pip_exits_fs.js
  • toolkit/components/windowwatcher/nsWindowWatcher.cpp
diff --git a/dom/documentpip/tests/browser/browser.toml b/dom/documentpip/tests/browser/browser.toml
index 239ad3eba6a..d6bf145aa2e 100644
--- a/dom/documentpip/tests/browser/browser.toml
+++ b/dom/documentpip/tests/browser/browser.toml
@@ -14,6 +14,8 @@ skip-if = [
 
 ["browser_pip_closes_once.js"]
 
+["browser_pip_exits_fs.js"]
+
 ["browser_pip_extensions.js"]
 
 ["browser_pip_fullscreen_disallowed.js"]
diff --git a/dom/documentpip/tests/browser/browser_pip_exits_fs.js b/dom/documentpip/tests/browser/browser_pip_exits_fs.js
new file mode 100644
index 00000000000..a7dd78c181b
--- /dev/null
+++ b/dom/documentpip/tests/browser/browser_pip_exits_fs.js
@@ -0,0 +1,46 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const { DOMFullscreenTestUtils } = ChromeUtils.importESModule(
+  "resource://testing-common/DOMFullscreenTestUtils.sys.mjs"
+);
+
+DOMFullscreenTestUtils.init(this, window);
+
+add_task(async function opening_pip_exits_fullscreen() {
+  await SpecialPowers.pushPrefEnv({
+    set: [["full-screen-api.exit-on.windowOpen", true]],
+  });
+
+  const tab = await BrowserTestUtils.openNewForegroundTab({
+    gBrowser,
+    opening: "https://example.com",
+    waitForLoad: true,
+  });
+  const browser = tab.linkedBrowser;
+
+  await DOMFullscreenTestUtils.changeFullscreen(browser, true);
+  ok(document.fullscreen, "Browser should be in fullscreen");
+
+  // Opening a document PiP window should exit fullscreen.
+  let fullscreenExited = DOMFullscreenTestUtils.waitForFullScreenState(
+    browser,
+    false
+  );
+  const chromePiPPromise = BrowserTestUtils.waitForNewWindow();
+  await SpecialPowers.spawn(browser, [], async () => {
+    content.document.notifyUserGestureActivation();
+    // Must use wrappedJSObject for LegacyIsCallerChromeOrNativeCode to be false
+    await content.wrappedJSObject.documentPictureInPicture.requestWindow();
+  });
+  const chromePiP = await chromePiPPromise;
+  await fullscreenExited;
+
+  ok(!document.fullscreen, "Browser should have exited fullscreen");
+
+  // Cleanup.
+  await BrowserTestUtils.closeWindow(chromePiP);
+  BrowserTestUtils.removeTab(tab);
+});
diff --git a/toolkit/components/windowwatcher/nsWindowWatcher.cpp b/toolkit/components/windowwatcher/nsWindowWatcher.cpp
index 95df4d57026..62aad2e351c 100644
--- a/toolkit/components/windowwatcher/nsWindowWatcher.cpp
+++ b/toolkit/components/windowwatcher/nsWindowWatcher.cpp
@@ -1517,7 +1517,9 @@ nsresult nsWindowWatcher::OpenWindowInternal(
     }
   }
   // If a website opens a popup exit DOM fullscreen
-  if (StaticPrefs::full_screen_api_exit_on_windowOpen() && aCalledFromJS &&
+  if (StaticPrefs::full_screen_api_exit_on_windowOpen() &&
+      (aCalledFromJS ||
+       chromeFlags & nsIWebBrowserChrome::CHROME_DOCUMENT_PIP) &&
       !hasChromeParent && !isCallerChrome && parentOuterWin) {
     Document::AsyncExitFullscreen(parentOuterWin->GetDoc());
   }
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/dom/documentpip/tests/browser/browser.toml b/dom/documentpip/tests/browser/browser.toml
index 239ad3eba6a..d6bf145aa2e 100644
--- a/dom/documentpip/tests/browser/browser.toml
+++ b/dom/documentpip/tests/browser/browser.toml
@@ -14,6 +14,8 @@ skip-if = [
 
 ["browser_pip_closes_once.js"]
 
+["browser_pip_exits_fs.js"]
+
 ["browser_pip_extensions.js"]
 
 ["browser_pip_fullscreen_disallowed.js"]
diff --git a/dom/documentpip/tests/browser/browser_pip_exits_fs.js b/dom/documentpip/tests/browser/browser_pip_exits_fs.js
new file mode 100644
index 00000000000..a7dd78c181b
--- /dev/null
+++ b/dom/documentpip/tests/browser/browser_pip_exits_fs.js
@@ -0,0 +1,46 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const { DOMFullscreenTestUtils } = ChromeUtils.importESModule(
+  "resource://testing-common/DOMFullscreenTestUtils.sys.mjs"
+);
+
+DOMFullscreenTestUtils.init(this, window);
+
+add_task(async function opening_pip_exits_fullscreen() {
+  await SpecialPowers.pushPrefEnv({
+    set: [["full-screen-api.exit-on.windowOpen", true]],
+  });
+
+  const tab = await BrowserTestUtils.openNewForegroundTab({
+    gBrowser,
+    opening: "https://example.com",
+    waitForLoad: true,
+  });
+  const browser = tab.linkedBrowser;
+
+  await DOMFullscreenTestUtils.changeFullscreen(browser, true);
+  ok(document.fullscreen, "Browser should be in fullscreen");
+
+  // Opening a document PiP window should exit fullscreen.
+  let fullscreenExited = DOMFullscreenTestUtils.waitForFullScreenState(
+    browser,
+    false
+  );
+  const chromePiPPromise = BrowserTestUtils.waitForNewWindow();
+  await SpecialPowers.spawn(browser, [], async () => {
+    content.document.notifyUserGestureActivation();
+    // Must use wrappedJSObject for LegacyIsCallerChromeOrNativeCode to be false
+    await content.wrappedJSObject.documentPictureInPicture.requestWindow();
+  });
+  const chromePiP = await chromePiPPromise;
+  await fullscreenExited;
+
+  ok(!document.fullscreen, "Browser should have exited fullscreen");
+
+  // Cleanup.
+  await BrowserTestUtils.closeWindow(chromePiP);
+  BrowserTestUtils.removeTab(tab);
+});
Loading diff…