Low chrome Logic Error 🔧 Commit mapped

Overview

Low
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInappropriate implementation in Sharing
DescriptionInappropriate implementation in Sharing
ComponentSharing
Bug ClassLogic Error
Tracker496271098
Fix commitd13b70bd2635 (chromium/src) +142/-51
CISA KEVNot listed
CreditedGoogle
Disclosed2026-07-29

Files Changed

  • chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_controller_browsertest.cc
  • chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_controller_interactive_uitest.cc
From d13b70bd2635d5461953800cae7b6dc721348d90 Mon Sep 17 00:00:00 2001
From: Mikel Astiz <mastiz@chromium.org>
Date: Tue, 09 Jun 2026 09:53:20 -0700
Subject: [PATCH] [STTS] Ignore unexpected URLs received via Sync

This patch unifies the URL filtering used during sending (or entrypoint
display logic) with the filtering used when processing incoming tabs
received from other devices.

Fixed: 496271098
Change-Id: I620483ec7a6de06342699d900140c1f88855519e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7899698
Reviewed-by: Ankush Singh <ankushkush@google.com>
Commit-Queue: Mikel Astiz <mastiz@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1644054}
---

diff --git a/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_controller_browsertest.cc b/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_controller_browsertest.cc
index 8618e3b..8dfc905 100644
--- a/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_controller_browsertest.cc
+++ b/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_controller_browsertest.cc
@@ -120,6 +120,11 @@
         }));
   }
 
+  void SetUpOnMainThread() override {
+    SigninBrowserTestBase::SetUpOnMainThread();
+    ASSERT_TRUE(embedded_test_server()->Start());
+  }
+
   void ExpectToastShown(ToastId expected_id,
                         int message_id,
                         const std::u16string& replacement = u"",
@@ -155,6 +160,10 @@
   }
 
  protected:
+  GURL empty_url() const {
+    return embedded_test_server()->GetURL("/empty.html");
+  }
+
   base::CallbackListSubscription create_services_subscription_;
 };
 
