Chrome · SplitView
CVE-2026-14072
Logic Error in SplitView
Overview
Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifchrome/browser/webshare/BUILD.gn |
modified | |
IN_PROC_BROWSER_TEST_Fchrome/browser/webshare/share_service_browsertest.cc |
modified |
Files Changed
chrome/browser/webshare/BUILD.gnchrome/browser/webshare/chromeos/sharesheet_client.ccchrome/browser/webshare/mac/sharing_service_operation.mmchrome/browser/webshare/share_service_browsertest.ccchrome/browser/webshare/win/share_operation.cc
Patch
From 38cdd6696fa03e758da8973657d1e1695a33f410 Mon Sep 17 00:00:00 2001 From: Alison Gale <[email protected]> Date: Mon, 11 May 2026 08:51:38 -0700 Subject: [PATCH] [SxS] Prevent sharing via WebShare API from inactive WebContents With Split View, tabs can be visible but inactive. So it is possible for an inactive tab in a split to trigger a share dialog which currently renders in a misleading way. This is fixed by just blocking share from inactive tabs on all platforms. Bug: 507099867 Change-Id: I08acac6194083eec33a9578971ab5b2c7d425dcd Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7828287 Reviewed-by: Dibyajyoti Pal <[email protected]> Commit-Queue: Alison Gale <[email protected]> Cr-Commit-Position: refs/heads/main@{#1628602} --- diff --git a/chrome/browser/webshare/BUILD.gn b/chrome/browser/webshare/BUILD.gn index 7b03fda..79b56c0 100644 --- a/chrome/browser/webshare/BUILD.gn +++ b/chrome/browser/webshare/BUILD.gn @@ -143,6 +143,7 @@ "//content/test:test_support", "//net:test_support", "//testing/gtest", + "//ui/base", ] if (is_chromeos) { diff --git a/chrome/browser/webshare/chromeos/sharesheet_client.cc b/chrome/browser/webshare/chromeos/sharesheet_client.cc index 6f03a4ad..2e35bf6 100644 --- a/chrome/browser/webshare/chromeos/sharesheet_client.cc +++ b/chrome/browser/webshare/chromeos/sharesheet_client.cc @@ -30,6 +30,7 @@ #include "components/prefs/pref_service.h" #include "components/services/app_service/public/cpp/intent.h" #include "components/services/app_service/public/cpp/intent_util.h" +#include "components/tabs/public/tab_interface.h" #include "components/visibility_timer/visibility_timer_tab_helper.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" @@ -146,6 +147,14 @@ return; } + // If the tab is no longer active, return permission denied. + tabs::TabInterface* tab_interface = + tabs::TabInterface::MaybeGetFromContents(web_contents()); + if (tab_interface && !tab_interface->IsActivated()) { + std::move(callback).Run(blink::mojom::ShareError::PERMISSION_DENIED); + return; + } + current_share_ = CurrentShare(); current_share_->files = std::move(files); current_share_->directory = diff --git a/chrome/browser/webshare/mac/sharing_service_operation.mm b/chrome/browser/webshare/mac/sharing_service_operation.mm index 9325106e..3e90569d 100644 --- a/chrome/browser/webshare/mac/sharing_service_operation.mm +++ b/chrome/browser/webshare/mac/sharing_service_operation.mm @@ -21,6 +21,7 @@ #include "chrome/browser/webshare/prepare_subdirectory_task.h" #include "chrome/browser/webshare/share_service_impl.h" #include "chrome/browser/webshare/store_files_task.h" +#include "components/tabs/public/tab_interface.h" #include "components/visibility_timer/visibility_timer_tab_helper.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/render_widget_host_view.h" @@ -89,6 +90,14 @@ return; } + // If the tab is no longer active, return permission denied. + tabs::TabInterface* tab_interface = + tabs::TabInterface::MaybeGetFromContents(web_contents_.get()); + if (tab_interface && !tab_interface->IsActivated()) { + std::move(callback_).Run(blink::mojom::ShareError::PERMISSION_DENIED); + return; + } + if (shared_files_.size() == 0) { GetSharePickerCallback().Run( web_contents_.get(), file_paths_, text_, title_, url_, diff --git a/chrome/browser/webshare/share_service_browsertest.cc b/chrome/browser/webshare/share_service_browsertest.cc index 1262ff5a..2af6b04 100644 --- a/chrome/browser/webshare/share_service_browsertest.cc +++ b/chrome/browser/webshare/share_service_browsertest.cc @@ -7,12 +7,16 @@ #include "build/chromeos_buildflags.h" #include "chrome/browser/safe_browsing/test_safe_browsing_service.h" #include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_commands.h" +#include "chrome/browser/ui/tabs/split_tab_metrics.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/webshare/share_service_impl.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" #include "components/safe_browsing/content/common/file_type_policies_test_util.h" #include "components/safe_browsing/core/browser/db/fake_database_manager.h" +#include "components/tabs/public/tab_interface.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_frame_host.h" #include "content/public/test/browser_test.h" @@ -101,6 +105,31 @@ WebShareMethod::kShare, kRepeats); } +IN_PROC_BROWSER_TEST_F(ShareServiceBrowserTest, InactiveWebContents) { + ASSERT_TRUE(embedded_test_server()->Start()); + ASSERT_TRUE(ui_test_utils::NavigateToURL( + browser(), embedded_test_server()->GetURL("/webshare/index.html"))); + content::WebContents* contents_0 = + browser()->tab_strip_model()->GetActiveWebContents(); + + // Create a split and verify there are now 2 tabs + chrome::NewSplitTab(browser(), + split_tabs::SplitTabCreatedSource::kToolbarButton); + ASSERT_EQ(2, browser()->tab_strip_model()->count()); + EXPECT_TRUE(browser()->tab_strip_model()->GetTabAtIndex(0)->IsSplit()); + EXPECT_TRUE(browser()->tab_strip_model()->GetTabAtIndex(1)->IsSplit()); + + // Tab 0 is now inactive. + tabs::TabInterface* tab_0 = tabs::TabInterface::GetFromContents(contents_0); + EXPECT_FALSE(tab_0->IsActivated()); + + // Initiate share from tab 0. Permission in denied because it's inactive. + std::string result = + content::EvalJs(contents_0, "share_text('hello')").ExtractString(); + EXPECT_THAT(result, testing::HasSubstr("share failed")); + EXPECT_THAT(result, testing::HasSubstr("NotAllowedError")); +} + #if BUILDFLAG(IS_WIN) IN_PROC_BROWSER_TEST_F(ShareServiceBrowserTest, Fullscreen) { base::HistogramTester histogram_tester; diff --git a/chrome/browser/webshare/win/share_operation.cc b/chrome/browser/webshare/win/share_operation.cc index 1eeb3cf..6769897 100644 --- a/chrome/browser/webshare/win/share_operation.cc +++ b/chrome/browser/webshare/win/share_operation.cc @@ -26,6 +26,7 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/webshare/share_service_impl.h" #include "chrome/browser/webshare/win/show_share_ui_for_window_operation.h" +#include "components/tabs/public/tab_interface.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/web_contents.h" @@ -386,6 +387,14 @@ return; } + // If the tab is no longer active, return permission denied. + tabs::TabInterface* tab_interface = + tabs::TabInterface::MaybeGetFromContents(web_contents_.get()); + if (tab_interface && !tab_interface->IsActivated()) { + Complete(blink::mojom::ShareError::PERMISSION_DENIED); + return; + } + if (files.size() > 0) { // Determine the source for use with the OS IAttachmentExecute. // If the source cannot be determined, does not appear to be valid,
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/chrome/browser/webshare/share_service_browsertest.cc b/chrome/browser/webshare/share_service_browsertest.cc
index 1262ff5a..2af6b04 100644
--- a/chrome/browser/webshare/share_service_browsertest.cc
+++ b/chrome/browser/webshare/share_service_browsertest.cc
@@ -7,12 +7,16 @@
#include "build/chromeos_buildflags.h"
#include "chrome/browser/safe_browsing/test_safe_browsing_service.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/tabs/split_tab_metrics.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/webshare/share_service_impl.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/safe_browsing/content/common/file_type_policies_test_util.h"
#include "components/safe_browsing/core/browser/db/fake_database_manager.h"
+#include "components/tabs/public/tab_interface.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/test/browser_test.h"
@@ -101,6 +105,31 @@
WebShareMethod::kShare, kRepeats);
}
+IN_PROC_BROWSER_TEST_F(ShareServiceBrowserTest, InactiveWebContents) {
+ ASSERT_TRUE(embedded_test_server()->Start());
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(
+ browser(), embedded_test_server()->GetURL("/webshare/index.html")));
+ content::WebContents* contents_0 =
+ browser()->tab_strip_model()->GetActiveWebContents();
+
+ // Create a split and verify there are now 2 tabs
+ chrome::NewSplitTab(browser(),
+ split_tabs::SplitTabCreatedSource::kToolbarButton);
+ ASSERT_EQ(2, browser()->tab_strip_model()->count());
+ EXPECT_TRUE(browser()->tab_strip_model()->GetTabAtIndex(0)->IsSplit());
+ EXPECT_TRUE(browser()->tab_strip_model()->GetTabAtIndex(1)->IsSplit());
+
+ // Tab 0 is now inactive.
+ tabs::TabInterface* tab_0 = tabs::TabInterface::GetFromContents(contents_0);
+ EXPECT_FALSE(tab_0->IsActivated());
+
+ // Initiate share from tab 0. Permission in denied because it's inactive.
+ std::string result =
+ content::EvalJs(contents_0, "share_text('hello')").ExtractString();
+ EXPECT_THAT(result, testing::HasSubstr("share failed"));
+ EXPECT_THAT(result, testing::HasSubstr("NotAllowedError"));
+}
+
#if BUILDFLAG(IS_WIN)
IN_PROC_BROWSER_TEST_F(ShareServiceBrowserTest, Fullscreen) {
base::HistogramTester histogram_tester;
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