Chrome · SplitView
CVE-2025-12446
Logic Error in SplitView
Overview
Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifchrome/browser/resources/tab_search/tab_search_page.ts |
modified |
Files Changed
chrome/browser/resources/tab_search/tab_search_item.csschrome/browser/resources/tab_search/tab_search_page.tschrome/browser/ui/webui/tab_search/tab_search_ui.ccchrome/test/data/webui/tab_search/tab_search_page_test.ts
Patch
From 5afd445e6deae19de5bf3629b451cea29a7b860e Mon Sep 17 00:00:00 2001
From: Alison Gale <agale@chromium.org>
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 <cthomp@chromium.org>
Reviewed-by: Yuheng Huang <yuhengh@chromium.org>
Commit-Queue: Alison Gale <agale@chromium.org>
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.
References
On This Page