Low chrome Memory Corruption 🔧 Commit mapped

Overview

Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactMemory corruption in Google Lens
DescriptionMemory corruption in Google Lens
ComponentGoogle Lens
Sub-componentLens
Bug ClassMemory Corruption
Tracker563183231
Fix commit1a4e43dc5b30 (chromium/src) +172/-2
CISA KEVNot listed
CreditedGoogle
Disclosed2026-10-20

Changed Functions

FunctionChangeNotes
FakeLensQueryFlowRouter
chrome/browser/ui/lens/test_lens_search_controller.h
modified

Files Changed

  • chrome/browser/ui/lens/test_lens_search_controller.h
  • chrome/browser/ui/lens/lens_search_controller.h
  • chrome/browser/ui/lens/lens_query_flow_router.cc
  • chrome/browser/ui/lens/lens_query_flow_router_unittest.cc
  • chrome/browser/ui/lens/test_lens_search_controller.cc
From 1a4e43dc5b30459616d022ef6ec4dd1756958148 Mon Sep 17 00:00:00 2001
From: Jason Hu <hujasonx@google.com>
Date: Mon, 21 Sep 2026 12:59:52 -0700
Subject: [PATCH] [lens] Gate contextual-tasks force-tabs on permissions and origin

In LensQueryFlowRouter::SendInteractionToContextualTasks, force-tabs
contextualization for AIM queries was previously triggered whenever
overlay_tab_context_file_token_ was unset without checking whether the
user had granted Lens permissions, whether full page context was
allowed (region-only mode), or whether the active tab had navigated
cross-origin.

This CL gates the force-tabs block on ShouldPopulateFullPageContext()
and LensSearchController::IsCurrentTabSameOrigin() to prevent
unauthorized tab capture and upload.

Bug: b:563183231
Change-Id: Ie89a5742bd147a7b5537cc8d2fb920cecfaa50a1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8436197
Reviewed-by: Juan Mojica <juanmojica@google.com>
Commit-Queue: Jason Hu <hujasonx@google.com>
Cr-Commit-Position: refs/heads/main@{#1701988}
---
diff --git a/chrome/browser/ui/lens/lens_query_flow_router.cc b/chrome/browser/ui/lens/lens_query_flow_router.cc
index 08b023cf..d7286626 100644
--- a/chrome/browser/ui/lens/lens_query_flow_router.cc
+++ b/chrome/browser/ui/lens/lens_query_flow_router.cc
@@ -784,7 +784,9 @@
     if (!overlay_tab_context_file_token_.has_value() &&
         ShouldFetchActiveTabForInvocationSource(
             pending_search_url_request_->invocation_source,
-            GetContextualSearchSessionHandle())) {
+            GetContextualSearchSessionHandle()) &&
+        ShouldPopulateFullPageContext() &&
+        lens_search_controller_->IsCurrentTabSameOrigin()) {
       force_tabs.push_back(tab_interface()->GetHandle().raw_value());
     }
     contextual_tasks::QueryContextualizer::ContextualizeParams params;
diff --git a/chrome/browser/ui/lens/lens_search_controller.h b/chrome/browser/ui/lens/lens_search_controller.h
index 8b561e71..75f9a9d3 100644
--- a/chrome/browser/ui/lens/lens_search_controller.h
+++ b/chrome/browser/ui/lens/lens_search_controller.h
@@ -285,7 +285,7 @@
 
   // Returns whether the current tab's committed origin matches the origin
   // of the page when this Lens session was initiated.
-  bool IsCurrentTabSameOrigin() const;
+  virtual bool IsCurrentTabSameOrigin() const;
 
   // Returns the origin of the page when this Lens session was initiated.
   const url::Origin& session_origin() const { return session_origin_; }
diff --git a/chrome/browser/ui/lens/test_lens_search_controller.cc b/chrome/browser/ui/lens/test_lens_search_controller.cc
index d981ac2b8..a0c67a2 100644
--- a/chrome/browser/ui/lens/test_lens_search_controller.cc
+++ b/chrome/browser/ui/lens/test_lens_search_controller.cc
@@ -97,6 +97,7 @@
       .WillByDefault([this](lens::LensOverlayDismissalSource dismissal_source) {
         LensSearchController::CloseLensSync(dismissal_source);
       });
