Overview

Medium
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUse after free in Omnibox
DescriptionUse after free in Omnibox
ComponentOmnibox
Bug ClassUAF
Tracker502449864
Fix commit4d9007792d4a (chromium/src) +66/-4
CISA KEVNot listed
Creditedgevakun
Disclosed2026-06-02

Changed Functions

FunctionChangeNotes
if
chrome/browser/ui/webui/cr_components/searchbox/contextual_searchbox_handler.cc
modified

Files Changed

  • chrome/browser/ui/webui/cr_components/searchbox/contextual_searchbox_handler.cc
  • chrome/browser/ui/webui/cr_components/searchbox/contextual_searchbox_handler.h
  • chrome/browser/ui/webui/omnibox_popup/omnibox_popup_web_contents_helper.cc
  • chrome/browser/ui/webui/searchbox/webui_omnibox_handler.cc
  • chrome/browser/ui/webui/searchbox/webui_omnibox_handler.h
From 4d9007792d4ad8ba545ee28c2978a0aebcbfd2d0 Mon Sep 17 00:00:00 2001
From: Orin Jaworski <orinj@chromium.org>
Date: Thu, 16 Apr 2026 12:10:07 -0700
Subject: [PATCH] [omnibox] Reconnect OmniboxController etc. after tab changes windows

This CL fixes UAF crash and other issues caused by the webui omnibox
remaining connected to its original window after its tab is
moved to a different window. This applies to webui omniboxes
in tabs, chrome://omnibox-popup.top-chrome/ . It was previously
possible to move the tab to a different window and then see
autocomplete suggestions for input to the original window's
omnibox, which wasn't right. Now it stays connected only to the
current browser window, as expected.

Fixed: 502449864
Change-Id: I15475b487431a61d7278b92f72a17d91b636e147
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7766130
Reviewed-by: Ananya Seelam <ananyaseelam@google.com>
Commit-Queue: Orin Jaworski <orinj@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1616041}
---

diff --git a/chrome/browser/ui/webui/cr_components/searchbox/contextual_searchbox_handler.cc b/chrome/browser/ui/webui/cr_components/searchbox/contextual_searchbox_handler.cc
index 26e793f9..68b5bd4 100644
--- a/chrome/browser/ui/webui/cr_components/searchbox/contextual_searchbox_handler.cc
+++ b/chrome/browser/ui/webui/cr_components/searchbox/contextual_searchbox_handler.cc
@@ -315,6 +315,14 @@
   }
 }
 
+void ContextualSearchboxHandler::UpdateTabListObservation(
+    TabListInterface* tab_list) {
+  tab_list_observation_.Reset();
+  if (tab_list) {
+    tab_list_observation_.Observe(tab_list);
+  }
+}
+
 void ContextualSearchboxHandler::OnTabAdded(TabListInterface& tab_list,
                                             tabs::TabInterface* tab,
                                             int index) {
diff --git a/chrome/browser/ui/webui/cr_components/searchbox/contextual_searchbox_handler.h b/chrome/browser/ui/webui/cr_components/searchbox/contextual_searchbox_handler.h
index e763b639..8b55be26 100644
--- a/chrome/browser/ui/webui/cr_components/searchbox/contextual_searchbox_handler.h
+++ b/chrome/browser/ui/webui/cr_components/searchbox/contextual_searchbox_handler.h
@@ -281,6 +281,8 @@
 
   virtual void InitializeInputStateModel();
 
+  void UpdateTabListObservation(TabListInterface* tab_list);
+
   std::unique_ptr<contextual_search::InputStateModel> input_state_model_;
 
   void OnInputStateChanged(const contextual_search::InputState& state);
diff --git a/chrome/browser/ui/webui/omnibox_popup/omnibox_popup_web_contents_helper.cc b/chrome/browser/ui/webui/omnibox_popup/omnibox_popup_web_contents_helper.cc
index 247a6fc..7c9fbcfd 100644
--- a/chrome/browser/ui/webui/omnibox_popup/omnibox_popup_web_contents_helper.cc
+++ b/chrome/browser/ui/webui/omnibox_popup/omnibox_popup_web_contents_helper.cc
@@ -6,6 +6,7 @@
 
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/browser_window/public/browser_window_features.h"
 #include "chrome/browser/ui/browser_window/public/browser_window_interface.h"
 #include "chrome/browser/ui/location_bar/location_bar.h"
 
@@ -17,10 +18,9 @@
   // on the current browser window, and make it available to the OmniboxPopupUI.
   if (BrowserWindowInterface* browser =
           chrome::FindBrowserWithTab(web_contents)) {
-    set_omnibox_controller(browser->GetBrowserForMigrationOnly()
-                               ->window()
-                               ->GetLocationBar()
-                               ->GetOmniboxController());
+    if (auto* location_bar = browser->GetFeatures().location_bar()) {
+      set_omnibox_controller(location_bar->GetOmniboxController());
+    }
   }
 }
 
