Low chrome Logic Error 🔧 Commit mapped

Overview

Low
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactIncorrect security UI in SplitView
DescriptionIncorrect security UI in SplitView
ComponentSplitView
Bug ClassLogic Error
Tracker444932667
Fix commit5afd445e6dea (chromium/src) +59/-2
CISA KEVNot listed
CreditedHafiizh
Disclosed2025-10-28

Changed Functions

FunctionChangeNotes
if
chrome/browser/resources/tab_search/tab_search_page.ts
modified

Files Changed

  • chrome/browser/resources/tab_search/tab_search_item.css
  • chrome/browser/resources/tab_search/tab_search_page.ts
  • chrome/browser/ui/webui/tab_search/tab_search_ui.cc
  • chrome/test/data/webui/tab_search/tab_search_page_test.ts
From 5afd445e6deae19de5bf3629b451cea29a7b860e Mon Sep 17 00:00:00 2001
From: Alison Gale <[email protected]>
Date: Wed, 17 Sep 2025 12:56:50 -0700
Subject: [PATCH] [SxS] Fix URL eliding for tab search

Show "temporary data" for blob: URLs and "local or shared file" for
file: URLs to match what we do for hovercards and mini toolbar. Elide
URLs from the front to avoid spoofing with long subdomains.

Before: https://screenshot.googleplex.com/BFA7KaDQtYpR5ZH
After: https://screenshot.googleplex.com/3e9uyAMCfZxxSHL

Guidelines: https://chromium.googlesource.com/chromium/src/+/HEAD/docs/security/url_display_guidelines/url_display_guidelines.md#eliding-urls

Bug: 444932667,444915898
Change-Id: Id3a540eaa4392a85f9db2d0b5424d009a1bd271c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6956837
Reviewed-by: Chris Thompson <[email protected]>
Reviewed-by: Yuheng Huang <[email protected]>
Commit-Queue: Alison Gale <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1516831}
---

diff --git a/chrome/browser/resources/tab_search/tab_search_item.css b/chrome/browser/resources/tab_search/tab_search_item.css
index 8a06e14e..5b3a2ae1 100644
--- a/chrome/browser/resources/tab_search/tab_search_item.css
+++ b/chrome/browser/resources/tab_search/tab_search_item.css
@@ -79,6 +79,11 @@
   white-space: nowrap;
 }
 
+#secondaryText {
+  /* Elide hostname from the front to prevent URL spoofing. */
+  direction: rtl;
+}
+
 #primaryText {
   color: var(--cr-primary-text-color);
   font-size: var(--mwb-primary-text-font-size);
diff --git a/chrome/browser/resources/tab_search/tab_search_page.ts b/chrome/browser/resources/tab_search/tab_search_page.ts
index c58fdc3..3dbd50776 100644
--- a/chrome/browser/resources/tab_search/tab_search_page.ts
+++ b/chrome/browser/resources/tab_search/tab_search_page.ts
@@ -661,11 +661,22 @@
     return ariaLabel(tabData);
   }
 
+  private getDisplayHostnameForUrl_(url: URL): string {
+    if (url.protocol === 'blob:') {
+      return loadTimeData.getString('blobUrlSource');
+    } else if (url.protocol === 'file:') {
+      return loadTimeData.getString('fileUrlSource');
+    } else {
+      return url.hostname;
+    }
+  }
+
   private tabData_(
       tab: Tab|RecentlyClosedTab, inActiveWindow: boolean, type: TabItemType,
       tabGroupsMap: Map<string, TabGroup>): TabData {
-    const tabData =
-        new TabData(tab, type, new URL(normalizeURL(tab.url.url)).hostname);
+    const tabData = new TabData(
+        tab, type,
+        this.getDisplayHostnameForUrl_(new URL(normalizeURL(tab.url.url))));
 
     if (tab.groupId) {
       tabData.tabGroup = tabGroupsMap.get(tokenToString(tab.groupId));
diff --git a/chrome/browser/ui/webui/tab_search/tab_search_ui.cc b/chrome/browser/ui/webui/tab_search/tab_search_ui.cc
index c3c82b31..f30546bc 100644
--- a/chrome/browser/ui/webui/tab_search/tab_search_ui.cc
+++ b/chrome/browser/ui/webui/tab_search/tab_search_ui.cc
@@ -79,10 +79,12 @@
        IDS_TAB_SEARCH_A11Y_RECENTLY_CLOSED_TAB_GROUP},
       {"audioMuting", IDS_TAB_AX_LABEL_AUDIO_MUTING_FORMAT},
       {"audioPlaying", IDS_TAB_AX_LABEL_AUDIO_PLAYING_FORMAT},
+      {"blobUrlSource", IDS_HOVER_CARD_BLOB_URL_SOURCE},
       {"clearSearch", IDS_CLEAR_SEARCH},
       {"closeTab", IDS_TAB_SEARCH_CLOSE_TAB},
       {"collapseRecentlyClosed", IDS_TAB_SEARCH_COLLAPSE_RECENTLY_CLOSED},
       {"expandRecentlyClosed", IDS_TAB_SEARCH_EXPAND_RECENTLY_CLOSED},
+      {"fileUrlSource", IDS_HOVER_CARD_FILE_URL_SOURCE},
       {"mediaRecording", IDS_TAB_AX_LABEL_MEDIA_RECORDING_FORMAT},
       {"audioRecording", IDS_TAB_AX_LABEL_AUDIO_RECORDING_FORMAT},
       {"videoRecording", IDS_TAB_AX_LABEL_VIDEO_RECORDING_FORMAT},
diff --git a/chrome/test/data/webui/tab_search/tab_search_page_test.ts b/chrome/test/data/webui/tab_search/tab_search_page_test.ts
index b91f9ca..5183ed0 100644
--- a/chrome/test/data/webui/tab_search/tab_search_page_test.ts
+++ b/chrome/test/data/webui/tab_search/tab_search_page_test.ts
@@ -4,6 +4,7 @@
 
 import 'chrome://tab-search.top-chrome/tab_search.js';
 
+import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
 import {MetricsReporterImpl} from 'chrome://resources/js/metrics_reporter/metrics_reporter.js';
 import type {ProfileData, RecentlyClosedTab, Tab, TabSearchItemElement, TabSearchPageElement} from 'chrome://tab-search.top-chrome/tab_search.js';
 import {SEARCH_QUERY_MAX_LENGTH, TabGroupColor, TabSearchApiProxyImpl} from 'chrome://tab-search.top-chrome/tab_search.js';
@@ -844,4 +845,42 @@
     const [tabInfo] = await testProxy.whenCalled('switchToTab');
     assertEquals(1, tabInfo.tabId);
   });