+  ON_CALL(*this, IsCurrentTabSameOrigin()).WillByDefault(testing::Return(true));
 }
 
 MockLensSearchController::~MockLensSearchController() = default;
diff --git a/chrome/browser/ui/lens/test_lens_search_controller.h b/chrome/browser/ui/lens/test_lens_search_controller.h
index f8c77a1..5fd4204c 100644
--- a/chrome/browser/ui/lens/test_lens_search_controller.h
+++ b/chrome/browser/ui/lens/test_lens_search_controller.h
@@ -62,6 +62,8 @@
               HandleInteractionResponse,
               (lens::mojom::TextPtr text),
               (override));
+
+  MOCK_METHOD(bool, IsCurrentTabSameOrigin, (), (const, override));
 };
 
 class FakeLensQueryFlowRouter : public LensQueryFlowRouter {
diff --git a/chrome/browser/ui/lens/lens_query_flow_router_unittest.cc b/chrome/browser/ui/lens/lens_query_flow_router_unittest.cc
index eb9bf4d..b7ac007 100644
--- a/chrome/browser/ui/lens/lens_query_flow_router_unittest.cc
+++ b/chrome/browser/ui/lens/lens_query_flow_router_unittest.cc
@@ -2993,6 +2993,7 @@
 TEST_F(
     LensQueryFlowRouterContextualTaskEnabledTest,
     SendContextualTextQuery_WithoutExistingToken_PassesActiveTabToForceTabs) {
+  lens::GrantLensOverlayNeededPermissions(profile_.get());
   auto mock_service = std::make_unique<
       testing::NiceMock<contextual_tasks::MockContextualTasksService>>();
   // FakeQueryContextualizerDelegate must outlive router.
@@ -3072,6 +3073,169 @@
 
 TEST_F(
     LensQueryFlowRouterContextualTaskEnabledTest,
+    SendContextualTextQuery_WithoutPermissions_DoesNotForceTabContextualization) {
+  // Do not grant permissions. Full page context should not be populated.
+  profile_->GetPrefs()->SetBoolean(lens::prefs::kLensSharingPageContentEnabled,
+                                   false);
+  auto mock_service = std::make_unique<
+      testing::NiceMock<contextual_tasks::MockContextualTasksService>>();
+  // FakeQueryContextualizerDelegate must outlive router.
+  auto fake_delegate = std::make_unique<FakeQueryContextualizerDelegate>();
+
+  TestLensQueryFlowRouter router(mock_lens_search_controller_.get(),
+                                 mock_context_controller_.get(),
+                                 profile_.get());
+  router.SetTabContextualizationController(
+      mock_tab_contextualization_controller_.get());
+
+  auto mock_query_contextualizer = std::make_unique<MockQueryContextualizer>(
+      mock_service.get(), fake_delegate.get());
+  auto* mock_contextualizer_ptr = mock_query_contextualizer.get();
+  ON_CALL(*mock_contextualizer_ptr,
+          MockContextualizeWithCallbacks(_, _, _, _, _, _))
+      .WillByDefault(
+          [](const std::optional<base::Uuid>& task_id,
+             const std::string& query_text,
+             const std::vector<contextual_tasks::QueryContextualizer::TabId>&
+                 tabs_to_recontextualize,
+             const std::vector<contextual_tasks::QueryContextualizer::TabId>&
+                 tabs_to_force_contextualize,
+             contextual_tasks::QueryContextualizer::TabProcessedCallback&
+                 on_processed_callback,
+             contextual_tasks::QueryContextualizer::ContextualizedCallback
+                 callback) { std::move(callback).Run(nullptr); });
+  router.SetQueryContextualizerForTesting(std::move(mock_query_contextualizer));
+
+  base::Time query_start_time = base::Time::Now();
+  std::string query_text = "test query";
+  lens::LensOverlaySelectionType selection_type =
+      lens::LensOverlaySelectionType::MULTIMODAL_SUGGEST_TYPEAHEAD;
+  std::map<std::string, std::string> additional_params;
+
+  EXPECT_CALL(*mock_contextualizer_ptr,
+              MockContextualize(testing::Eq(std::nullopt), query_text,
+                                testing::IsEmpty(), testing::_))
+      .WillOnce(
+          [](const std::optional<base::Uuid>& task_id,
+             const std::string& query_text,
+             const std::vector<contextual_tasks::QueryContextualizer::TabId>&
+                 tabs_to_recontextualize,
+             const std::vector<contextual_tasks::QueryContextualizer::TabId>&
+                 tabs_to_force_contextualize) {
+            EXPECT_THAT(tabs_to_force_contextualize, testing::IsEmpty());
+          });
+
+  EXPECT_CALL(*router.mock_session_handle(), CreateSearchUrl(_, _))
+      .WillOnce(base::test::RunOnceCallback<1>(
+          GURL("https://www.google.com/search?q=test")));
+
+  auto* service = static_cast<MockContextualTasksUiService*>(
+      contextual_tasks::ContextualTasksUiServiceFactory::GetForBrowserContext(
+          profile_.get()));
+
+  EXPECT_CALL(*service,
+              StartTaskUiInSidePanelImpl(
+                  mock_browser_window_interface_.get(), &mock_tab_interface_,
+                  GURL("https://www.google.com/search?q=test"),
+                  testing::Pointer(router.mock_session_handle()), testing::_))
+      .WillOnce(
+          [&router](
+              BrowserWindowInterface*, tabs::TabInterface*, const GURL&,
+              std::unique_ptr<contextual_search::ContextualSearchSessionHandle>
+                  handle,
+              contextual_tasks::StartTaskUiOptions options) {
+            router.SetTransferredSessionHandle(std::move(handle));
+          });
+
+  router.SendContextualTextQuery(query_start_time, query_text, selection_type,
+                                 additional_params,
+                                 lens::LensOverlayInvocationSource::kAppMenu);
+}
+
+TEST_F(
+    LensQueryFlowRouterContextualTaskEnabledTest,
+    SendContextualTextQuery_CrossOriginTab_DoesNotForceTabContextualization) {
+  lens::GrantLensOverlayNeededPermissions(profile_.get());
+  EXPECT_CALL(*mock_lens_search_controller_, IsCurrentTabSameOrigin())
+      .WillRepeatedly(Return(false));
+
+  auto mock_service = std::make_unique<
+      testing::NiceMock<contextual_tasks::MockContextualTasksService>>();
+  // FakeQueryContextualizerDelegate must outlive router.
+  auto fake_delegate = std::make_unique<FakeQueryContextualizerDelegate>();
+
+  TestLensQueryFlowRouter router(mock_lens_search_controller_.get(),
+                                 mock_context_controller_.get(),
+                                 profile_.get());
+  router.SetTabContextualizationController(
+      mock_tab_contextualization_controller_.get());
+
+  auto mock_query_contextualizer = std::make_unique<MockQueryContextualizer>(
+      mock_service.get(), fake_delegate.get());
+  auto* mock_contextualizer_ptr = mock_query_contextualizer.get();
+  ON_CALL(*mock_contextualizer_ptr,
+          MockContextualizeWithCallbacks(_, _, _, _, _, _))
+      .WillByDefault(
+          [](const std::optional<base::Uuid>& task_id,
+             const std::string& query_text,
+             const std::vector<contextual_tasks::QueryContextualizer::TabId>&
+                 tabs_to_recontextualize,
+             const std::vector<contextual_tasks::QueryContextualizer::TabId>&
+                 tabs_to_force_contextualize,
+             contextual_tasks::QueryContextualizer::TabProcessedCallback&
+                 on_processed_callback,
+             contextual_tasks::QueryContextualizer::ContextualizedCallback
+                 callback) { std::move(callback).Run(nullptr); });
+  router.SetQueryContextualizerForTesting(std::move(mock_query_contextualizer));
+
+  base::Time query_start_time = base::Time::Now();
+  std::string query_text = "test query";
+  lens::LensOverlaySelectionType selection_type =
+      lens::LensOverlaySelectionType::MULTIMODAL_SUGGEST_TYPEAHEAD;
+  std::map<std::string, std::string> additional_params;
+
+  EXPECT_CALL(*mock_contextualizer_ptr,
+              MockContextualize(testing::Eq(std::nullopt), query_text,
+                                testing::IsEmpty(), testing::_))
+      .WillOnce(
+          [](const std::optional<base::Uuid>& task_id,
+             const std::string& query_text,
+             const std::vector<contextual_tasks::QueryContextualizer::TabId>&
+                 tabs_to_recontextualize,
+             const std::vector<contextual_tasks::QueryContextualizer::TabId>&
+                 tabs_to_force_contextualize) {
+            EXPECT_THAT(tabs_to_force_contextualize, testing::IsEmpty());
+          });
+
+  EXPECT_CALL(*router.mock_session_handle(), CreateSearchUrl(_, _))
+      .WillOnce(base::test::RunOnceCallback<1>(
+          GURL("https://www.google.com/search?q=test")));
+
+  auto* service = static_cast<MockContextualTasksUiService*>(
+      contextual_tasks::ContextualTasksUiServiceFactory::GetForBrowserContext(
+          profile_.get()));
+
+  EXPECT_CALL(*service,
+              StartTaskUiInSidePanelImpl(
+                  mock_browser_window_interface_.get(), &mock_tab_interface_,
+                  GURL("https://www.google.com/search?q=test"),
+                  testing::Pointer(router.mock_session_handle()), testing::_))
+      .WillOnce(
+          [&router](
+              BrowserWindowInterface*, tabs::TabInterface*, const GURL&,
+              std::unique_ptr<contextual_search::ContextualSearchSessionHandle>
+                  handle,
+              contextual_tasks::StartTaskUiOptions options) {
+            router.SetTransferredSessionHandle(std::move(handle));
+          });
+
+  router.SendContextualTextQuery(query_start_time, query_text, selection_type,
+                                 additional_params,
+                                 lens::LensOverlayInvocationSource::kAppMenu);
+}
+
+TEST_F(
+    LensQueryFlowRouterContextualTaskEnabledTest,
     SendContextualTextQuery_OmniboxContextualQuery_WithoutExistingToken_DoesNotForceTabContextualization) {
   auto mock_service = std::make_unique<
       testing::NiceMock<contextual_tasks::MockContextualTasksService>>();
@@ -3155,6 +3319,7 @@
 TEST_F(
     LensQueryFlowRouterContextualTaskEnabledTest,
     SendContextualTextQuery_OmniboxContextualSuggestion_WithoutExistingToken_ForcesTabContextualization) {
+  lens::GrantLensOverlayNeededPermissions(profile_.get());
   auto mock_service = std::make_unique<
       testing::NiceMock<contextual_tasks::MockContextualTasksService>>();
   // FakeQueryContextualizerDelegate must outlive router.
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/chrome/browser/ui/lens/lens_query_flow_router_unittest.cc b/chrome/browser/ui/lens/lens_query_flow_router_unittest.cc
index eb9bf4d..b7ac007 100644
--- a/chrome/browser/ui/lens/lens_query_flow_router_unittest.cc
+++ b/chrome/browser/ui/lens/lens_query_flow_router_unittest.cc
@@ -2993,6 +2993,7 @@
 TEST_F(
     LensQueryFlowRouterContextualTaskEnabledTest,
     SendContextualTextQuery_WithoutExistingToken_PassesActiveTabToForceTabs) {
+  lens::GrantLensOverlayNeededPermissions(profile_.get());
   auto mock_service = std::make_unique<
       testing::NiceMock<contextual_tasks::MockContextualTasksService>>();
   // FakeQueryContextualizerDelegate must outlive router.
@@ -3072,6 +3073,169 @@
 
 TEST_F(
     LensQueryFlowRouterContextualTaskEnabledTest,
+    SendContextualTextQuery_WithoutPermissions_DoesNotForceTabContextualization) {
+  // Do not grant permissions. Full page context should not be populated.
+  profile_->GetPrefs()->SetBoolean(lens::prefs::kLensSharingPageContentEnabled,
+                                   false);
+  auto mock_service = std::make_unique<
+      testing::NiceMock<contextual_tasks::MockContextualTasksService>>();
+  // FakeQueryContextualizerDelegate must outlive router.
+  auto fake_delegate = std::make_unique<FakeQueryContextualizerDelegate>();
+
+  TestLensQueryFlowRouter router(mock_lens_search_controller_.get(),
+                                 mock_context_controller_.get(),
+                                 profile_.get());
+  router.SetTabContextualizationController(
+      mock_tab_contextualization_controller_.get());
+
+  auto mock_query_contextualizer = std::make_unique<MockQueryContextualizer>(
+      mock_service.get(), fake_delegate.get());
+  auto* mock_contextualizer_ptr = mock_query_contextualizer.get();
+  ON_CALL(*mock_contextualizer_ptr,
+          MockContextualizeWithCallbacks(_, _, _, _, _, _))
+      .WillByDefault(
+          [](const std::optional<base::Uuid>& task_id,
+             const std::string& query_text,
+             const std::vector<contextual_tasks::QueryContextualizer::TabId>&
+                 tabs_to_recontextualize,
+             const std::vector<contextual_tasks::QueryContextualizer::TabId>&
+                 tabs_to_force_contextualize,
+             contextual_tasks::QueryContextualizer::TabProcessedCallback&
+                 on_processed_callback,
+             contextual_tasks::QueryContextualizer::ContextualizedCallback
+                 callback) { std::move(callback).Run(nullptr); });
+  router.SetQueryContextualizerForTesting(std::move(mock_query_contextualizer));
+
+  base::Time query_start_time = base::Time::Now();
+  std::string query_text = "test query";
+  lens::LensOverlaySelectionType selection_type =
+      lens::LensOverlaySelectionType::MULTIMODAL_SUGGEST_TYPEAHEAD;
+  std::map<std::string, std::string> additional_params;
+
+  EXPECT_CALL(*mock_contextualizer_ptr,
+              MockContextualize(testing::Eq(std::nullopt), query_text,
+                                testing::IsEmpty(), testing::_))
+      .WillOnce(
+          [](const std::optional<base::Uuid>& task_id,
+             const std::string& query_text,
+             const std::vector<contextual_tasks::QueryContextualizer::TabId>&
+                 tabs_to_recontextualize,
+             const std::vector<contextual_tasks::QueryContextualizer::TabId>&
+                 tabs_to_force_contextualize) {
+            EXPECT_THAT(tabs_to_force_contextualize, testing::IsEmpty());
+          });
+
+  EXPECT_CALL(*router.mock_session_handle(), CreateSearchUrl(_, _))
+      .WillOnce(base::test::RunOnceCallback<1>(
+          GURL("https://www.google.com/search?q=test")));
+
+  auto* service = static_cast<MockContextualTasksUiService*>(
+      contextual_tasks::ContextualTasksUiServiceFactory::GetForBrowserContext(
+          profile_.get()));
+
+  EXPECT_CALL(*service,
+              StartTaskUiInSidePanelImpl(
+                  mock_browser_window_interface_.get(), &mock_tab_interface_,
+                  GURL("https://www.google.com/search?q=test"),
+                  testing::Pointer(router.mock_session_handle()), testing::_))
+      .WillOnce(
+          [&router](
+              BrowserWindowInterface*, tabs::TabInterface*, const GURL&,
+              std::unique_ptr<contextual_search::ContextualSearchSessionHandle>
+                  handle,
+              contextual_tasks::StartTaskUiOptions options) {
+            router.SetTransferredSessionHandle(std::move(handle));
+          });
+
+  router.SendContextualTextQuery(query_start_time, query_text, selection_type,
+                                 additional_params,
+                                 lens::LensOverlayInvocationSource::kAppMenu);
+}
+
+TEST_F(
+    LensQueryFlowRouterContextualTaskEnabledTest,
+    SendContextualTextQuery_CrossOriginTab_DoesNotForceTabContextualization) {
+  lens::GrantLensOverlayNeededPermissions(profile_.get());
+  EXPECT_CALL(*mock_lens_search_controller_, IsCurrentTabSameOrigin())
+      .WillRepeatedly(Return(false));
+
+  auto mock_service = std::make_unique<
+      testing::NiceMock<contextual_tasks::MockContextualTasksService>>();
+  // FakeQueryContextualizerDelegate must outlive router.
+  auto fake_delegate = std::make_unique<FakeQueryContextualizerDelegate>();
+
+  TestLensQueryFlowRouter router(mock_lens_search_controller_.get(),
+                                 mock_context_controller_.get(),
+                                 profile_.get());
+  router.SetTabContextualizationController(
+      mock_tab_contextualization_controller_.get());
+
+  auto mock_query_contextualizer = std::make_unique<MockQueryContextualizer>(
+      mock_service.get(), fake_delegate.get());
+  auto* mock_contextualizer_ptr = mock_query_contextualizer.get();
+  ON_CALL(*mock_contextualizer_ptr,
+          MockContextualizeWithCallbacks(_, _, _, _, _, _))
+      .WillByDefault(
+          [](const std::optional<base::Uuid>& task_id,
+             const std::string& query_text,
+             const std::vector<contextual_tasks::QueryContextualizer::TabId>&
+                 tabs_to_recontextualize,
+             const std::vector<contextual_tasks::QueryContextualizer::TabId>&
+                 tabs_to_force_contextualize,
+             contextual_tasks::QueryContextualizer::TabProcessedCallback&
+                 on_processed_callback,
+             contextual_tasks::QueryContextualizer::ContextualizedCallback
+                 callback) { std::move(callback).Run(nullptr); });
+  router.SetQueryContextualizerForTesting(std::move(mock_query_contextualizer));
+
+  base::Time query_start_time = base::Time::Now();
+  std::string query_text = "test query";
+  lens::LensOverlaySelectionType selection_type =
+      lens::LensOverlaySelectionType::MULTIMODAL_SUGGEST_TYPEAHEAD;
+  std::map<std::string, std::string> additional_params;
+
+  EXPECT_CALL(*mock_contextualizer_ptr,
+              MockContextualize(testing::Eq(std::nullopt), query_text,
+                                testing::IsEmpty(), testing::_))
+      .WillOnce(
+          [](const std::optional<base::Uuid>& task_id,
+             const std::string& query_text,
+             const std::vector<contextual_tasks::QueryContextualizer::TabId>&
+                 tabs_to_recontextualize,
+             const std::vector<contextual_tasks::QueryContextualizer::TabId>&
+                 tabs_to_force_contextualize) {
+            EXPECT_THAT(tabs_to_force_contextualize, testing::IsEmpty());
+          });
+
+  EXPECT_CALL(*router.mock_session_handle(), CreateSearchUrl(_, _))
+      .WillOnce(base::test::RunOnceCallback<1>(
+          GURL("https://www.google.com/search?q=test")));
+
+  auto* service = static_cast<MockContextualTasksUiService*>(
+      contextual_tasks::ContextualTasksUiServiceFactory::GetForBrowserContext(
+          profile_.get()));
+
+  EXPECT_CALL(*service,
+              StartTaskUiInSidePanelImpl(
+                  mock_browser_window_interface_.get(), &mock_tab_interface_,
+                  GURL("https://www.google.com/search?q=test"),
+                  testing::Pointer(router.mock_session_handle()), testing::_))
+      .WillOnce(
+          [&router](
+              BrowserWindowInterface*, tabs::TabInterface*, const GURL&,
+              std::unique_ptr<contextual_search::ContextualSearchSessionHandle>
+                  handle,
+              contextual_tasks::StartTaskUiOptions options) {
+            router.SetTransferredSessionHandle(std::move(handle));
+          });
+
+  router.SendContextualTextQuery(query_start_time, query_text, selection_type,
+                                 additional_params,
+                                 lens::LensOverlayInvocationSource::kAppMenu);
+}
+
+TEST_F(
+    LensQueryFlowRouterContextualTaskEnabledTest,
     SendContextualTextQuery_OmniboxContextualQuery_WithoutExistingToken_DoesNotForceTabContextualization) {
   auto mock_service = std::make_unique<
       testing::NiceMock<contextual_tasks::MockContextualTasksService>>();
@@ -3155,6 +3319,7 @@
 TEST_F(
     LensQueryFlowRouterContextualTaskEnabledTest,
     SendContextualTextQuery_OmniboxContextualSuggestion_WithoutExistingToken_ForcesTabContextualization) {
+  lens::GrantLensOverlayNeededPermissions(profile_.get());
   auto mock_service = std::make_unique<
       testing::NiceMock<contextual_tasks::MockContextualTasksService>>();
   // FakeQueryContextualizerDelegate must outlive router.
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.