Medium CVSS 6.5 chrome Input Validation 🔧 Commit mapped

Overview

Medium
Severity
6.5
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInsufficient validation of untrusted input in Glic
DescriptionInsufficient validation of untrusted input in Glic
ComponentGlic
Sub-componentGlic
Bug ClassInput Validation
Tracker497604407
Fix commit0906aba512c8 (chromium/src) +187/-13
CWECWE-20 (Improper input validation)
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N
CISA KEVNot listed
CreditedGoogle
Reported2026-03-30 (per vendor advisory)
Fix landed2026-04-15 (public git)
Disclosed2026-06-02
Patch gap48 days — fix public in source before the advisory

Changed Functions

FunctionChangeNotes
Profile
chrome/browser/glic/host/context/glic_tab_data_observer.h
modified
GlicTabDataObserver
chrome/browser/glic/host/context/glic_tab_data_observer.h
modified
Profile
chrome/browser/glic/host/context/glic_tab_favicon_observer.h
modified
GlicTabFaviconObserver
chrome/browser/glic/host/context/glic_tab_favicon_observer.h
modified
if
chrome/browser/glic/host/glic_page_handler.cc
modified

Files Changed

  • chrome/browser/glic/host/context/glic_sharing_manager_impl.cc
  • chrome/browser/glic/host/context/glic_tab_data_observer.cc
  • chrome/browser/glic/host/context/glic_tab_data_observer.h
  • chrome/browser/glic/host/context/glic_tab_favicon_observer.cc
  • chrome/browser/glic/host/context/glic_tab_favicon_observer.h
  • chrome/browser/glic/host/glic_page_handler.cc
  • chrome/browser/glic/host/new_glic_api_browsertest.cc
From 0906aba512c8f7949f313b725c26db54262bb1d5 Mon Sep 17 00:00:00 2001
From: Dan Harrington <[email protected]>
Date: Wed, 15 Apr 2026 14:24:42 -0700
Subject: [PATCH] glic: check tab profile before returning data

Check that a tab's profile matches the profile using glic before
returning data. Adds regression tests.

Bug: 497604407
Link: https://chromium-review.googlesource.com/id/Ib94e11490b47bf3951e347f914ec8a0e6a6a6964
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7744663
Reviewed-by: Nick Birnie <[email protected]>
Commit-Queue: Dan H <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1615420}
---

diff --git a/chrome/browser/glic/host/context/glic_sharing_manager_impl.cc b/chrome/browser/glic/host/context/glic_sharing_manager_impl.cc
index ead7096..84c2696 100644
--- a/chrome/browser/glic/host/context/glic_sharing_manager_impl.cc
+++ b/chrome/browser/glic/host/context/glic_sharing_manager_impl.cc
@@ -273,7 +273,11 @@
         GlicGetContextFromTabError::kTabNotFound, "tab not found"}));
     return;
   }
-
+  if (tab->GetBrowserWindowInterface()->GetProfile() != profile_) {
+    std::move(callback).Run(base::unexpected(GlicGetContextError{
+        GlicGetContextFromTabError::kPermissionDenied, "profile mismatch"}));
+    return;
+  }
   GetContextFromTabImpl(tab, options, std::move(callback));
 }
 
diff --git a/chrome/browser/glic/host/context/glic_tab_data_observer.cc b/chrome/browser/glic/host/context/glic_tab_data_observer.cc
index f8efdbe..aadd721c 100644
--- a/chrome/browser/glic/host/context/glic_tab_data_observer.cc
+++ b/chrome/browser/glic/host/context/glic_tab_data_observer.cc
@@ -10,6 +10,7 @@
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/glic/common/future_browser_features.h"
 #include "chrome/browser/glic/host/context/glic_tab_data.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser_window/public/browser_window_interface.h"
 #include "components/tabs/public/tab_interface.h"
 #include "content/public/browser/web_contents_observer.h"
@@ -154,7 +155,8 @@
   base::WeakPtrFactory<TabObserver> weak_ptr_factory_{this};
 };
 
-GlicTabDataObserver::GlicTabDataObserver() = default;
+GlicTabDataObserver::GlicTabDataObserver(Profile* profile)
+    : profile_(profile) {}
 GlicTabDataObserver::~GlicTabDataObserver() = default;
 
 void GlicTabDataObserver::OnTabWillClose(tabs::TabHandle tab_handle) {
@@ -170,6 +172,10 @@
     remote.reset();
     return;
   }