diff --git a/chrome/browser/ui/webui/searchbox/webui_omnibox_handler.cc b/chrome/browser/ui/webui/searchbox/webui_omnibox_handler.cc
index bae92e8..0ad79fa9 100644
--- a/chrome/browser/ui/webui/searchbox/webui_omnibox_handler.cc
+++ b/chrome/browser/ui/webui/searchbox/webui_omnibox_handler.cc
@@ -14,10 +14,13 @@
 #include "chrome/browser/autocomplete/aim_eligibility_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/bookmarks/bookmark_stats.h"
+#include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/browser_window/public/browser_window_features.h"
 #include "chrome/browser/ui/browser_window/public/browser_window_interface.h"
 #include "chrome/browser/ui/contextual_search/searchbox_context_data.h"
+#include "chrome/browser/ui/location_bar/location_bar.h"
 #include "chrome/browser/ui/omnibox/omnibox_controller.h"
 #include "chrome/browser/ui/omnibox/omnibox_edit_model.h"
 #include "chrome/browser/ui/omnibox/omnibox_next_features.h"
@@ -31,6 +34,7 @@
 #include "chrome/browser/ui/webui/cr_components/searchbox/searchbox_omnibox_client.h"
 #include "chrome/browser/ui/webui/metrics_reporter/metrics_reporter.h"
 #include "chrome/browser/ui/webui/omnibox_popup/omnibox_popup_ui.h"
+#include "chrome/browser/ui/webui/omnibox_popup/omnibox_popup_web_contents_helper.h"
 #include "chrome/browser/ui/webui/webui_embedding_context.h"
 #include "chrome/grit/new_tab_page_resources.h"
 #include "components/contextual_search/contextual_search_service.h"
@@ -57,6 +61,7 @@
 #include "components/profile_metrics/browser_profile_type.h"
 #include "components/search_engines/template_url_service.h"
 #include "components/strings/grit/components_strings.h"
+#include "components/tabs/public/tab_interface.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/web_contents.h"
 #include "net/cookies/cookie_util.h"
@@ -130,6 +135,14 @@
       base::BindRepeating(&WebuiOmniboxHandler::OnContentSharingPolicyChanged,
                           base::Unretained(this)));
 
+  if (tabs::TabInterface* tab =
+          tabs::TabInterface::MaybeGetFromContents(web_ui->GetWebContents())) {
+    tab_will_detach_subscription_ = tab->RegisterWillDetach(base::BindRepeating(
+        &WebuiOmniboxHandler::OnTabWillDetach, base::Unretained(this)));
+    tab_did_insert_subscription_ = tab->RegisterDidInsert(base::BindRepeating(
+        &WebuiOmniboxHandler::OnTabDidInsert, base::Unretained(this)));
+  }
+
   OnAimPopupEligibilityChanged();
   OnContentSharingPolicyChanged();
 }
@@ -391,6 +404,36 @@
   ContextualSearchboxHandler::OnActiveTabChanged(tab_list, tab);
 }
 