+
+  test('Handles file URLs', async () => {
+    await setupTest(createProfileData({
+      windows: [{
+        active: true,
+        isHostWindow: true,
+        height: SAMPLE_WINDOW_HEIGHT,
+        tabs: [createTab({
+          title: 'My file',
+          url: {url: 'file:///home'},
+          lastActiveTimeTicks: {internalValue: BigInt(4)},
+        })],
+      }],
+    }));
+    const tabSearchItem =
+        tabSearchPage.$.tabsList.querySelector('tab-search-item')!;
+    assertEquals(
+        loadTimeData.getString('fileUrlSource'), tabSearchItem.data.hostname);
+  });
+
+  test('Handles blob URLs', async () => {
+    await setupTest(createProfileData({
+      windows: [{
+        active: true,
+        isHostWindow: true,
+        height: SAMPLE_WINDOW_HEIGHT,
+        tabs: [createTab({
+          title: 'My blob',
+          url: {url: 'blob:null/foo'},
+          lastActiveTimeTicks: {internalValue: BigInt(4)},
+        })],
+      }],
+    }));
+    const tabSearchItem =
+        tabSearchPage.$.tabsList.querySelector('tab-search-item')!;
+    assertEquals(
+        loadTimeData.getString('blobUrlSource'), tabSearchItem.data.hostname);
+  });
 });
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/chrome/test/data/webui/tab_search/tab_search_page_test.ts b/chrome/test/data/webui/tab_search/tab_search_page_test.ts
index b91f9ca..5183ed0 100644
--- a/chrome/test/data/webui/tab_search/tab_search_page_test.ts
+++ b/chrome/test/data/webui/tab_search/tab_search_page_test.ts
@@ -4,6 +4,7 @@
 
 import 'chrome://tab-search.top-chrome/tab_search.js';
 
+import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
 import {MetricsReporterImpl} from 'chrome://resources/js/metrics_reporter/metrics_reporter.js';
 import type {ProfileData, RecentlyClosedTab, Tab, TabSearchItemElement, TabSearchPageElement} from 'chrome://tab-search.top-chrome/tab_search.js';
 import {SEARCH_QUERY_MAX_LENGTH, TabGroupColor, TabSearchApiProxyImpl} from 'chrome://tab-search.top-chrome/tab_search.js';
@@ -844,4 +845,42 @@
     const [tabInfo] = await testProxy.whenCalled('switchToTab');
     assertEquals(1, tabInfo.tabId);
   });
+
+  test('Handles file URLs', async () => {
+    await setupTest(createProfileData({
+      windows: [{
+        active: true,
+        isHostWindow: true,
+        height: SAMPLE_WINDOW_HEIGHT,
+        tabs: [createTab({
+          title: 'My file',
+          url: {url: 'file:///home'},
+          lastActiveTimeTicks: {internalValue: BigInt(4)},
+        })],
+      }],
+    }));
+    const tabSearchItem =
+        tabSearchPage.$.tabsList.querySelector('tab-search-item')!;
+    assertEquals(
+        loadTimeData.getString('fileUrlSource'), tabSearchItem.data.hostname);
+  });
+
+  test('Handles blob URLs', async () => {
+    await setupTest(createProfileData({
+      windows: [{
+        active: true,
+        isHostWindow: true,
+        height: SAMPLE_WINDOW_HEIGHT,
+        tabs: [createTab({
+          title: 'My blob',
+          url: {url: 'blob:null/foo'},
+          lastActiveTimeTicks: {internalValue: BigInt(4)},
+        })],
+      }],
+    }));
+    const tabSearchItem =
+        tabSearchPage.$.tabsList.querySelector('tab-search-item')!;
+    assertEquals(
+        loadTimeData.getString('blobUrlSource'), tabSearchItem.data.hostname);
+  });
 });
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.