CVE-2026-14096
Overview
Files Changed
content/public/android/java/src/org/chromium/content/browser/input/SelectPopup.java
Patch
From 9a8c4e20c3576a4b102a884b23edcda93eb3f03b Mon Sep 17 00:00:00 2001
From: Bo Liu <boliu@chromium.org>
Date: Mon, 18 May 2026 14:55:52 -0700
Subject: [PATCH] android: Dismiss <select> pop up on window change
Bug: 513310821
Change-Id: I9b7400d1e933e0ab5d46814a5068865bc133b9e3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7857150
Auto-Submit: Bo Liu <boliu@chromium.org>
Reviewed-by: Jinsuk Kim <jinsukkim@chromium.org>
Commit-Queue: Jinsuk Kim <jinsukkim@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1632422}
---
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/SelectPopup.java b/content/public/android/java/src/org/chromium/content/browser/input/SelectPopup.java
index 7367db8..3bd6d7d 100644
--- a/content/public/android/java/src/org/chromium/content/browser/input/SelectPopup.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/SelectPopup.java
@@ -96,11 +96,6 @@
WindowEventObserverManager.from(mWebContents).addObserver(this);
}
- /** Close popup. Called when {@link WindowAndroid} is updated. */
- public void close() {
- mPopupView = null;
- }
-
// HideablePopup
@Override
@@ -122,7 +117,10 @@
@Override
public void onWindowAndroidChanged(@Nullable WindowAndroid windowAndroid) {
- close();
+ if (mPopupView == null) return;
+ mPopupView.hide(true);
+ mPopupView = null;
+ assert mNativeSelectPopupSourceFrame == 0;
}
/**
Original Bug Report
Potential Browser Crash or Cross-Origin Selection Leak via Orphaned SelectPopup on Android
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 without the Chrome Security team. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.
Overview: A logic flaw in the Android implementation of <select> popups allows UI dialogs to remain active after their internal references are cleared in the browser process. This creates ‘zombie’ dialogs that can be exploited by a compromised renderer to intercept user selections from other origins or trigger a browser process crash.
Affected files:
content/public/android/java/src/org/chromium/content/browser/input/SelectPopup.javacontent/browser/android/select_popup.cccontent/public/android/java/src/org/chromium/content/browser/input/SelectPopupDialog.java
Estimated timestamp from git blame: 2018-03-02
Analysis
In the Android implementation of selection popups, a logic error in content/public/android/java/src/org/chromium/content/browser/input/SelectPopup.java allows UI components to become ‘orphaned’ from their controlling logic. Specifically, the close() method, which is triggered during window-level changes (such as dragging a tab to a new window in multi-window mode), clears the internal reference to the popup UI without actually dismissing it:
// content/public/android/java/src/org/chromium/content/browser/input/SelectPopup.java
public void close() {
mPopupView = null; // Logic flaw: The UI remains visible and interactive
}
When a dialog is orphaned in this manner, it remains interactive on the screen. Because mPopupView is now null, subsequent cleanup attempts via hideWithoutCancel() fail due to an early return:
public void hideWithoutCancel() {
if (mPopupView == null) return; // Cleanup is bypassed for zombie dialogs
mPopupView.hide(false);
mPopupView = null;
mNativeSelectPopupSourceFrame = 0;
}
This leaves the system in an inconsistent state where a visible ‘zombie’ dialog is still associated with the mNativeSelectPopupSourceFrame (a raw pointer used to identify the target renderer client).
Potential Security Impact
An attacker who has compromised a renderer process (e.g., via a separate V8 vulnerability) can exploit this state inconsistency in a cross-origin iframe within the same tab:
- Cross-Origin Information Leak: The attacker triggers their own
<select>menu in an OOPIF. This updates the sharedmNativeSelectPopupSourceFrameto point to the attacker’s renderer. If the user then interacts with the victim’s zombie dialog (which may still be visible in another window or underlying UI layer), the selection indices are dispatched to the attacker’s renderer. This allows an attacker to intercept user selections from a different origin. - Browser Process Denial of Service (DoS): If an attacker triggers a popup and then immediately disconnects their client (e.g., via navigation), the native
popup_client_remote is reset. If the user subsequently interacts with a zombie dialog, the nativeSelectMenuItemsfunction may attempt to call methods on the unbound Mojo remote, potentially leading to a browser process crash.
Suggested Reproduction Steps
Note: These steps are based on code analysis and have not been verified with a functional exploit.
- Navigate to a page (the victim) containing a
<select>menu and an embedded cross-origin iframe (the attacker). - Open the
<select>menu on the victim page. - Trigger
SelectPopup.close()by moving the tab to a new window using Android’s multi-window dragging feature. - Confirm that the selection menu remains visible despite the window transition.
- From the attacker iframe, trigger a new selection popup or navigate the iframe to reset the popup client.
- Interact with the original victim selection menu.
- Observe whether selection data is leaked to the attacker’s context or if the browser process terminates unexpectedly.
Suggested Fix
Ensure that SelectPopup.close() explicitly dismisses the UI before clearing the reference. The cleanup logic should be consolidated to ensure that mNativeSelectPopupSourceFrame is always reset when a popup is dismissed or closed:
public void close() {
if (mPopupView != null) {
mPopupView.hide(false);
mPopupView = null;
}
mNativeSelectPopupSourceFrame = 0;
}
Evaluated with Chrome root at commit: b3153093eb3c78c3e88ccf562bcbc20437a04b0e
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.