@@ -171,7 +180,7 @@
 
 IN_PROC_BROWSER_TEST_F(SendTabToSelfPostSendToastBrowserTest,
                        BubbleShowsToast_Desktop) {
-  GURL test_url("about:blank");
+  GURL test_url = empty_url();
 
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
@@ -204,7 +213,7 @@
 
 IN_PROC_BROWSER_TEST_F(SendTabToSelfPostSendToastBrowserTest,
                        BubbleShowsToast_Phone) {
-  GURL test_url("about:blank");
+  GURL test_url = empty_url();
 
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
@@ -237,7 +246,7 @@
 
 IN_PROC_BROWSER_TEST_F(SendTabToSelfPostSendToastBrowserTest,
                        BubbleShowsToast_Tablet) {
-  GURL test_url("about:blank");
+  GURL test_url = empty_url();
 
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
@@ -269,7 +278,7 @@
 
 IN_PROC_BROWSER_TEST_F(SendTabToSelfPostSendToastBrowserTest,
                        BubbleShowsThrottledToast) {
-  GURL test_url("about:blank");
+  GURL test_url = empty_url();
 
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
@@ -306,8 +315,7 @@
 
 IN_PROC_BROWSER_TEST_F(SendTabToSelfPostSendToastBrowserTest,
                        ContextMenuShowsToast) {
-  GURL test_url(
-      "data:text/html;charset=utf-8,<html><body><p>Test</p></body></html>");
+  GURL test_url = empty_url();
 
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
@@ -339,7 +347,7 @@
 
 IN_PROC_BROWSER_TEST_F(SendTabToSelfPostSendToastBrowserTest,
                        BubbleShowsFailureToast) {
-  GURL test_url("about:blank");
+  GURL test_url = empty_url();
 
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
@@ -378,7 +386,7 @@
 
 IN_PROC_BROWSER_TEST_F(SendTabToSelfPostSendToastDisabledBrowserTest,
                        BubbleShowsFailureNotification) {
-  GURL test_url("about:blank");
+  GURL test_url = empty_url();
 
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
@@ -422,14 +430,10 @@
 
 IN_PROC_BROWSER_TEST_F(SendTabToSelfScrollPositionBrowserTest,
                        ScrollPositionPropagated_HappyPath) {
-  ASSERT_TRUE(embedded_test_server()->Start());
   // Using a page with significant content ensures the renderer can generate
   // a selector for the center of the viewport.
-  GURL test_url(
-      "data:text/html;charset=utf-8,<html><body>"
-      "<p style='text-align: center'>This is some test content "
-      "that is long enough to be selected by the text fragment "
-      "generator.</p></body></html>");
+  GURL test_url =
+      embedded_test_server()->GetURL("/send_tab_to_self/scroll.html");
 
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
@@ -469,7 +473,6 @@
 
 IN_PROC_BROWSER_TEST_F(SendTabToSelfScrollPositionBrowserTest,
                        ScrollPositionPropagated_EmptyPage) {
-  ASSERT_TRUE(embedded_test_server()->Start());
   GURL test_url = embedded_test_server()->GetURL("/empty.html");
 
   content::WebContents* web_contents =
@@ -508,14 +511,8 @@
 
 IN_PROC_BROWSER_TEST_F(SendTabToSelfScrollPositionBrowserTest,
                        ScrollPositionPropagated_ScrolledPage) {
-  // Use a data URL to avoid external dependencies. The page is long enough to
-  // require scrolling.
-  GURL test_url(
-      "data:text/html;charset=utf-8,<html><body>"
-      "<div style='height: 2000px'>Spacer Top</div>"
-      "<p id='text' style='text-align: center'>Some interesting text</p>"
-      "<div style='height: 2000px'>Spacer Bottom</div>"
-      "</body></html>");
+  GURL test_url =
+      embedded_test_server()->GetURL("/send_tab_to_self/scroll.html");
 
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
@@ -525,7 +522,7 @@
   EXPECT_TRUE(content::ExecJs(
       web_contents,
       "new Promise(r => {"
-      "  document.getElementById('text').scrollIntoView("
+      "  document.getElementById('target').scrollIntoView("
       "      {behavior: 'instant', block: 'center', inline: 'center'});"
       "  requestAnimationFrame(() => "
       "    requestAnimationFrame(r)"
@@ -564,10 +561,12 @@
   EXPECT_FALSE(
       observer.last_added_entry()->GetPageContext().scroll_position.IsEmpty());
   // Verify that the generated selector matches the expected text.
-  EXPECT_EQ(observer.last_added_entry()
-                ->GetPageContext()
-                .scroll_position.text_fragment.text_start,
-            "interesting");
+  EXPECT_THAT(
+      observer.last_added_entry()
+          ->GetPageContext()
+          .scroll_position.text_fragment.text_start,
+      testing::AnyOf(testing::HasSubstr("fox"), testing::HasSubstr("jumps"),
+                     testing::HasSubstr("dog")));
 }
 
 #if BUILDFLAG(ENABLE_DICE_SUPPORT)
@@ -575,7 +574,7 @@
                        ShowPromoBubble) {
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
-  ASSERT_TRUE(content::NavigateToURL(web_contents, GURL("about:blank")));
+  ASSERT_TRUE(content::NavigateToURL(web_contents, empty_url()));
 
   StubSendTabToSelfSyncService* sync_service = GetStubSyncService();
   ASSERT_TRUE(sync_service);
@@ -595,7 +594,7 @@
                        PromoBubbleAccept_OpensDiceSignInTab) {
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
-  ASSERT_TRUE(content::NavigateToURL(web_contents, GURL("about:blank")));
+  ASSERT_TRUE(content::NavigateToURL(web_contents, empty_url()));
 
   // Trigger the 'Offer Sign-In' state by overriding the entry point display
   // reason.
diff --git a/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_controller_interactive_uitest.cc b/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_controller_interactive_uitest.cc
index 860c024..ed55d83 100644
--- a/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_controller_interactive_uitest.cc
@@ -67,6 +67,7 @@
     identity_test_env_adaptor_ =
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_controller_browsertest.cc b/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_controller_browsertest.cc
index 8618e3b..8dfc905 100644
--- a/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_controller_browsertest.cc
+++ b/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_controller_browsertest.cc
@@ -120,6 +120,11 @@
         }));
   }
 
+  void SetUpOnMainThread() override {
+    SigninBrowserTestBase::SetUpOnMainThread();
+    ASSERT_TRUE(embedded_test_server()->Start());
+  }
+
   void ExpectToastShown(ToastId expected_id,
                         int message_id,
                         const std::u16string& replacement = u"",
@@ -155,6 +160,10 @@
   }
 
  protected:
+  GURL empty_url() const {
+    return embedded_test_server()->GetURL("/empty.html");
+  }
+
   base::CallbackListSubscription create_services_subscription_;
 };
 
@@ -171,7 +180,7 @@
 
 IN_PROC_BROWSER_TEST_F(SendTabToSelfPostSendToastBrowserTest,
                        BubbleShowsToast_Desktop) {
-  GURL test_url("about:blank");
+  GURL test_url = empty_url();
 
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
@@ -204,7 +213,7 @@
 
 IN_PROC_BROWSER_TEST_F(SendTabToSelfPostSendToastBrowserTest,
                        BubbleShowsToast_Phone) {
-  GURL test_url("about:blank");
+  GURL test_url = empty_url();
 
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
@@ -237,7 +246,7 @@
 
 IN_PROC_BROWSER_TEST_F(SendTabToSelfPostSendToastBrowserTest,
                        BubbleShowsToast_Tablet) {
-  GURL test_url("about:blank");
+  GURL test_url = empty_url();
 
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
@@ -269,7 +278,7 @@
 
 IN_PROC_BROWSER_TEST_F(SendTabToSelfPostSendToastBrowserTest,
                        BubbleShowsThrottledToast) {
-  GURL test_url("about:blank");
+  GURL test_url = empty_url();
 
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
@@ -306,8 +315,7 @@
 
 IN_PROC_BROWSER_TEST_F(SendTabToSelfPostSendToastBrowserTest,
                        ContextMenuShowsToast) {
-  GURL test_url(
-      "data:text/html;charset=utf-8,<html><body><p>Test</p></body></html>");
+  GURL test_url = empty_url();
 
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
@@ -339,7 +347,7 @@
 
 IN_PROC_BROWSER_TEST_F(SendTabToSelfPostSendToastBrowserTest,
                        BubbleShowsFailureToast) {
-  GURL test_url("about:blank");
+  GURL test_url = empty_url();
 
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
@@ -378,7 +386,7 @@
 
 IN_PROC_BROWSER_TEST_F(SendTabToSelfPostSendToastDisabledBrowserTest,
                        BubbleShowsFailureNotification) {
-  GURL test_url("about:blank");
+  GURL test_url = empty_url();
 
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
@@ -422,14 +430,10 @@
 
 IN_PROC_BROWSER_TEST_F(SendTabToSelfScrollPositionBrowserTest,
                        ScrollPositionPropagated_HappyPath) {
-  ASSERT_TRUE(embedded_test_server()->Start());
   // Using a page with significant content ensures the renderer can generate
   // a selector for the center of the viewport.
-  GURL test_url(
-      "data:text/html;charset=utf-8,<html><body>"
-      "<p style='text-align: center'>This is some test content "
-      "that is long enough to be selected by the text fragment "
-      "generator.</p></body></html>");
+  GURL test_url =
+      embedded_test_server()->GetURL("/send_tab_to_self/scroll.html");
 
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
@@ -469,7 +473,6 @@
 
 IN_PROC_BROWSER_TEST_F(SendTabToSelfScrollPositionBrowserTest,
                        ScrollPositionPropagated_EmptyPage) {
-  ASSERT_TRUE(embedded_test_server()->Start());
   GURL test_url = embedded_test_server()->GetURL("/empty.html");
 
   content::WebContents* web_contents =
@@ -508,14 +511,8 @@
 
 IN_PROC_BROWSER_TEST_F(SendTabToSelfScrollPositionBrowserTest,
                        ScrollPositionPropagated_ScrolledPage) {
-  // Use a data URL to avoid external dependencies. The page is long enough to
-  // require scrolling.
-  GURL test_url(
-      "data:text/html;charset=utf-8,<html><body>"
-      "<div style='height: 2000px'>Spacer Top</div>"
-      "<p id='text' style='text-align: center'>Some interesting text</p>"
-      "<div style='height: 2000px'>Spacer Bottom</div>"
-      "</body></html>");
+  GURL test_url =
+      embedded_test_server()->GetURL("/send_tab_to_self/scroll.html");
 
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
@@ -525,7 +522,7 @@
   EXPECT_TRUE(content::ExecJs(
       web_contents,
       "new Promise(r => {"
-      "  document.getElementById('text').scrollIntoView("
+      "  document.getElementById('target').scrollIntoView("
       "      {behavior: 'instant', block: 'center', inline: 'center'});"
       "  requestAnimationFrame(() => "
       "    requestAnimationFrame(r)"
@@ -564,10 +561,12 @@
   EXPECT_FALSE(
       observer.last_added_entry()->GetPageContext().scroll_position.IsEmpty());
   // Verify that the generated selector matches the expected text.
-  EXPECT_EQ(observer.last_added_entry()
-                ->GetPageContext()
-                .scroll_position.text_fragment.text_start,
-            "interesting");
+  EXPECT_THAT(
+      observer.last_added_entry()
+          ->GetPageContext()
+          .scroll_position.text_fragment.text_start,
+      testing::AnyOf(testing::HasSubstr("fox"), testing::HasSubstr("jumps"),
+                     testing::HasSubstr("dog")));
 }
 
 #if BUILDFLAG(ENABLE_DICE_SUPPORT)
@@ -575,7 +574,7 @@
                        ShowPromoBubble) {
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
-  ASSERT_TRUE(content::NavigateToURL(web_contents, GURL("about:blank")));
+  ASSERT_TRUE(content::NavigateToURL(web_contents, empty_url()));
 
   StubSendTabToSelfSyncService* sync_service = GetStubSyncService();
   ASSERT_TRUE(sync_service);
@@ -595,7 +594,7 @@
                        PromoBubbleAccept_OpensDiceSignInTab) {
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
-  ASSERT_TRUE(content::NavigateToURL(web_contents, GURL("about:blank")));
+  ASSERT_TRUE(content::NavigateToURL(web_contents, empty_url()));
 
   // Trigger the 'Offer Sign-In' state by overriding the entry point display
   // reason.
diff --git a/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_controller_interactive_uitest.cc b/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_controller_interactive_uitest.cc
index 860c024..ed55d83 100644
--- a/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_controller_interactive_uitest.cc
@@ -67,6 +67,7 @@
     identity_test_env_adaptor_ =
         std::make_unique<IdentityTestEnvironmentProfileAdaptor>(
             browser()->profile());
+    ASSERT_TRUE(embedded_test_server()->Start());
   }
 
   void OnWillCreateBrowserContextServices(content::BrowserContext* context) {
@@ -125,7 +126,7 @@
 // a success toast after a device is selected.
 IN_PROC_BROWSER_TEST_F(SendTabToSelfInteractiveUiTest,
                        SendTabShowsBubbleAndToast) {
-  const GURL test_url("chrome://flags/");
+  const GURL test_url = embedded_test_server()->GetURL("/empty.html");
   RunTestSequence(
       InstrumentTab(kPrimaryTabId),
       NavigateWebContents(kPrimaryTabId, test_url),
@@ -180,7 +181,7 @@
 
 IN_PROC_BROWSER_TEST_F(SendTabToSelfDeviceSelectionInteractiveUiTest,
                        SendTabShowsBubbleAndToastDeviceSelection) {
-  const GURL test_url("chrome://flags/");
+  const GURL test_url = embedded_test_server()->GetURL("/empty.html");
   RunTestSequence(
       InstrumentTab(kPrimaryTabId),
       NavigateWebContents(kPrimaryTabId, test_url),
@@ -230,7 +231,7 @@
 
 IN_PROC_BROWSER_TEST_F(SendTabToSelfDeviceSelectionInteractiveUiTest,
                        SendTabMultipleDevicesDeviceSelection) {
-  const GURL test_url("chrome://flags/");
+  const GURL test_url = embedded_test_server()->GetURL("/empty.html");
   RunTestSequence(
       InstrumentTab(kPrimaryTabId),
       NavigateWebContents(kPrimaryTabId, test_url),
@@ -296,7 +297,7 @@
 
 IN_PROC_BROWSER_TEST_F(SendTabToSelfDeviceSelectionInteractiveUiTest,
                        CancelClosesBubbleWithoutSending) {
-  const GURL test_url("chrome://flags/");
+  const GURL test_url = embedded_test_server()->GetURL("/empty.html");
   RunTestSequence(
       InstrumentTab(kPrimaryTabId),
       NavigateWebContents(kPrimaryTabId, test_url), Do([this]() {
diff --git a/components/send_tab_to_self/send_tab_to_self_bridge_unittest.cc b/components/send_tab_to_self/send_tab_to_self_bridge_unittest.cc
index ec1ed492..0bfcdef 100644
--- a/components/send_tab_to_self/send_tab_to_self_bridge_unittest.cc
+++ b/components/send_tab_to_self/send_tab_to_self_bridge_unittest.cc
@@ -116,6 +116,16 @@
   return state;
 }
 
+syncer::EntityData CreateEntityData(const std::string& guid,
+                                    const std::string& url) {
+  syncer::EntityData entity_data;
+  sync_pb::SendTabToSelfSpecifics* specifics =
+      entity_data.specifics.mutable_send_tab_to_self();
+  specifics->set_guid(guid);
+  specifics->set_url(url);
+  return entity_data;
+}
+
 class MockSendTabToSelfModelObserver : public SendTabToSelfModelObserver {
  public:
   MOCK_METHOD(void,
@@ -714,6 +724,49 @@
                                          kLocalDeviceCacheGuid, PageContext(),
                                          NavigationHistory(),
                                          mock_callback_fail_3.Get()));
+
+  // Add Entry should fail on invalid schemes.
+  base::MockCallback<base::OnceCallback<void(SendTabToSelfResult)>>
+      mock_callback_fail_scheme_1;
+  EXPECT_CALL(mock_callback_fail_scheme_1,
+              Run(SendTabToSelfResult::kFailureInvalidUrl));
+  EXPECT_EQ(nullptr, bridge()->SendEntry(GURL("chrome://flags"), "d",
+                                         kLocalDeviceCacheGuid, PageContext(),
+                                         NavigationHistory(),
+                                         mock_callback_fail_scheme_1.Get()));
+
+  base::MockCallback<base::OnceCallback<void(SendTabToSelfResult)>>
+      mock_callback_fail_scheme_2;
+  EXPECT_CALL(mock_callback_fail_scheme_2,
+              Run(SendTabToSelfResult::kFailureInvalidUrl));
+  EXPECT_EQ(nullptr,
+            bridge()->SendEntry(GURL("about:blank"), "d", kLocalDeviceCacheGuid,
+                                PageContext(), NavigationHistory(),
+                                mock_callback_fail_scheme_2.Get()));
+}
+
+TEST_F(SendTabToSelfBridgeTest, IsEntityDataValid) {
+  InitializeBridge();
+
+  // Valid entries.
+  EXPECT_TRUE(bridge()->IsEntityDataValid(
+      CreateEntityData("guid", "http://www.google.com")));
+  EXPECT_TRUE(bridge()->IsEntityDataValid(
+      CreateEntityData("guid", "https://www.google.com")));
+
+  // Invalid entries.
+  EXPECT_FALSE(bridge()->IsEntityDataValid(
+      CreateEntityData("", "http://www.google.com")));  // Empty GUID.
+  EXPECT_FALSE(
+      bridge()->IsEntityDataValid(CreateEntityData("guid", "")));  // Empty URL.
+  EXPECT_FALSE(bridge()->IsEntityDataValid(
+      CreateEntityData("guid", "invalid_url")));  // Invalid URL.
+  EXPECT_FALSE(bridge()->IsEntityDataValid(
+      CreateEntityData("guid", "chrome://flags")));  // Invalid scheme.
+  EXPECT_FALSE(bridge()->IsEntityDataValid(
+      CreateEntityData("guid", "about:blank")));  // Invalid scheme.
+  EXPECT_FALSE(bridge()->IsEntityDataValid(CreateEntityData(
+      "guid", "file:///sdcard/test.html")));  // Invalid scheme.
 }
 
 // Tests that the pending commit callback is fired with success when the
diff --git a/components/send_tab_to_self/send_tab_to_self_entry_unittest.cc b/components/send_tab_to_self/send_tab_to_self_entry_unittest.cc
index f843dd0..7182e92 100644
--- a/components/send_tab_to_self/send_tab_to_self_entry_unittest.cc
+++ b/components/send_tab_to_self/send_tab_to_self_entry_unittest.cc
... (truncated)
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.