CVE-2026-95279
Overview
Background
- Omnibox prefocus
- On the Android New Tab Page (NTP), the URL bar can be given a blinking cursor via
showUrlBarCursorWithoutFocusAnimations()so a keyboard user can start typing immediately, without playing the normal focus animation. - `DeviceInput.supportsAlphabeticKeyboard()`
- The canonical, centralized predicate for whether the device currently has an alphabetic (typing-capable) keyboard attached; the patch adds
import org.chromium.ui.base.DeviceInputto both files. - `OmniboxCapabilities.hasDesktopExperience(mContext)` and `Configuration.KEYBOARD_QWERTY`
- The two divergent signals used before the patch: one tests whether the omnibox is running in a desktop-windowing experience, the other tests the raw Android
Configuration.keyboardhardware-keyboard flag. - `ToolbarManager` / `LocationBarMediator`
- Two separate Android UI components that each independently decide whether to prefocus the omnibox cursor on the NTP.
Root Cause Analysis
Two independent code paths decided whether to prefocus the NTP omnibox cursor, but each used a different condition to gate the decision: ToolbarManager checked mActivity.getResources().getConfiguration().keyboard == Configuration.KEYBOARD_QWERTY, while LocationBarMediator checked OmniboxCapabilities.hasDesktopExperience(mContext). Because these two signals do not always agree — a device can report a QWERTY hardware-keyboard configuration without being in the desktop experience, or vice-versa — the two components could reach opposite conclusions about whether the cursor should be shown.
The invariant that was violated is that all omnibox prefocus decisions for the same device state must be consistent; here the cursor/focus state could be rendered in a way that did not match the device’s actual keyboard capability or the sibling component’s decision.
The fix replaces both divergent conditions with a single call to DeviceInput.supportsAlphabeticKeyboard(), so both paths derive the prefocus decision from one authoritative signal. This is not a boundary tightening or relaxation but a normalization of two inconsistent predicates onto one canonical source of truth. The removed comment in LocationBarMediator (“While a hardware keyboard is connected, loading the NTP should cause the URL bar to gain focus …”) confirms the intended behavior was keyed to keyboard presence, which hasDesktopExperience() only imperfectly approximated.
DeviceInput.supportsAlphabeticKeyboard().Attack Path
- Reach a divergent device state
Use an Android device/configuration where
Configuration.KEYBOARD_QWERTYandOmniboxCapabilities.hasDesktopExperience(mContext)disagree (e.g., a hardware keyboard reported by the configuration without the desktop experience active, or the reverse). - Load the New Tab Page
Navigate to an NTP, which triggers both the
ToolbarManagerprefocus check (guarded bymIsTabletandUrlUtilities.isNtpUrl(...)) and theLocationBarMediatorNTP-load handler. - Trigger inconsistent prefocus decisions
Because the two components evaluate different conditions, one may call
showUrlBarCursorWithoutFocusAnimations()while the other does not, leaving the omnibox in an inconsistent or misleading focus/cursor state. - UI misrepresentation The user is shown an omnibox focus/cursor presentation that does not accurately reflect the true input state, i.e., the omnibox misrepresents whether it is focused and ready for typed input. (inferred) Any further exploitation as address-bar spoofing is not demonstrated by the diff.
Impact Assessment
LogicError with impact “UI misrepresentation in Omnibox” and reports no memory corruption, code execution, or exploited-in-the-wild status. Any escalation to true address-bar spoofing or user deception beyond the inconsistent cursor state is (inferred), not established by the patch.Changed Functions
| Function | Change | Notes |
|---|---|---|
ifchrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.java |
modified |
Files Changed
chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.javachrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.javachrome/android/java/src/org/chromium/chrome/browser/toolbar/DEPS
Audit Directions
- Duplicated gating conditionsLook for UI behaviors (focus, cursor, animations, capability toggles) decided independently in more than one component; verify every site uses the same canonical predicate rather than locally re-deriving it from
Configuration, capability helpers, or form-factor flags. - Ad-hoc keyboard/desktop signalsFlag any use of
Configuration.keyboard/KEYBOARD_QWERTYorOmniboxCapabilities.hasDesktopExperience()as a proxy for keyboard availability and migrate it toDeviceInput.supportsAlphabeticKeyboard(), checking that the two are not silently assumed equivalent. - NTP prefocus and focus-state pathsAudit all callers of
showUrlBarCursorWithoutFocusAnimations()and the NTP-load/URL-load handlers to ensure the focus-set and focus-clear branches stay mutually consistent across tablet, desktop-windowing, and phone form factors.
Patch
From 9c6700ed12a5ce0e3c43536be563403702493838 Mon Sep 17 00:00:00 2001 From: Tomasz Wiszkowski <[email protected]> Date: Tue, 25 Aug 2026 16:44:56 -0700 Subject: [PATCH] Use consistent signaling to prefocus Omnibox. Change-Id: Icb1228c6ba5e72dd41c9da0f6c2f5cb90ef95a79 Fixed: 514012689 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8286325 Auto-Submit: Tomasz Wiszkowski <[email protected]> Reviewed-by: Patrick Noland <[email protected]> Cr-Commit-Position: refs/heads/main@{#1686027} --- diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java index 64f10dc..c2a18c8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java @@ -272,6 +272,7 @@ import org.chromium.ui.base.ActivityWindowAndroid; import org.chromium.ui.base.BackGestureEventSwipeEdge; import org.chromium.ui.base.DeviceFormFactor; +import org.chromium.ui.base.DeviceInput; import org.chromium.ui.base.WindowAndroid; import org.chromium.ui.display.DisplayUtil; import org.chromium.ui.modaldialog.ModalDialogManager; @@ -3754,7 +3755,7 @@ if (!mIsTablet) return; if (!UrlUtilities.isNtpUrl(mLocationBarModel.getCurrentGurl())) return; - if (mActivity.getResources().getConfiguration().keyboard == Configuration.KEYBOARD_QWERTY) { + if (DeviceInput.supportsAlphabeticKeyboard()) { mLocationBar.showUrlBarCursorWithoutFocusAnimations(); } } diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.java index b0ebb6d..309188ea 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.java @@ -144,6 +144,7 @@ import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.common.ResourceRequestBody; import org.chromium.ui.base.DeviceFormFactor; +import org.chromium.ui.base.DeviceInput; import org.chromium.ui.base.KeyNavigationUtil; import org.chromium.ui.base.PageTransition; import org.chromium.ui.base.WindowAndroid; @@ -823,7 +824,7 @@ // While a hardware keyboard is connected, loading the NTP should cause the URL bar to gain // focus with a blinking cursor and without focus animations. Loading a non-NTP URL should // clear such focus if it exists. - if (OmniboxCapabilities.hasDesktopExperience(mContext)) { + if (DeviceInput.supportsAlphabeticKeyboard()) { if (onNtp) { showUrlBarCursorWithoutFocusAnimations(); } else { diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/DEPS b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/DEPS index ba8ace8..2f0ddab6 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/DEPS +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/DEPS @@ -20,7 +20,7 @@ "+components/browser_ui/bottomsheet/android/java", "+components/browser_ui/desktop_windowing/android", "+components/browser_ui/device_lock/android/java", - "+components/omnibox/browser", + "+components/omnibox", "+content/public/android/java/src/org/chromium/content_public", ]