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 <aixba@chromium.org>
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 <dmurph@chromium.org>
Reviewed-by: Eshwar Stalin <estalin@chromium.org>
Commit-Queue: Adriana Ixba <aixba@chromium.org>
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