Medium watch CVSS 5.4 chrome Spoofing 📄 Reporter bug report 🔧 Commit mapped

Overview

Medium
Severity
5.4
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactIncorrect security UI in Omnibox
DescriptionIncorrect security UI in Omnibox
ComponentOmnibox
Sub-componentMobar
Bug ClassSpoofing
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.
Tracker446463993
Fix commitb6d8c675b341 (chromium/src) +37/-8
CWECWE-285, CWE-451
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:L
CISA KEVNot listed
CreditedHafiizh
Reported2025-09-21 · bounty $3000 (per vendor advisory)
Fix landed2025-09-23 (public git)
Disclosed2025-10-28
Patch gap35 days — fix public in source before the advisory

Background

Location-bar-only mode ("mobar")
an Android toolbar state, tracked by mShowLocationBarOnly in ToolbarControlContainer, in which the mLocationBarView is detached from the toolbar and shown on its own inside mToolbarContainer, with the container painting its own background color.
Toolbar primary color
the background color of the Android top toolbar, which varies with tab state (e.g., incognito, page theme color) and is exposed by ToolbarDataProvider.getPrimaryColor(), which the commit names as the source of truth.
`LocationBarModel`
the Android model that implements the location bar and toolbar data providers and notifies registered observers when data such as the primary color changes.
`ToolbarDataProvider.Observer`
the observer interface for toolbar data consumers, which before the patch only offered onIncognitoStateChanged().

Root Cause Analysis

When ToolbarControlContainer switched into location-bar-only mode, it set its background once with setBackgroundColor(mToolbar.getPrimaryColor()) and never updated it afterwards, because it had no subscription to primary-color changes. LocationBarModel notified only LocationBarDataProvider observers of onPrimaryColorChanged(), so if the primary color changed while the mobar was showing (the commit calls this “the rare but bad case”), the container background stayed stale while other location-bar consumers updated to the new color. This breaks the invariant that the security-relevant URL/origin display is drawn against the background color its styling was computed for; a mismatch could make the displayed origin or security indicators misleading or hard to read (inferred; the diff does not show how text/icon colors are derived).

The fix adds onPrimaryColorChanged() to ToolbarDataProvider.Observer, has LocationBarModel also notify mToolbarDataObservers, passes the ToolbarDataProvider into ToolbarControlContainer, which registers itself as an observer (and unregisters on teardown), and re-applies mToolbarDataProvider.getPrimaryColor() whenever the color changes while mShowLocationBarOnly is true. The initial background in location-bar-only mode is also taken from mToolbarDataProvider rather than mToolbar, making the data provider the single source of truth.

Key insight
The location-bar-only container sampled the toolbar color once and was not wired to color-change notifications, so its background could go stale while the omnibox was showing. The fix adds a ToolbarDataProvider primary-color observer path so the container repaints whenever the color changes.

Attack Path

  1. Location-bar-only mode shown The Android browser enters the state where ToolbarControlContainer shows only the location bar (mShowLocationBarOnly) and sets its background from the current primary color.
  2. Primary color changes While that mode is visible, the toolbar primary color changes; a page influencing its theme color is one plausible trigger (inferred; the diff does not show what drives the change).
  3. Stale background Pre-patch, LocationBarModel only notified LocationBarDataProvider observers, so the container kept the old color while location-bar contents updated for the new one.
  4. Misleading security UI The URL/origin and security indicators are drawn against a background they were not styled for, which could make them hard to read or misleading to the user (inferred).

Impact Assessment

The bug is a UI-consistency flaw in the Android browser UI (Java browser process), not memory corruption: at most it lets the omnibox display a stale background color that could make origin or security indicators misleading or hard to read, aiding spoofing (inferred). It is limited to Android and to the location-bar-only mode, needs the primary color to change while that mode is visible (described by the commit as rare), and whether ordinary web content can reliably trigger both conditions, or whether the mode is behind a feature flag, is not shown by the diff. The vendor rates it Medium severity; the provided metadata does not state in-the-wild exploitation.

Changed Functions

FunctionChangeNotes
for
chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java
modified
if
chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainer.java
modified

Files Changed

  • chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java
  • chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ToolbarDataProvider.java
  • chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainer.java
  • chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainerTest.java
  • chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java

Audit Directions

  • One-shot sampling of security UI state
    Search Android toolbar/omnibox code for places that read getPrimaryColor(), security level, or URL text once when entering a special layout mode (location-bar-only, fullscreen, custom tabs, desktop windowing) without subscribing to later changes.
  • Split observer lists
    Where a model like LocationBarModel maintains multiple observer lists for overlapping data, check that every change notification fans out to all lists whose consumers render that data.
  • Background/foreground color coupling
    Verify that any view painting its own background behind omnibox text or security icons derives both from the same provider and updates them together, so attacker-influenced theme changes cannot desynchronize them.
