Overview

Low
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactObject lifecycle issue in Input
DescriptionObject lifecycle issue in Input
ComponentInput
Bug ClassLogic Error
Tracker513310821
Fix commit9a8c4e20c357 (chromium/src) +4/-6
CISA KEVNot listed
CreditedGoogle
Disclosed2026-06-30

Files Changed

  • content/public/android/java/src/org/chromium/content/browser/input/SelectPopup.java
From 9a8c4e20c3576a4b102a884b23edcda93eb3f03b Mon Sep 17 00:00:00 2001
From: Bo Liu <[email protected]>
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 <[email protected]>
Reviewed-by: Jinsuk Kim <[email protected]>
Commit-Queue: Jinsuk Kim <[email protected]>
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;
     }
 
     /**
Loading diff…

Original Bug Report

reported by [email protected]

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.java
  • content/browser/android/select_popup.cc
  • content/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:

  1. Cross-Origin Information Leak: The attacker triggers their own <select> menu in an OOPIF. This updates the shared mNativeSelectPopupSourceFrame to 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.
  2. 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 native SelectMenuItems function 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.

  1. Navigate to a page (the victim) containing a <select> menu and an embedded cross-origin iframe (the attacker).
  2. Open the <select> menu on the victim page.
  3. Trigger SelectPopup.close() by moving the tab to a new window using Android’s multi-window dragging feature.
  4. Confirm that the selection menu remains visible despite the window transition.
  5. From the attacker iframe, trigger a new selection popup or navigate the iframe to reset the popup client.
  6. Interact with the original victim selection menu.
  7. 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.

View on issue tracker