Chrome · Input
CVE-2026-14140
Logic Error in Input
Overview
Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifcontent/public/android/java/src/org/chromium/content/browser/input/ImeAdapterImpl.java |
modified |
Files Changed
content/public/android/java/src/org/chromium/content/browser/input/ImeAdapterImpl.java
Patch
From c03d94e511860de8f90c092b28d7253f72a35dac Mon Sep 17 00:00:00 2001
From: Aaron Moss <aaronmoss@google.com>
Date: Thu, 28 May 2026 15:30:27 -0700
Subject: [PATCH] [a11y] Clamp cursor-following to viewport
Ensure that cursor-following cannot be used to scroll outside the
WebView.
Bug: 514072607
Change-Id: I82729ae0837f12f91620adc599c3eff86ff9ef3d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7859114
Reviewed-by: Bo Liu <boliu@chromium.org>
Commit-Queue: Aaron Moss <aaronmoss@google.com>
Cr-Commit-Position: refs/heads/main@{#1638003}
---
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapterImpl.java b/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapterImpl.java
index 17ade2a..4adbbbe6 100644
--- a/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapterImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapterImpl.java
@@ -1593,8 +1593,10 @@
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA
&& Build.VERSION.SDK_INT_FULL >= Build.VERSION_CODES_FULL.BAKLAVA_1
&& ContentFeatureList.sAccessibilityMagnificationFollowsFocus.isEnabled()) {
- Rect nodePix = fromCssToDevicePix(nodeLeftDip, nodeTopDip, nodeRightDip, nodeBottomDip);
- if (!nodePix.isEmpty()) {
+ Rect nodePix =
+ fromViewportDipToViewContentPix(
+ nodeLeftDip, nodeTopDip, nodeRightDip, nodeBottomDip, containerView);
+ if (nodePix != null && !nodePix.isEmpty()) {
containerView.requestRectangleOnScreen(
nodePix,
/* immediate= */ false,
@@ -1768,23 +1770,49 @@
}
/**
- * Converts bounds from CSS pixels to device pixels, accounting for page scale, device scale,
- * and content Y offset.
+ * Converts bounds from device-independent pixels in viewport space to device pixels in
+ * view-content space, clamped to the visible rectangle of the container view.
*
- * @param left left X coordinate in CSS pixels
- * @param top top Y coordinate in CSS pixels
- * @param right right X coordinate in CSS pixels
- * @param bottom bottom Y coordinate in CSS pixels
- * @return {@link Rect} with the device pixel equivalents of the provided coordinates.
+ * @param left left X coordinate in Blink viewport-relative DIPs
+ * @param top top Y coordinate in Blink viewport-relative DIPs
+ * @param right right X coordinate in Blink viewport-relative DIPs
+ * @param bottom bottom Y coordinate in Blink viewport-relative DIPs
+ * @param containerView view to clamp coordinates to
+ * @return {@link Rect} with the device pixel equivalents of the provided coordinates in
+ * view-content space, clamped to the visible portion of the container view, or null if the
+ * bounds do not intersect the visible portion of the container view.
*/
- private Rect fromCssToDevicePix(float left, float top, float right, float bottom) {
+ private @Nullable Rect fromViewportDipToViewContentPix(
+ float left, float top, float right, float bottom, View containerView) {
+ // Get container view's visible area in view-content coordinates.
+ // Chrome team trial-and-error has determined that (inconsistently with other View
+ // documentation), "top left" in the View#getLocalVisibleRect is in content space rather
+ // than viewport space for the view.
+ Rect visibleRect = new Rect();
+ if (!containerView.getLocalVisibleRect(visibleRect)) {
+ return null; // The container is entirely offscreen.
+ }
+
+ // Scale bounds to device pixels in Android view coordinates.
RenderCoordinatesImpl coords = mWebContents.getRenderCoordinates();
- final int topOffset = coords.getContentOffsetYPixInt();
- return new Rect(
- (int) coords.fromLocalCssToPix(left),
- ((int) coords.fromLocalCssToPix(top)) + topOffset,
- (int) coords.fromLocalCssToPix(right),
- ((int) coords.fromLocalCssToPix(bottom)) + topOffset);
+ final int topOffset = coords.getContentOffsetYPixInt(); // Offset for Chrome address bar.
+ final float scale = coords.getDeviceScaleFactor();
+ Rect bounds =
+ new Rect(
+ (int) (left * scale),
+ (int) (top * scale) + topOffset,
+ (int) (right * scale),
+ (int) (bottom * scale) + topOffset);
+
+ // Translate bounds to view-content coordinates by adding Android view scroll. This is a
+ // no-op for Chrome (which always reports zero scroll), but will adjust for WebView scroll.
+ bounds.offset(containerView.getScrollX(), containerView.getScrollY());
+
+ // Clamp to visible area and return clamped bounds in view-content coordinates.
+ if (!bounds.intersect(visibleRect)) {
+ return null; // The bounds are entirely offscreen.
+ }
+ return bounds;
}
/**
@@ -1810,23 +1838,26 @@
// Convert caret bounds from CSS pixels to device pixels relative to root view.
var caretCss = cursorAnchorInfo.insertionMarker;
Rect caretPix =
- fromCssToDevicePix(
+ fromViewportDipToViewContentPix(
caretCss.x,
caretCss.y,
caretCss.x + caretCss.width,
- caretCss.y + caretCss.height);
+ caretCss.y + caretCss.height,
+ containerView);
- // Note: `SDK_INT_FULL` added in `BAKLAVA`, hence two checks.
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA
- && Build.VERSION.SDK_INT_FULL >= Build.VERSION_CODES_FULL.BAKLAVA_1) {
- containerView.requestRectangleOnScreen(
- caretPix,
- /* immediate= */ false,
- View.RECTANGLE_ON_SCREEN_REQUEST_SOURCE_TEXT_CURSOR);
- } else {
- // Fallback to previous API (where `requestRectangleOnScreen()` calls are assumed
- // to come from text cursor moves).
- containerView.requestRectangleOnScreen(caretPix);
+ if (caretPix != null) {
+ // Note: `SDK_INT_FULL` added in `BAKLAVA`, hence two checks.
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA
+ && Build.VERSION.SDK_INT_FULL >= Build.VERSION_CODES_FULL.BAKLAVA_1) {
+ containerView.requestRectangleOnScreen(
+ caretPix,
+ /* immediate= */ false,
+ View.RECTANGLE_ON_SCREEN_REQUEST_SOURCE_TEXT_CURSOR);
+ } else {
+ // Fallback to previous API (where `requestRectangleOnScreen()` calls are
+ // assumed to come from text cursor moves).
+ containerView.requestRectangleOnScreen(caretPix);
+ }
}
}
}
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