From b6d8c675b3417e6e3bafb37921d4f914eb8b25f6 Mon Sep 17 00:00:00 2001
From: Patrick Noland <pnoland@google.com>
Date: Tue, 23 Sep 2025 16:27:56 -0700
Subject: [PATCH] [mobar] Update mobar bg color in sync with toolbar primary color

The source of truth for this is is ToolbarDataProvider. This avoids the
rare but bad case of color changes while the mobar is showing.

Bug: 446463993
Change-Id: I6268839d362865245473ccef31220b90a8af0d82
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6976339
Commit-Queue: Patrick Noland <pnoland@chromium.org>
Reviewed-by: Tomasz Wiszkowski <ender@google.com>
Cr-Commit-Position: refs/heads/main@{#1519663}
---

diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java
index fea74b3..42853d0 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java
@@ -598,6 +598,9 @@
         for (LocationBarDataProvider.Observer observer : mLocationBarDataObservers) {
             observer.onPrimaryColorChanged();
         }
+        for (ToolbarDataProvider.Observer observer : mToolbarDataObservers) {
+            observer.onPrimaryColorChanged();
+        }
     }
 
     @Override
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ToolbarDataProvider.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ToolbarDataProvider.java
index f3cf95b8..cec5c7fd 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ToolbarDataProvider.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ToolbarDataProvider.java
@@ -21,6 +21,8 @@
     /** Observer interface for consumers who wish to subscribe to updates of ToolbarData. */
     interface Observer {
         default void onIncognitoStateChanged() {}
+
+        default void onPrimaryColorChanged() {}
     }
 
     /** Adds an observer of changes to ToolbarDataProvider's data. */
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainer.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainer.java
index aadf251e..4ca03b5b 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainer.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainer.java
@@ -54,12 +54,14 @@
 import org.chromium.chrome.browser.toolbar.ControlContainer;
 import org.chromium.chrome.browser.toolbar.R;
 import org.chromium.chrome.browser.toolbar.ToolbarCaptureType;
+import org.chromium.chrome.browser.toolbar.ToolbarDataProvider;
+import org.chromium.chrome.browser.toolbar.ToolbarDataProvider.Observer;
 import org.chromium.chrome.browser.toolbar.ToolbarFeatures;
 import org.chromium.chrome.browser.toolbar.ToolbarHairlineView;
 import org.chromium.chrome.browser.toolbar.ToolbarProgressBar;
 import org.chromium.chrome.browser.toolbar.top.CaptureReadinessResult.TopToolbarBlockCaptureReason;
 import org.chromium.components.browser_ui.desktop_windowing.AppHeaderState;
-import org.chromium.components.browser_ui.desktop_windowing.DesktopWindowStateManager;
+import org.chromium.components.browser_ui.desktop_windowing.DesktopWindowStateManager.AppHeaderObserver;
 import org.chromium.components.browser_ui.widget.ClipDrawableProgressBar.DrawingInfo;
 import org.chromium.components.browser_ui.widget.TouchEventObserver;
 import org.chromium.components.browser_ui.widget.ViewResourceCoordinatorLayout;
@@ -80,7 +82,7 @@
 /** Layout for the browser controls (omnibox, menu, tab strip, etc..). */
 @NullMarked
 public class ToolbarControlContainer extends OptimizedFrameLayout
