Low watch CVSS 5.4 chrome Logic Error 🔧 Commit mapped

Overview

Low
Severity
5.4
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInappropriate implementation in Custom Tabs
DescriptionInappropriate implementation in Custom Tabs
ComponentCustom Tabs
Sub-componentCCT
Bug ClassLogic Error
Action tierwatch — logic/policy bug — security-relevant, no memory-unsafety
Computed by PatchGap's deterministic exploitability ruler from the fixing commit. patch-now = RCE-class & attacker-reachable in a default config, or exploited in the wild; watch = real security signal below that bar; noise = no security relevance.
Tracker362545037
Fix commitce7064982527 (chromium/src) +8/-100
CWECWE-451
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N
CISA KEVNot listed
CreditedOm Apip
Reported2024-08-27 · bounty $1000 (per vendor advisory)
Fix landed2025-02-06 (public git)
Disclosed2025-04-01
Patch gap54 days — fix public in source before the advisory

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_TAB context-menu item, gated by EphemeralTabCoordinator.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.

Key insight
The core mistake was unconditionally offering the “Preview Page” ephemeral-tab action for any URL scheme in a Custom Tab, including attacker-controlled data: URLs; the fix adds a scheme check that suppresses the menu item when a Custom Tab targets a data: URL.

Attack Path

  1. Open content in a Custom Tab A host app (or a page opened in CCT) presents a link whose URL uses the data: scheme, so mMode == ContextMenuMode.CUSTOM_TAB and the target scheme is UrlConstants.DATA_SCHEME.
  2. Invoke the context menu The user long-presses the link, and ChromeContextMenuPopulator builds the menu; pre-patch it adds Item.OPEN_IN_EPHEMERAL_TAB regardless of scheme.
  3. 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).
  4. 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

An attacker able to place a 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

FunctionChangeNotes
if
chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java
modified

Files Changed

  • chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java
  • tools/metrics/histograms/metadata/custom_tabs/enums.xml
  • tools/metrics/histograms/metadata/custom_tabs/histograms.xml

Audit Directions

  • Scheme-agnostic UI actions
    Audit context-menu and share/preview actions that are offered without checking the URL scheme, especially where data:, blob:, javascript:, or content: content could be rendered.
  • Custom Tab UI boundaries
    Look 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 sinks
    Review every entry point into ephemeral/preview tabs to confirm attacker-controlled inline schemes are gated the same way as this fixed context-menu path.
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>
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.