CVE-2025-3072
Overview
Background
- Custom Tabs (CCT)
- Android’s Chrome Custom Tabs, a mode where a host app embeds Chrome’s browsing UI; here the context menu runs in
ContextMenuMode.CUSTOM_TAB. - Ephemeral / Preview tab
- the “Preview Page” (Open in ephemeral tab) feature surfaced as the
Item.OPEN_IN_EPHEMERAL_TABcontext-menu item, gated byEphemeralTabCoordinator.isSupported(). - `data:` URL
- a URL scheme (
UrlConstants.DATA_SCHEME) that embeds document content inline in the URL rather than fetching from an origin, so its content and origin are attacker-controlled. - `ChromeContextMenuPopulator`
- the Java class that builds Chrome’s link/image context menu, including the CCT preview item, from
mParams(the touched link’s parameters).
Root Cause Analysis
Before the patch, when the context menu was built in a Custom Tab and ephemeral tabs were supported, the “Open in ephemeral tab” (Preview Page) item was added unconditionally via linkGroup.add(createListItem(Item.OPEN_IN_EPHEMERAL_TAB, ...)), with the CCT branch only recording a UMA histogram of the URL scheme. This meant a data: URL could be previewed in an ephemeral tab inside a Custom Tab, which the commit message states “could present a potential security problem.”
The fix computes isDataUrl from mParams.getUrl().getScheme().equals(UrlConstants.DATA_SCHEME) and wraps the linkGroup.add(...) in if (!(mMode == ContextMenuMode.CUSTOM_TAB && isDataUrl)), so the preview item is suppressed for data: URLs specifically in CCT. The one-off measurement machinery (the UrlScheme @IntDef, schemeForUrl, the RecordHistogram call, and the CustomTabsUrlScheme enum/histogram XML) is removed since its purpose — sizing the volume of data: scheme previews — is complete.
The fix works by removing the code path that offered ephemeral-tab preview of data: content under a CCT host’s UI.
data: URLs; the fix adds a scheme check that suppresses the menu item when a Custom Tab targets a data: URL.Attack Path
- Open content in a Custom Tab
A host app (or a page opened in CCT) presents a link whose URL uses the
data:scheme, somMode == ContextMenuMode.CUSTOM_TABand the target scheme isUrlConstants.DATA_SCHEME. - Invoke the context menu
The user long-presses the link, and
ChromeContextMenuPopulatorbuilds the menu; pre-patch it addsItem.OPEN_IN_EPHEMERAL_TABregardless of scheme. - Preview the `data:` document
Selecting “Preview Page” opens the
data:content in an ephemeral/preview tab within the CCT UI, rendering attacker-controlled content in a context that could be misattributed to the host app’s tab (inferred). - Exploit the security issue
The mismatch between the previewed
data:content and the surrounding Custom Tab presentation enables the “potential security problem” the commit cites, such as UI spoofing (inferred), which the patch closes by never offering the item.
Impact Assessment
data: URL link inside a Custom Tab could offer a “Preview Page” action that renders attacker-controlled inline content in the ephemeral-tab UI, an inappropriate implementation in Custom Tabs per the advisory. The precondition is user interaction (opening the context menu and choosing Preview Page) on a data: link within CCT on Android. The advisory rates this as a LogicError and does not report in-the-wild exploitation; any concrete escalation such as origin/UI spoofing is (inferred).Changed Functions
| Function | Change | Notes |
|---|---|---|
ifchrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java |
modified |
Files Changed
chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.javatools/metrics/histograms/metadata/custom_tabs/enums.xmltools/metrics/histograms/metadata/custom_tabs/histograms.xml
Audit Directions
- Scheme-agnostic UI actionsAudit context-menu and share/preview actions that are offered without checking the URL scheme, especially where
data:,blob:,javascript:, orcontent:content could be rendered. - Custom Tab UI boundariesLook for CCT-mode surfaces (
ContextMenuMode.CUSTOM_TAB) that render or preview content in a way that can be confused with the host app’s context or the embedding origin. - Ephemeral/preview rendering sinksReview every entry point into ephemeral/preview tabs to confirm attacker-controlled inline schemes are gated the same way as this fixed context-menu path.
Patch
From ce7064982527865ee63c8fd136fe2cca52fbdb10 Mon Sep 17 00:00:00 2001 From: Jinsuk Kim <[email protected]> Date: Thu, 06 Feb 2025 13:38:45 -0800 Subject: [PATCH] [CCT] Suppress preview page for data: url on CCT The volume of data: url scheme opening preview page on CCT is pretty low. This CL suppresses the menu item as it could present a potential security problem. Histogram/enum added for the stats were also removed as they were for one-off measurement. Bug: 362545037 Change-Id: I72b6cf77507157b8f8dfdac43dee127530c9415a Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6184388 Reviewed-by: Sinan Sahin <[email protected]> Commit-Queue: Jinsuk Kim <[email protected]> Cr-Commit-Position: refs/heads/main@{#1416995} --- diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java index 5809857..86c45512 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java @@ -26,7 +26,6 @@ import org.chromium.base.Callback; import org.chromium.base.ContextUtils; -import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.shared_preferences.SharedPreferencesManager; import org.chromium.base.supplier.Supplier; import org.chromium.chrome.R; @@ -211,67 +210,6 @@ } } - // Used to record the UMA histogram Android.CustomTabs.ContextMenu.UrlScheme. These don't - // need to be a comprehensive list of schemes since what we are interested in is the relative - // volume of data scheme. - // Since these values are persisted to logs, they should never be renumbered or reused. - // LINT.IfChange(UrlScheme) - @VisibleForTesting - @IntDef({ - UrlScheme.UNKNOWN_SCHEME, - UrlScheme.HTTP_SCHEME, - UrlScheme.HTTPS_SCHEME, - UrlScheme.FILE_SCHEME, - UrlScheme.FTP_SCHEME, - UrlScheme.DATA_SCHEME, - UrlScheme.JAVASCRIPT_SCHEME, - UrlScheme.CHROME_SCHEME, - UrlScheme.BLOB_SCHEME, - UrlScheme.CONTENT_SCHEME, - UrlScheme.INTENT_SCHEME, - }) - public @interface UrlScheme { - int UNKNOWN_SCHEME = 0; - int HTTP_SCHEME = 1; - int HTTPS_SCHEME = 2; - int FILE_SCHEME = 3; - int FTP_SCHEME = 4; - int DATA_SCHEME = 5; - int JAVASCRIPT_SCHEME = 6; - int CHROME_SCHEME = 7; - int BLOB_SCHEME = 8; - int CONTENT_SCHEME = 9; - int INTENT_SCHEME = 10; - int COUNT = 11; - } - - // LINT.ThenChange(/tools/metrics/histograms/metadata/custom_tabs/enums.xml:CustomTabsUrlScheme) - - private static @UrlScheme int schemeForUrl(String scheme) { - if (scheme.equals(UrlConstants.HTTP_SCHEME)) { - return UrlScheme.HTTP_SCHEME; - } else if (scheme.equals(UrlConstants.HTTPS_SCHEME)) { - return UrlScheme.HTTPS_SCHEME; - } else if (scheme.equals(UrlConstants.FILE_SCHEME)) { - return UrlScheme.FILE_SCHEME; - } else if (scheme.equals(UrlConstants.FTP_SCHEME)) { - return UrlScheme.FTP_SCHEME; - } else if (scheme.equals(UrlConstants.DATA_SCHEME)) { - return UrlScheme.DATA_SCHEME; - } else if (scheme.equals(UrlConstants.JAVASCRIPT_SCHEME)) { - return UrlScheme.JAVASCRIPT_SCHEME; - } else if (scheme.equals(UrlConstants.CHROME_SCHEME)) { - return UrlScheme.CHROME_SCHEME; - } else if (scheme.equals(UrlConstants.BLOB_SCHEME)) { - return UrlScheme.BLOB_SCHEME; - } else if (scheme.equals(UrlConstants.CONTENT_SCHEME)) { - return UrlScheme.CONTENT_SCHEME; - } else if (scheme.equals(UrlConstants.INTENT_SCHEME)) { - return UrlScheme.INTENT_SCHEME; - } - return UrlScheme.UNKNOWN_SCHEME; - } - /** * Builds a {@link ChromeContextMenuPopulator}. * @@ -350,15 +288,15 @@ } if ((mMode == ContextMenuMode.NORMAL || mMode == ContextMenuMode.CUSTOM_TAB) && EphemeralTabCoordinator.isSupported()) { - mShowEphemeralTabNewLabel = shouldTriggerEphemeralTabHelpUi(); - if (mMode == ContextMenuMode.CUSTOM_TAB) { - @UrlScheme int enumScheme = schemeForUrl(mParams.getUrl().getScheme()); - RecordHistogram.recordEnumeratedHistogram( - "CustomTabs.ContextMenu.UrlScheme", enumScheme, UrlScheme.COUNT); + boolean showNewLabel = shouldTriggerEphemeralTabHelpUi(); + boolean isDataUrl = + mParams.getUrl().getScheme().equals(UrlConstants.DATA_SCHEME); + if (!(mMode == ContextMenuMode.CUSTOM_TAB && isDataUrl)) { + // Do not show the item if CCT opens data: url as it could potentially + // cause a security issue. + linkGroup.add(createListItem(Item.OPEN_IN_EPHEMERAL_TAB, showNewLabel)); + mShowEphemeralTabNewLabel = showNewLabel; } - - linkGroup.add( - createListItem(Item.OPEN_IN_EPHEMERAL_TAB, mShowEphemeralTabNewLabel)); } } if (!MailTo.isMailTo(mParams.getLinkUrl().getSpec()) diff --git a/tools/metrics/histograms/metadata/custom_tabs/enums.xml b/tools/metrics/histograms/metadata/custom_tabs/enums.xml index bcf6192..0676ac3 100644 --- a/tools/metrics/histograms/metadata/custom_tabs/enums.xml +++ b/tools/metrics/histograms/metadata/custom_tabs/enums.xml @@ -184,24 +184,6 @@ memory"/> </enum> -<!-- LINT.IfChange(CustomTabsUrlScheme) --> - -<enum name="CustomTabsUrlScheme"> - <int value="0" label="Unknown scheme"/> - <int value="1" label="HTTP"/> - <int value="2" label="HTTPS"/> - <int value="3" label="File"/> - <int value="4" label="Ftp"/> - <int value="5" label="Data"/> - <int value="6" label="Javascript"/> - <int value="7" label="Chrome"/> - <int value="8" label="Blob"/> - <int value="9" label="Content"/> - <int value="10" label="Intent"/> -</enum> - -<!-- LINT.ThenChange(//chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java:UrlScheme) --> - <enum name="GoogleBottomBarButtonEvent"> <int value="0" label="Unknown button"/> <int value="1" label="Chrome Page Insights button"/> diff --git a/tools/metrics/histograms/metadata/custom_tabs/histograms.xml b/tools/metrics/histograms/metadata/custom_tabs/histograms.xml index 999cd33d..8d30595e7 100644 --- a/tools/metrics/histograms/metadata/custom_tabs/histograms.xml +++ b/tools/metrics/histograms/metadata/custom_tabs/histograms.xml @@ -227,18 +227,6 @@ </summary> </histogram> -<histogram name="CustomTabs.ContextMenu.UrlScheme" enum="CustomTabsUrlScheme" - expires_after="2025-07-27"> - <owner>[email protected]</owner> - <owner>[email protected]</owner> - <summary> - Records the scheme of the URL for which the context menu is shown on Custom - Tabs. This histogram is to understand the relative volume of data: scheme - with a view to not displaying the menu 'Preview Page' for the scheme if the - volume is insignificant. Recorded when the context menu is opened. - </summary> -</histogram> - <histogram base="true" name="CustomTabs.DetachedResourceRequest.Duration" units="ms" expires_after="2024-03-17"> <owner>[email protected]</owner>