+  if (tab->GetBrowserWindowInterface()->GetProfile() != profile_) {
+    remote.reset();
+    return;
+  }
   TabObserver* observer_ptr = nullptr;
   auto iter = observers_.find(handle);
   if (iter != observers_.end()) {
diff --git a/chrome/browser/glic/host/context/glic_tab_data_observer.h b/chrome/browser/glic/host/context/glic_tab_data_observer.h
index 162db323..088f9b4 100644
--- a/chrome/browser/glic/host/context/glic_tab_data_observer.h
+++ b/chrome/browser/glic/host/context/glic_tab_data_observer.h
@@ -7,10 +7,13 @@
 
 #include <map>
 
+#include "base/memory/raw_ptr.h"
 #include "base/timer/timer.h"
 #include "chrome/browser/glic/host/context/glic_tab_data.h"
 #include "components/tabs/public/tab_interface.h"
 
+class Profile;
+
 namespace glic {
 
 // This is a collection of observers each of which observe a tab for changes
@@ -25,7 +28,7 @@
 // API.
 class GlicTabDataObserver {
  public:
-  GlicTabDataObserver();
+  explicit GlicTabDataObserver(Profile* profile);
   ~GlicTabDataObserver();
 
   GlicTabDataObserver(const GlicTabDataObserver&) = delete;
@@ -51,6 +54,7 @@
   std::map<tabs::TabHandle, std::unique_ptr<TabObserver>> observers_;
   std::set<tabs::TabHandle> pending_cleanup_;
   base::OneShotTimer cleanup_timer_;
+  const raw_ptr<Profile> profile_;
 };
 
 }  // namespace glic
diff --git a/chrome/browser/glic/host/context/glic_tab_favicon_observer.cc b/chrome/browser/glic/host/context/glic_tab_favicon_observer.cc
index 65dd922..2d194594 100644
--- a/chrome/browser/glic/host/context/glic_tab_favicon_observer.cc
+++ b/chrome/browser/glic/host/context/glic_tab_favicon_observer.cc
@@ -11,6 +11,8 @@
 #include "chrome/browser/glic/common/future_browser_features.h"
 #include "chrome/browser/glic/host/context/glic_tab_data.h"
 #include "chrome/browser/glic/host/glic.mojom.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser_window/public/browser_window_interface.h"
 #include "chrome/common/chrome_features.h"
 #include "components/favicon/content/content_favicon_driver.h"
 #include "components/favicon/core/favicon_driver_observer.h"
@@ -253,7 +255,8 @@
   base::CallbackListSubscription will_discard_contents_subscription_;
 };
 
-GlicTabFaviconObserver::GlicTabFaviconObserver() = default;
+GlicTabFaviconObserver::GlicTabFaviconObserver(Profile* profile)
+    : profile_(profile) {}
 GlicTabFaviconObserver::~GlicTabFaviconObserver() = default;
 
 void GlicTabFaviconObserver::OnTabWillClose(tabs::TabHandle tab_handle) {
@@ -269,6 +272,10 @@
     remote.reset();
     return;
   }
+  if (tab->GetBrowserWindowInterface()->GetProfile() != profile_) {
+    remote.reset();
+    return;
+  }
   TabObserver* observer_ptr = nullptr;
   auto iter = observers_.find(handle);
   if (iter != observers_.end()) {
diff --git a/chrome/browser/glic/host/context/glic_tab_favicon_observer.h b/chrome/browser/glic/host/context/glic_tab_favicon_observer.h
index 4f2ed82..4598fdf 100644
--- a/chrome/browser/glic/host/context/glic_tab_favicon_observer.h
+++ b/chrome/browser/glic/host/context/glic_tab_favicon_observer.h
@@ -9,6 +9,7 @@
 #include <memory>
 #include <set>
 
+#include "base/memory/raw_ptr.h"
 #include "base/timer/timer.h"
 #include "chrome/browser/glic/host/glic.mojom.h"
 #include "components/tabs/public/tab_interface.h"
@@ -16,13 +17,15 @@
 #include "third_party/abseil-cpp/absl/container/flat_hash_map.h"
 #include "third_party/abseil-cpp/absl/container/flat_hash_set.h"
 
+class Profile;
+
 namespace glic {
 
 // Observers tabs for favicon changes. Plumbs these changes to the provided
 // mojo receiver.
 class GlicTabFaviconObserver {
  public:
-  GlicTabFaviconObserver();
+  explicit GlicTabFaviconObserver(Profile* profile);
   ~GlicTabFaviconObserver();
 
   GlicTabFaviconObserver(const GlicTabFaviconObserver&) = delete;
@@ -47,6 +50,7 @@
   absl::flat_hash_map<tabs::TabHandle, std::unique_ptr<TabObserver>> observers_;
   absl::flat_hash_set<tabs::TabHandle> pending_cleanup_;
   base::OneShotTimer cleanup_timer_;
+  const raw_ptr<Profile> profile_;
 };
 
 }  // namespace glic
diff --git a/chrome/browser/glic/host/glic_page_handler.cc b/chrome/browser/glic/host/glic_page_handler.cc
index 3b8d0c9..62ac2d0 100644
--- a/chrome/browser/glic/host/glic_page_handler.cc
+++ b/chrome/browser/glic/host/glic_page_handler.cc
@@ -744,7 +744,7 @@
         &GlicWebClientHandler::WebClientDisconnected, base::Unretained(this)));
 
     page_metadata_manager_ =