-        implements ControlContainer, DesktopWindowStateManager.AppHeaderObserver, TopControlLayer {
+        implements ControlContainer, AppHeaderObserver, TopControlLayer, Observer {
     private boolean mIncognito;
     private boolean mMidVisibilityToggle;
     private boolean mIsCompositorInitialized;
@@ -104,6 +106,7 @@
     private @Nullable ObservableSupplier<Boolean> mXrSpaceModeObservableSupplier;
     private @Nullable ObservableSupplierImpl<Integer> mHeightChangedSupplier;
     private @Nullable TopControlsStacker mTopControlsStacker;
+    private ToolbarDataProvider mToolbarDataProvider;
 
     /**
      * Constructs a new control container.
@@ -250,7 +253,7 @@
             mToolbarView.setVisibility(View.GONE);
             mToolbarView.removeView(mLocationBarView);
             mToolbarContainer.addView(mLocationBarView);
-            setBackgroundColor(mToolbar.getPrimaryColor());
+            setBackgroundColor(mToolbarDataProvider.getPrimaryColor());
         } else {
             assert mLocationBarView != null
                     : "Trying to restore location bar view to toolbar without removing it first";
@@ -291,6 +294,9 @@
         if (mXrSpaceModeObservableSupplier != null) {
             mXrSpaceModeObservableSupplier.removeObserver(mOnXrSpaceModeChanged);
         }
+        if (mToolbarDataProvider != null) {
+            mToolbarDataProvider.removeToolbarDataProviderObserver(this);
+        }
     }
 
     @Override
@@ -381,10 +387,13 @@
                     browserStateBrowserControlsVisibilityDelegate,
             OneshotSupplier<LayoutStateProvider> layoutStateProviderSupplier,
             FullscreenManager fullscreenManager,
-            TopControlsStacker topControlsStacker) {
+            TopControlsStacker topControlsStacker,
+            ToolbarDataProvider toolbarDataProvider) {
         mToolbar = toolbar;
         mIncognito = isIncognito;
         mTopControlsStacker = topControlsStacker;
+        mToolbarDataProvider = toolbarDataProvider;
+        mToolbarDataProvider.addToolbarDataProviderObserver(this);
 
         BooleanSupplier isVisible = () -> this.getVisibility() == View.VISIBLE;
         mToolbarContainer.setPostInitializationDependencies(
@@ -477,6 +486,13 @@
         mToolbarContainer.setOnDragListener(mToolbarContainerDragListener);
     }
 
+    @Override
+    public void onPrimaryColorChanged() {
+        if (mShowLocationBarOnly) {
+            setBackgroundColor(mToolbarDataProvider.getPrimaryColor());
+        }
+    }
+
     /** The layout that handles generating the toolbar view resource. */
     // Only publicly visible due to lint warnings.
     public static class ToolbarViewResourceCoordinatorLayout extends ViewResourceCoordinatorLayout {
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainerTest.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainerTest.java
index 7a79938..aac01ab 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainerTest.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainerTest.java
@@ -549,7 +549,7 @@
     @Test
     public void testShowLocationBarOnly() {
         doReturn(mLocationBarView).when(mToolbar).removeLocationBarView();
-        doReturn(Color.RED).when(mToolbar).getPrimaryColor();
+        doReturn(Color.RED).when(mToolbarDataProvider).getPrimaryColor();
         ToolbarControlContainer controlContainer =
                 (ToolbarControlContainer)
                         mActivity.getLayoutInflater().inflate(R.layout.control_container, null);
@@ -564,7 +564,8 @@
                 mBrowserStateBrowserControlsVisibilityDelegate,
                 mLayoutStateProviderSupplier,
                 mFullscreenManager,
-                mTopControlsStacker);
+                mTopControlsStacker,
+                mToolbarDataProvider);
 
         ToolbarPhone toolbarPhone = controlContainer.findViewById(R.id.toolbar);
         doReturn(mLocationBarCoordinatorPhone).when(mLocationBarCoordinator).getPhoneCoordinator();
@@ -595,7 +596,12 @@
         verify(mProgressBar).setVisibility(View.GONE);
         verify(mToolbarView).setVisibility(View.GONE);
         verify(mToolbarView).removeView(mLocationBarView);
+
         assertEquals(Color.RED, ((ColorDrawable) controlContainer.getBackground()).getColor());
+        doReturn(Color.GREEN).when(mToolbarDataProvider).getPrimaryColor();
+        controlContainer.onPrimaryColorChanged();
+        assertEquals(Color.GREEN, ((ColorDrawable) controlContainer.getBackground()).getColor());
+
         ToolbarViewResourceCoordinatorLayout toolbarViewResourceFrameLayout =
                 controlContainer.getToolbarContainerForTesting();
         assertEquals(
@@ -629,7 +635,8 @@
                 mBrowserStateBrowserControlsVisibilityDelegate,
                 mLayoutStateProviderSupplier,
                 mFullscreenManager,
-                mTopControlsStacker);
+                mTopControlsStacker,
+                mToolbarDataProvider);
         ToolbarControlContainer.ToolbarViewResourceCoordinatorLayout toolbarContainer =
                 controlContainer.findViewById(R.id.toolbar_container);
         toolbarContainer.setVisibility(View.GONE);
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java
index 1cd82ab..13ba4e7b 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java
@@ -243,7 +243,8 @@
                 browserStateBrowserControlsVisibilityDelegate,
                 layoutStateProviderSupplier,
                 fullscreenManager,
-                topControlsStacker);
+                topControlsStacker,
+                toolbarDataProvider);
         mToolbarLayout.initialize(
                 toolbarDataProvider,
                 tabController,
Loading diff…

Original Bug Report

reported by sa...@gmail.com

Spoof on virtual keyboard

VULNERABILITY DETAILS

when the virtual keyboard is displayed and at the same time the navigation is directed to the previous page (history.go(-1)) the virtual keyboard still appears and the color of the minibar above the virtual keyboard becomes dynamic (the color follows the –theme-color of the background color so that the writing in the minibar is the same so that the domain is not visible in this bug I use white color) , leading to a spoof.

OS: Android 15 Device: Samsung A56 Chrome Version: 142.0.7396.0 Canary

Steps to reproduce:

  1. download detx.html,spoofkeyboard.html in same folder / host detx.html,spoofkeyboard.html on local web server using https:// protocol
  2. open https://you-can-billowy-nimble-login-secure-docs-google-source-attacker.com/detx.html or open detx.html on local web server using https: protocol
  3. click the button
  4. clik the go to google button
View on issue tracker