CVE-2026-17980
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifcontent/browser/android/selection/selection_popup_controller.cc |
modified |
Files Changed
content/browser/android/selection/selection_popup_controller.cccontent/public/android/java/src/org/chromium/content/browser/input/ImeAdapterImpl.java
Patch
From f0e142a719fd48c201eb5bd976a13f0944591f62 Mon Sep 17 00:00:00 2001 From: Yaron Friedman <[email protected]> Date: Thu, 04 Jun 2026 11:36:30 -0700 Subject: [PATCH] Android: Fix selection menu password exposure (b/519710361) When a password field is toggled to text, it becomes type="text" but still contains sensitive data. We should not show ACTION_PROCESS_TEXT handlers for it. This CL checks the HAS_BEEN_PASSWORD_FIELD and HAS_BEEN_CUSTOM_PASSWORD flags in both IME (Java) and Selection (C++) layers to force the password state to true if the field has ever been a password. Bug: 519710361 Change-Id: I86e58ac46a7fb26d90be65aa745e877f58b85793 Fixed: 519710361 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7903878 Reviewed-by: Ted Choc <[email protected]> Commit-Queue: Yaron Friedman <[email protected]> Cr-Commit-Position: refs/heads/main@{#1641829} --- diff --git a/content/browser/android/selection/selection_popup_controller.cc b/content/browser/android/selection/selection_popup_controller.cc index fefd6ea..b846c7e1 100644 --- a/content/browser/android/selection/selection_popup_controller.cc +++ b/content/browser/android/selection/selection_popup_controller.cc @@ -12,6 +12,7 @@ #include "base/feature_list.h" #include "content/browser/android/selection/composited_touch_handle_drawable.h" #include "content/browser/renderer_host/render_widget_host_view_android.h" +#include "content/browser/renderer_host/text_input_manager.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/browser/web_contents/web_contents_view_android.h" #include "content/common/features.h" @@ -21,6 +22,7 @@ #include "third_party/blink/public/common/context_menu_data/edit_flags.h" #include "third_party/blink/public/mojom/context_menu/context_menu.mojom.h" #include "third_party/blink/public/mojom/input/input_handler.mojom.h" +#include "ui/base/ime/text_input_flags.h" #include "ui/base/models/menu_model.h" #include "ui/base/mojom/menu_source_type.mojom.h" #include "ui/gfx/android/android_surface_control_compat.h" @@ -300,8 +302,20 @@ !!(params.edit_flags & blink::ContextMenuDataEditFlags::kCanSelectAll); const bool can_edit_richly = !!(params.edit_flags & blink::ContextMenuDataEditFlags::kCanEditRichly); - const bool is_password_type = + bool is_password_type = params.form_control_type == blink::mojom::FormControlType::kInputPassword; + if (rwhva_) { + TextInputManager* text_input_manager = rwhva_->GetTextInputManager(); + if (text_input_manager) { + const ui::mojom::TextInputState* state = + text_input_manager->GetTextInputState(); + if (state && + (state->flags & (ui::TEXT_INPUT_FLAG_HAS_BEEN_PASSWORD | + ui::TEXT_INPUT_FLAG_HAS_BEEN_CUSTOM_PASSWORD))) { + is_password_type = true; + } + } + } const ScopedJavaLocalRef<jstring> jselected_text = ConvertUTF16ToJavaString(env, params.selection_text); const bool should_suggest = 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 0fb1507..c0ba05bc3 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 @@ -64,6 +64,7 @@ import org.chromium.blink.mojom.InputCursorAnchorInfo; import org.chromium.blink.mojom.StylusWritingGestureData; import org.chromium.blink_public.web.WebInputEventModifier; +import org.chromium.blink_public.web.WebTextInputFlags; import org.chromium.blink_public.web.WebTextInputMode; import org.chromium.build.annotations.NullMarked; import org.chromium.build.annotations.Nullable; @@ -796,7 +797,10 @@ } boolean editable = focusedNodeEditable(); - boolean password = textInputType == TextInputType.PASSWORD; + boolean password = + textInputType == TextInputType.PASSWORD + || (textInputFlags & WebTextInputFlags.HAS_BEEN_PASSWORD_FIELD) != 0 + || (textInputFlags & WebTextInputFlags.HAS_BEEN_CUSTOM_PASSWORD) != 0; updateNodeAttributes(editable, password); if (mCursorAnchorInfoController != null && (!TextUtils.equals(mLastText, text)
Original Bug Report
Potential Android selection menu password exposure to third-party ACTION_PROCESS_TEXT handlers
Project Fortify, an experimental security project, has identified the following potential security issue. If you’re a feature owner CC-ed on this bug, please do your best to review these reports. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.
Overview: The Android selection popup controller fails to check the sticky HAS_BEEN_PASSWORD flag when evaluating if a text selection is in a password field. If a user toggles a password field’s visibility to plaintext and selects it, the plaintext credential is exposed to third-party ACTION_PROCESS_TEXT intent handlers. This bypasses Chrome’s security gate designed to keep sensitive credential selections isolated.
Affected files:
content/browser/android/selection/selection_popup_controller.cccontent/public/android/java/src/org/chromium/content/browser/selection/SelectionPopupControllerImpl.javacontent/public/android/java/src/org/chromium/content/browser/input/ImeAdapterImpl.javacontent/public/android/java/src/org/chromium/content/browser/selection/SelectActionMenuHelper.java
Estimated timestamp from git blame: 2015-09-25
Potential Vulnerability: Plaintext Password Exposure to Third-Party Android Handlers
Root Cause
The Android selection menu controller derives its password classification state solely from the active/current input element type, ignoring the sticky has-been-password flag (WebTextInputFlags.HAS_BEEN_PASSWORD_FIELD) propagated by Blink. Because of this, when a password field is revealed to plaintext (a common UX design pattern on login pages), both the native and Java layers of Chrome treat the field selection as ordinary text.
There are two main propagation sites where this occurs:
-
Native (selection_popup_controller.cc):
const bool is_password_type = params.form_control_type == blink::mojom::FormControlType::kInputPassword;is_password_typeevaluates tofalsewhen the input type changes totext. -
Java (ImeAdapterImpl.java):
boolean password = textInputType == TextInputType.PASSWORD; // mTextInputFlags is ignored here updateNodeAttributes(editable, password);passwordevaluates tofalsewhen the input type becomesTextInputType.TEXT.
Because the popup controller determines isSelectionPassword is false, it allows SelectActionMenuHelper.getTextProcessingItems() to query and show registered third-party ACTION_PROCESS_TEXT handlers in the selection popup menu. When the user taps one of these items, Chrome sends the raw selected plaintext password in the EXTRA_PROCESS_TEXT intent extra to the target third-party application.
Note: These are suggested/potential steps and analysis; our current tooling agent does not have the ability to run code or compile a working proof-of-concept.
Potential Trigger Steps
- An Android device has a third-party application installed that declares an
<intent-filter>forandroid.intent.action.PROCESS_TEXTwith mimeTypetext/plain. - The user navigates to a login page containing a password field with a show/hide toggle in Chrome for Android.
- The user types their credential, then taps the visibility toggle to show the plaintext password.
- The user long-presses to select the revealed password text.
- The custom selection menu appears, exposing third-party application options (which would otherwise be suppressed if the field were recognized as having been a password field).
- The user taps the third-party application’s action. The external application receives the plaintext password via the
ACTION_PROCESS_TEXTintent.
Suggested Fix
Update both the native and Java state-propagation logic to consult the sticky has-been-password bit:
- In
ImeAdapterImpl.java:boolean password = textInputType == TextInputType.PASSWORD || (mTextInputFlags & WebTextInputFlags.HAS_BEEN_PASSWORD_FIELD) != 0; - In
selection_popup_controller.cc, retrieve and consult the state of the active input’s has-been-password flag (which is already tracked in Blink) to correctly markis_password_typeas true if the field has ever been a password field.
Evaluated with Chrome root at commit: 9ebf4302210513a012c901d87a2668b3aadf8cc1
Results so far have been promising, but there can be wrong deductions. Feel free to adjust as follows:
- If you are familiar with the severity guidelines, you may adjust the severity.
- If this is a false positive, and there’s no work to be done, please close as WAI.
- If there is work to do here but not a vulnerability, please change the issue type to Task/Bug/FR.
Data from false positives will be used to improve accuracy over time. And please feel free to reach out to me directly if you have concerns or feedback on the project.