-        std::make_unique<PageMetadataManager>(web_client_.get());
+        std::make_unique<PageMetadataManager>(profile_, web_client_.get());
 
     // Listen for changes to prefs.
     pref_change_registrar_.Init(pref_service_);
@@ -1418,6 +1418,9 @@
     if (!tab) {
       return;
     }
+    if (tab->GetBrowserWindowInterface()->GetProfile() != profile_) {
+      return;
+    }
     glic_service_->DeleteCapturedRegion(tab, id);
 #else
     NOTIMPLEMENTED();
diff --git a/chrome/browser/glic/host/new_glic_api_browsertest.cc b/chrome/browser/glic/host/new_glic_api_browsertest.cc
index a8fec3b1..fc6a9d410 100644
--- a/chrome/browser/glic/host/new_glic_api_browsertest.cc
+++ b/chrome/browser/glic/host/new_glic_api_browsertest.cc
@@ -5,6 +5,7 @@
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/chrome/browser/glic/host/new_glic_api_browsertest.cc b/chrome/browser/glic/host/new_glic_api_browsertest.cc
index a8fec3b1..fc6a9d410 100644
--- a/chrome/browser/glic/host/new_glic_api_browsertest.cc
+++ b/chrome/browser/glic/host/new_glic_api_browsertest.cc
@@ -5,6 +5,7 @@
 #include "base/test/gmock_expected_support.h"
 #include "base/test/scoped_logging_settings.h"
 #include "base/values.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/enterprise/browser_management/management_service_factory.h"
 #include "chrome/browser/glic/host/glic_features.mojom-features.h"
 #include "chrome/browser/glic/host/glic_web_contents_warming_pool.h"
@@ -19,11 +20,15 @@
 #include "chrome/browser/glic/test_support/new_glic_api_test.h"
 #include "chrome/browser/policy/chrome_browser_policy_connector.h"
 #include "chrome/browser/policy/profile_policy_connector.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/profiles/profile_test_util.h"
 #include "chrome/browser/signin/chrome_signin_client_factory.h"
 #include "chrome/browser/signin/chrome_signin_client_test_util.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
 #include "chrome/browser/skills/skills_ui_tab_controller_interface.h"
+#include "chrome/browser/tab_list/tab_list_interface.h"
+#include "chrome/browser/ui/browser_window/public/browser_window_interface.h"
 #include "chrome/browser/ui/browser_window/public/browser_window_interface_iterator.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/webui_url_constants.h"
@@ -40,6 +45,7 @@
 #include "components/signin/public/identity_manager/account_info.h"
 #include "components/skills/features.h"
 #include "components/skills/public/skills_service.h"
+#include "components/tabs/public/tab_interface.h"
 #include "content/public/browser/favicon_status.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_entry.h"
@@ -56,6 +62,10 @@
 #include "chrome/test/base/ui_test_utils.h"
 #endif
 
+#if !BUILDFLAG(IS_ANDROID)
+#include "chrome/browser/ui/browser.h"
+#endif
+
 #if BUILDFLAG(IS_ANDROID)
 #include "base/android/device_info.h"
 #include "chrome/browser/flags/android/chrome_feature_list.h"
@@ -80,6 +90,7 @@
       "NewGlicApiTestWithWebContentsWarming",
       "NewGlicApiTestWithPixelOutput",
       "NewGlicApiTestWithGeminiActOnWebPolicy",
+      "NewGlicApiMultiProfileTest",
 #if !BUILDFLAG(IS_ANDROID)
       "NewGlicApiTestWithSkills",
 #endif
@@ -88,6 +99,10 @@
   return names;
 }
 