+void WebuiOmniboxHandler::OnTabWillDetach(
+    tabs::TabInterface* tab,
+    tabs::TabInterface::DetachReason reason) {
+  edit_model_observation_.Reset();
+  autocomplete_controller_observation_.Reset();
+  controller_ = nullptr;
+  UpdateTabListObservation(nullptr);
+}
+
+void WebuiOmniboxHandler::OnTabDidInsert(tabs::TabInterface* tab) {
+  if (auto* browser_window_interface = tab->GetBrowserWindowInterface()) {
+    if (auto* location_bar =
+            browser_window_interface->GetFeatures().location_bar()) {
+      if (auto* omnibox_controller = location_bar->GetOmniboxController()) {
+        edit_model_observation_.Reset();
+        autocomplete_controller_observation_.Reset();
+        controller_ = omnibox_controller;
+        autocomplete_controller_observation_.Observe(autocomplete_controller());
+        edit_model_observation_.Observe(omnibox_controller->edit_model());
+        if (auto* helper = OmniboxPopupWebContentsHelper::FromWebContents(
+                web_contents_.get())) {
+          helper->set_omnibox_controller(omnibox_controller);
+        }
+        UpdateTabListObservation(
+            TabListInterface::From(browser_window_interface));
+      }
+    }
+  }
+}
+
 WebuiOmniboxHandler::WebContentsObserver::WebContentsObserver(
     WebuiOmniboxHandler* handler,
     content::WebContents* web_contents)
diff --git a/chrome/browser/ui/webui/searchbox/webui_omnibox_handler.h b/chrome/browser/ui/webui/searchbox/webui_omnibox_handler.h
index d56cae2..bd5a5d94 100644
--- a/chrome/browser/ui/webui/searchbox/webui_omnibox_handler.h
+++ b/chrome/browser/ui/webui/searchbox/webui_omnibox_handler.h
@@ -92,6 +92,13 @@
                           tabs::TabInterface* tab) override;
 
  private:
+  // When the omnibox is hosted in a tab, e.g. for debug, it must remain
+  // connected with the host window's OmniboxController. These methods
+  // support disconnect and reconnect as the window changes to avoid UAF.
+  void OnTabWillDetach(tabs::TabInterface* tab,
+                       tabs::TabInterface::DetachReason reason);
+  void OnTabDidInsert(tabs::TabInterface* tab);
+
   // Delegate to observe WebContents.
   // Managed as a separate class to prevent member naming conflicts
   // of `web_contents_` with a member of the same name in `SearchboxHandler`.
@@ -123,6 +130,8 @@
 
   PrefChangeRegistrar pref_change_registrar_;
   base::CallbackListSubscription aim_eligibility_subscription_;
+  base::CallbackListSubscription tab_will_detach_subscription_;
+  base::CallbackListSubscription tab_did_insert_subscription_;
 
   raw_ptr<MetricsReporter> metrics_reporter_;
 
Loading diff…

Original Bug Report

reported by ge...@gmail.com

Heap UAF in WebuiOmniboxHandler


VULNERABILITY DETAILS

The bug is a heap use-after-free that triggers when chrome://omnibox-popup.top-chrome/ is opened as a tab and then moved to a new window. The popup listens to omnibox data from its host window, but when you drag it out, the original window goes empty and gets destroyed, freeing that data without notifying the handler. The next time the moved tab refreshes, closes, or navigates, the cleanup code tries to unregister itself and reads freed memory.

I also tested whether the bug could be reached without loading chrome://omnibox-popup.top-chrome as a tab. For example, by opening the “+” popup (when type something in the address bar) and then closing the window or dragging a tab. Unfortunately those step do not reproduce the crash, the overlay popup widget dismisses synchronously on any focus loss, so the handler is always destroyed while the browser window’s omnibox data is still alive.


VERSION

Chrome Version: 149.0.7792.0 (Developer Build) (64-bit)

Operating System: Ubuntu 24.04


REPRODUCTION CASE

  1. ./chrome –no-sandbox –enable-features=WebUIOmniboxPopup or ./chrome –no-sandbox –enable-features=WebUIOmniboxAimPopup
  2. Open chrome://omnibox-popup.top-chrome/in the first window (Window A).
  3. Open new window (Window B).
  4. Drag the chrome://omnibox-popup.top-chrome/ tab from Window A’s tab into Window B’s.
  5. In Window B, refresh the chrome://omnibox-popup.top-chrome/ tab.

FOR CRASHES, PLEASE INCLUDE THE FOLLOWING ADDITIONAL INFORMATION

Type of crash: Browser process.

Crash State:

  • asan-s1-uaf.txt = primary scenario, clean heap-use-after-free with complete freed-by and allocated-by stacks.

  • asan-s2-hbo.txt = identical bug after normal user activity between the free and the read, ASAN reclassifies the access as heap-buffer-overflow

Client ID (if relevant): N/A


CREDIT INFORMATION

Reporter credit: gevakun

View on issue tracker