Chrome · WebAppInstalls › PWA
CVE-2026-113080
UAF in WebAppInstalls (PWA)
Overview
Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
IN_PROC_BROWSER_TEST_Fchrome/browser/extensions/api/tabs/tabs_test.cc |
modified | |
ifchrome/browser/extensions/extension_browsertest.cc |
modified |
Files Changed
chrome/browser/extensions/api/tabs/tabs_test.ccchrome/browser/ui/browser_browsertest.ccchrome/browser/extensions/extension_browsertest.ccchrome/browser/ui/browser_commands.cc
Patch
From 977032a456e29c6e18edb398332e5f793bf10bcd Mon Sep 17 00:00:00 2001 From: Adriana Ixba <[email protected]> Date: Thu, 17 Sep 2026 20:42:48 -0700 Subject: [PATCH] [PWA] Disallow tab duplication on APP_POPUPs browser windows Duplicating a tab in a TYPE_APP_POPUP browser window (such as via chrome.tabs.duplicate) is not supported because app popups do not have a tab strip and cannot be cloned into a standalone popup window with a valid app controller. Previously, attempting to duplicate an app popup bypassed the DCHECK in release builds and created a TYPE_APP_POPUP window with an empty app_name, leading to a browser-process CHECK crash on Linux and a chromeless window without an origin indicator on Windows/macOS. This CL: 1. Updates chrome::CanDuplicateTabAt() to return false for BrowserWindowInterface::TYPE_APP_POPUP, mirroring TYPE_PICTURE_IN_PICTURE. And additionally guard with CanDuplicateTabAt in DuplicateTabAt 2. Hardens CreateAndShowNewWindowWithContents() by upgrading the DCHECK against TYPE_APP_POPUP to CHECK_NE. 3. Updates ExtensionBrowserTest::CreateBrowserWindowWithType to populate app_name for TYPE_APP_POPUP test windows. 4. Adds test coverage in BrowserTest.CanDuplicateTab and ExtensionTabsTest.CannotDuplicateAppPopupWindows. Bug: 533135911 Change-Id: I52ed317eb95f386dcff4f891afca76543abd9630 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8415307 Reviewed-by: Daniel Murphy <[email protected]> Reviewed-by: Eshwar Stalin <[email protected]> Commit-Queue: Adriana Ixba <[email protected]> Cr-Commit-Position: refs/heads/main@{#1700446} --- diff --git a/chrome/browser/ui/browser_commands.cc b/chrome/browser/ui/browser_commands.cc index 53a351ee..08c50fa 100644 --- a/chrome/browser/ui/browser_commands.cc +++ b/chrome/browser/ui/browser_commands.cc @@ -280,7 +280,8 @@ std::unique_ptr<content::WebContents> contents, BrowserWindowInterface* original_browser) { BrowserWindowInterface* new_browser = nullptr; - DCHECK(original_browser->GetType() != BrowserWindowInterface::TYPE_APP_POPUP); + CHECK_NE(original_browser->GetType(), BrowserWindowInterface::TYPE_APP_POPUP); + CHECK_NE(original_browser->GetType(), BrowserWindowInterface::TYPE_DEVTOOLS); if (original_browser->GetType() == BrowserWindowInterface::TYPE_APP) { const bool is_trusted_source = WindowFeatureController::From(original_browser)->IsTrustedSource(); @@ -369,6 +370,9 @@ content::WebContents* DuplicateTabAt(BrowserWindowInterface* browser, int index, int dst_index) { + if (!chrome::CanDuplicateTabAt(browser, index)) { + return nullptr; + } content::WebContents* contents = browser->GetTabStripModel()->GetWebContentsAt(index); CHECK(contents); @@ -1766,7 +1770,9 @@ } bool CanDuplicateTabAt(const BrowserWindowInterface* browser, int index) { - if (browser->GetType() == BrowserWindowInterface::TYPE_PICTURE_IN_PICTURE) { + if (browser->GetType() == BrowserWindowInterface::TYPE_PICTURE_IN_PICTURE || + browser->GetType() == BrowserWindowInterface::TYPE_APP_POPUP || + browser->GetType() == BrowserWindowInterface::TYPE_DEVTOOLS) { return false; } WebContents* contents = browser->GetTabStripModel()->GetWebContentsAt(index); diff --git a/chrome/browser/extensions/api/tabs/tabs_test.cc b/chrome/browser/extensions/api/tabs/tabs_test.cc index be48a02..fc6a164 100644 --- a/chrome/browser/extensions/api/tabs/tabs_test.cc +++ b/chrome/browser/extensions/api/tabs/tabs_test.cc @@ -5452,6 +5452,40 @@ error); } +IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, CannotDuplicateAppPopupWindows) { + // Create app popup browser. + BrowserWindowInterface* app_popup_browser = + CreateBrowserWindowWithType(BrowserWindowInterface::Type::TYPE_APP_POPUP); + TabListInterface* app_popup_tab_list = + TabListInterface::From(app_popup_browser); + + // Ensure we have a tab. + if (app_popup_tab_list->GetTabCount() == 0) { + app_popup_tab_list->OpenTab(GURL(url::kAboutBlankURL), -1); + } + ASSERT_GE(app_popup_tab_list->GetTabCount(), 1); + content::WebContents* web_contents = + app_popup_tab_list->GetTab(0)->GetContents(); + ASSERT_NE(web_contents, nullptr); + int app_popup_tab_id = ExtensionTabUtil::GetTabId(web_contents); + ASSERT_GT(app_popup_tab_id, 0); + + // Attempt to duplicate the app popup tab. This should fail as app popup tabs + // are not allowed to be duplicated. + auto function = base::MakeRefCounted<TabsDuplicateFunction>(); + scoped_refptr<const Extension> extension = + ExtensionBuilder("Test").AddAPIPermission("tabs").Build(); + function->set_extension(extension); + std::string args = base::StringPrintf("[%d]", app_popup_tab_id); + std::string error = utils::RunFunctionAndReturnError( + function.get(), args, app_popup_browser->GetProfile(), + utils::FunctionMode::kNone); + EXPECT_EQ( + ErrorUtils::FormatErrorMessage(keys::kCannotDuplicateTab, + base::NumberToString(app_popup_tab_id)), + error); +} + #endif // !BUILDFLAG(IS_ANDROID) #if BUILDFLAG(IS_CHROMEOS) diff --git a/chrome/browser/extensions/extension_browsertest.cc b/chrome/browser/extensions/extension_browsertest.cc index e27cee5..53b14ab 100644 --- a/chrome/browser/extensions/extension_browsertest.cc +++ b/chrome/browser/extensions/extension_browsertest.cc @@ -853,7 +853,8 @@ BrowserWindowInterface::Type type) { BrowserWindowCreateParams create_params = BrowserWindowCreateParams( type, *GetProfile(), /*from_user_gesture=*/false); - if (type == BrowserWindowInterface::Type::TYPE_APP) { + if (type == BrowserWindowInterface::Type::TYPE_APP || + type == BrowserWindowInterface::Type::TYPE_APP_POPUP) { // Apps must have an app name. create_params.app_name = "app_name"; } diff --git a/chrome/browser/ui/browser_browsertest.cc b/chrome/browser/ui/browser_browsertest.cc index 0a91dc2..792e4f6 100644 --- a/chrome/browser/ui/browser_browsertest.cc +++ b/chrome/browser/ui/browser_browsertest.cc @@ -2805,6 +2805,24 @@ EXPECT_TRUE(chrome::CanDuplicateTab(browser())); EXPECT_TRUE(chrome::CanDuplicateTabAt(browser(), 0)); EXPECT_TRUE(chrome::CanDuplicateTabAt(browser(), 1)); + + BrowserWindowInterface* app_popup_browser = + CreateBrowserWindow(BrowserWindowCreateParams::CreateForAppPopup( + "app_name", /*trusted_source=*/true, gfx::Rect(), + browser()->GetProfile(), /*user_gesture=*/true)); + AddBlankTabAndShow(app_popup_browser); + EXPECT_FALSE(chrome::CanDuplicateTab(app_popup_browser)); + EXPECT_FALSE(chrome::CanDuplicateTabAt(app_popup_browser, 0)); + EXPECT_FALSE(chrome::CanDuplicateKeyboardFocusedTab(app_popup_browser)); + EXPECT_EQ(chrome::DuplicateTabAt(app_popup_browser, 0), nullptr); + + BrowserWindowInterface* devtools_browser = CreateBrowserWindow( + BrowserWindowCreateParams::CreateForDevTools(browser()->GetProfile())); + AddBlankTabAndShow(devtools_browser); + EXPECT_FALSE(chrome::CanDuplicateTab(devtools_browser)); + EXPECT_FALSE(chrome::CanDuplicateTabAt(devtools_browser, 0)); + EXPECT_FALSE(chrome::CanDuplicateKeyboardFocusedTab(devtools_browser)); + EXPECT_EQ(chrome::DuplicateTabAt(devtools_browser, 0), nullptr); } namespace {
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/chrome/browser/extensions/api/tabs/tabs_test.cc b/chrome/browser/extensions/api/tabs/tabs_test.cc
index be48a02..fc6a164 100644
--- a/chrome/browser/extensions/api/tabs/tabs_test.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_test.cc
@@ -5452,6 +5452,40 @@
error);
}
+IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, CannotDuplicateAppPopupWindows) {
+ // Create app popup browser.
+ BrowserWindowInterface* app_popup_browser =
+ CreateBrowserWindowWithType(BrowserWindowInterface::Type::TYPE_APP_POPUP);
+ TabListInterface* app_popup_tab_list =
+ TabListInterface::From(app_popup_browser);
+
+ // Ensure we have a tab.
+ if (app_popup_tab_list->GetTabCount() == 0) {
+ app_popup_tab_list->OpenTab(GURL(url::kAboutBlankURL), -1);
+ }
+ ASSERT_GE(app_popup_tab_list->GetTabCount(), 1);
+ content::WebContents* web_contents =
+ app_popup_tab_list->GetTab(0)->GetContents();
+ ASSERT_NE(web_contents, nullptr);
+ int app_popup_tab_id = ExtensionTabUtil::GetTabId(web_contents);
+ ASSERT_GT(app_popup_tab_id, 0);
+
+ // Attempt to duplicate the app popup tab. This should fail as app popup tabs
+ // are not allowed to be duplicated.
+ auto function = base::MakeRefCounted<TabsDuplicateFunction>();
+ scoped_refptr<const Extension> extension =
+ ExtensionBuilder("Test").AddAPIPermission("tabs").Build();
+ function->set_extension(extension);
+ std::string args = base::StringPrintf("[%d]", app_popup_tab_id);
+ std::string error = utils::RunFunctionAndReturnError(
+ function.get(), args, app_popup_browser->GetProfile(),
+ utils::FunctionMode::kNone);
+ EXPECT_EQ(
+ ErrorUtils::FormatErrorMessage(keys::kCannotDuplicateTab,
+ base::NumberToString(app_popup_tab_id)),
+ error);
+}
+
#endif // !BUILDFLAG(IS_ANDROID)
#if BUILDFLAG(IS_CHROMEOS)
diff --git a/chrome/browser/extensions/extension_browsertest.cc b/chrome/browser/extensions/extension_browsertest.cc
index e27cee5..53b14ab 100644
--- a/chrome/browser/extensions/extension_browsertest.cc
+++ b/chrome/browser/extensions/extension_browsertest.cc
@@ -853,7 +853,8 @@
BrowserWindowInterface::Type type) {
BrowserWindowCreateParams create_params = BrowserWindowCreateParams(
type, *GetProfile(), /*from_user_gesture=*/false);
- if (type == BrowserWindowInterface::Type::TYPE_APP) {
+ if (type == BrowserWindowInterface::Type::TYPE_APP ||
+ type == BrowserWindowInterface::Type::TYPE_APP_POPUP) {
// Apps must have an app name.
create_params.app_name = "app_name";
}
diff --git a/chrome/browser/ui/browser_browsertest.cc b/chrome/browser/ui/browser_browsertest.cc
index 0a91dc2..792e4f6 100644
--- a/chrome/browser/ui/browser_browsertest.cc
+++ b/chrome/browser/ui/browser_browsertest.cc
@@ -2805,6 +2805,24 @@
EXPECT_TRUE(chrome::CanDuplicateTab(browser()));
EXPECT_TRUE(chrome::CanDuplicateTabAt(browser(), 0));
EXPECT_TRUE(chrome::CanDuplicateTabAt(browser(), 1));
+
+ BrowserWindowInterface* app_popup_browser =
+ CreateBrowserWindow(BrowserWindowCreateParams::CreateForAppPopup(
+ "app_name", /*trusted_source=*/true, gfx::Rect(),
+ browser()->GetProfile(), /*user_gesture=*/true));
+ AddBlankTabAndShow(app_popup_browser);
+ EXPECT_FALSE(chrome::CanDuplicateTab(app_popup_browser));
+ EXPECT_FALSE(chrome::CanDuplicateTabAt(app_popup_browser, 0));
+ EXPECT_FALSE(chrome::CanDuplicateKeyboardFocusedTab(app_popup_browser));
+ EXPECT_EQ(chrome::DuplicateTabAt(app_popup_browser, 0), nullptr);
+
+ BrowserWindowInterface* devtools_browser = CreateBrowserWindow(
+ BrowserWindowCreateParams::CreateForDevTools(browser()->GetProfile()));
+ AddBlankTabAndShow(devtools_browser);
+ EXPECT_FALSE(chrome::CanDuplicateTab(devtools_browser));
+ EXPECT_FALSE(chrome::CanDuplicateTabAt(devtools_browser, 0));
+ EXPECT_FALSE(chrome::CanDuplicateKeyboardFocusedTab(devtools_browser));
+ EXPECT_EQ(chrome::DuplicateTabAt(devtools_browser, 0), nullptr);
}
namespace {
Loading diff…
Original Bug Report
The reporter's bug is still restricted on the tracker. Chrome de-restricts security bugs ~30–90 days after the fix ships; a later run will backfill it here.
References
On This Page