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 <agale@chromium.org>
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 <dibyapal@chromium.org>
Commit-Queue: Alison Gale <agale@chromium.org>
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