+std::string GlicTabId(tabs::TabHandle tab_handle) {
+  return base::NumberToString(tab_handle.raw_value());
+}
+
 }  // namespace
 
 // All tests in this file use the same test params here.
@@ -196,6 +211,22 @@
   base::test::ScopedFeatureList features_;
 };
 
+class NewGlicApiMultiProfileTest : public NewGlicApiTest {
+ public:
+  BrowserWindowInterface* CreateBrowserWithNewProfile() {
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
+    ProfileManager* profile_manager = g_browser_process->profile_manager();
+    base::FilePath new_path =
+        profile_manager->GenerateNextProfileDirectoryPath();
+    Profile& new_profile =
+        profiles::testing::CreateProfileSync(profile_manager, new_path);
+    return CreateBrowser(&new_profile);
+#else
+    NOTREACHED();
+#endif
+  }
+};
+
 class NewGlicApiTestWithWebContentsWarming : public NewGlicApiTest {
  public:
   NewGlicApiTestWithWebContentsWarming() {
@@ -462,6 +493,67 @@
   ExecuteJsTest();
 }
 
+IN_PROC_BROWSER_TEST_P(NewGlicApiMultiProfileTest,
+                       testPageMetadataCrossProfile) {
+#if !BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_WIN) && !BUILDFLAG(IS_MAC)
+  GTEST_SKIP() << "Multi-profile tests only supported on Desktop";
+#endif
+  ASSERT_OK(OpenGlicForActiveTab());
+  BrowserWindowInterface* other_browser = CreateBrowserWithNewProfile();
+  ASSERT_TRUE(other_browser);
+  ASSERT_TRUE(content::NavigateToURL(
+      TabListInterface::From(other_browser)->GetActiveTab()->GetContents(),
+      GetTestUrl("page.html")));
+  auto other_tab_handle =
+      TabListInterface::From(other_browser)->GetTab(0)->GetHandle();
+  ExecuteJsTest({.params = base::Value(GlicTabId(other_tab_handle))});
+}
+
+IN_PROC_BROWSER_TEST_P(NewGlicApiMultiProfileTest, testTabDataCrossProfile) {
+#if !BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_WIN) && !BUILDFLAG(IS_MAC)
+  GTEST_SKIP() << "Multi-profile tests only supported on Desktop";
+#endif
+  ASSERT_OK(OpenGlicForActiveTab());
+  BrowserWindowInterface* other_browser = CreateBrowserWithNewProfile();
+  ASSERT_TRUE(other_browser);
+  ASSERT_TRUE(content::NavigateToURL(
+      TabListInterface::From(other_browser)->GetActiveTab()->GetContents(),
+      GetTestUrl("page.html")));
+  auto other_tab_handle =
+      TabListInterface::From(other_browser)->GetTab(0)->GetHandle();
+  ExecuteJsTest({.params = base::Value(GlicTabId(other_tab_handle))});
+}
+
+IN_PROC_BROWSER_TEST_P(NewGlicApiMultiProfileTest, testTabFaviconCrossProfile) {
+#if !BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_WIN) && !BUILDFLAG(IS_MAC)
+  GTEST_SKIP() << "Multi-profile tests only supported on Desktop";
+#endif
+  ASSERT_OK(OpenGlicForActiveTab());
+  BrowserWindowInterface* other_browser = CreateBrowserWithNewProfile();
+  ASSERT_TRUE(other_browser);
+  ASSERT_TRUE(content::NavigateToURL(
+      TabListInterface::From(other_browser)->GetActiveTab()->GetContents(),
+      GetTestUrl("page.html")));
+  auto other_tab_handle =
+      TabListInterface::From(other_browser)->GetTab(0)->GetHandle();
+  ExecuteJsTest({.params = base::Value(GlicTabId(other_tab_handle))});
+}
+
+IN_PROC_BROWSER_TEST_P(NewGlicApiMultiProfileTest, testGetContextCrossProfile) {
+#if !BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_WIN) && !BUILDFLAG(IS_MAC)
+  GTEST_SKIP() << "Multi-profile tests only supported on Desktop";
+#endif
+  ASSERT_OK(OpenGlicForActiveTab());
+  BrowserWindowInterface* other_browser = CreateBrowserWithNewProfile();
+  ASSERT_TRUE(other_browser);
+  ASSERT_TRUE(content::NavigateToURL(
+      TabListInterface::From(other_browser)->GetActiveTab()->GetContents(),
+      GetTestUrl("page.html")));
+  auto other_tab_handle =
+      TabListInterface::From(other_browser)->GetTab(0)->GetHandle();
+  ExecuteJsTest({.params = base::Value(GlicTabId(other_tab_handle))});
+}
+
 IN_PROC_BROWSER_TEST_P(NewGlicApiTestWithWebContentsWarming,
                        testWebClientReadyOnFullLoad) {
   service()->web_contents_warming_pool().EnsurePreload();
@@ -923,6 +1015,11 @@
                          DefaultTestParamSet(),
                          &WithTestParams::PrintTestVariant);
 
+INSTANTIATE_TEST_SUITE_P(,
+                         NewGlicApiMultiProfileTest,
+                         DefaultTestParamSet(),
+                         &WithTestParams::PrintTestVariant);
+
 // Skills are not supported yet on Android.
 #if !BUILDFLAG(IS_ANDROID)
 INSTANTIATE_TEST_SUITE_P(,
@@ -930,7 +1027,6 @@
                          DefaultTestParamSet(),
                          &WithTestParams::PrintTestVariant);
 #endif
-
 #else
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(NewGlicApiTest);
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
@@ -938,6 +1034,7 @@
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(NewGlicApiTestWithPixelOutput);
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
     NewGlicApiTestWithGeminiActOnWebPolicy);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(NewGlicApiMultiProfileTest);
 #if !BUILDFLAG(IS_ANDROID)
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(NewGlicApiTestWithSkills);
 #endif
diff --git a/chrome/test/data/webui/glic/browser_tests/new_glic_api_browsertest.ts b/chrome/test/data/webui/glic/browser_tests/new_glic_api_browsertest.ts
index 8b56477..0e0f3160 100644
--- a/chrome/test/data/webui/glic/browser_tests/new_glic_api_browsertest.ts
+++ b/chrome/test/data/webui/glic/browser_tests/new_glic_api_browsertest.ts
@@ -5,7 +5,7 @@
 import {ClientCapabilities, SkillSource} from '/glic/glic_api/glic_api.js';
 import type {GlicWebClient, InvokeOptions, Observable, OpenPanelInfo, PageMetadata, PanelOpeningData, PanelState, TabData} from '/glic/glic_api/glic_api.js';
 
-import {ApiTestError, ApiTestFixtureBase, assertDefined, assertEquals, assertTrue, assertUndefined, checkDefined, mapObservable, observeSequence, runUntil, sleep, testMain, waitFor, WebClient} from './browser_test_base.js';
+import {ApiTestError, ApiTestFixtureBase, assertDefined, assertEquals, assertRejects, assertTrue, assertUndefined, checkDefined, mapObservable, observeSequence, runUntil, sleep, testMain, waitFor, WebClient} from './browser_test_base.js';
 
 class ApiTests extends ApiTestFixtureBase {
   override async setUpTest() {
@@ -240,6 +240,45 @@
     await this.advanceToNextStep();
     await actOnWebCapabilitySequence.waitForValue(false);
   }
+
+  async testPageMetadataCrossProfile() {
+    const otherTabId = this.testParams as string;
+    assertDefined(this.host.getPageMetadata);
+    const observable = this.host.getPageMetadata(otherTabId, ['title']);
+    const sequence = observeSequence(observable);
+    await sequence.waitForComplete();
+    assertEquals(
+        true, sequence.isEmpty(),
+        'Expected no page metadata for cross-profile tab');
+  }
+
+  async testTabDataCrossProfile() {
+    const otherTabId = this.testParams as string;
+    assertDefined(this.host.getTabById);
+    const observable = this.host.getTabById(otherTabId);
+    const sequence = observeSequence(observable);
+    await sequence.waitForComplete();
+    assertEquals(
+        true, sequence.isEmpty(), 'Expected no tab data for cross-profile tab');
+  }
+
+  async testTabFaviconCrossProfile() {
+    const otherTabId = this.testParams as string;
+    assertDefined(this.host.getTabFaviconById);
+    const observable = this.host.getTabFaviconById(otherTabId);
+    const sequence = observeSequence(observable);
+    await sequence.waitForComplete();
+    assertEquals(
+        true, sequence.isEmpty(), 'Expected no favicon for cross-profile tab');
+  }
+
+  async testGetContextCrossProfile() {
+    const otherTabId = this.testParams as string;
+    assertDefined(this.host.getContextForActorFromTab);
+    await assertRejects(this.host.getContextForActorFromTab(otherTabId, {}), {
+      withErrorMessage: 'tabContext failed: profile mismatch',
+    });
+  }
 }
 
 class FaviconTest extends ApiTests {
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.