High chrome UAF 🔧 Commit mapped

Overview

High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactImproper input validation in ReadingList
DescriptionImproper input validation in ReadingList
ComponentReadingList
Bug ClassUAF
Tracker573389782
Fix commit3f44a926056f (chromium/src) +8/-4
CISA KEVNot listed
Creditedmalichamdan
Disclosed2026-10-27

Background

Reading List side panel
a WebUI surface (chrome/browser/ui/webui/side_panel/reading_list/) backed by ReadingListPageHandler, which handles browser-side actions for the panel (mark as read, add tab, show context menu).
`views::MenuRunner` / `ui::MenuModel`
a MenuRunner runs a context menu and holds a raw_ptr to the MenuModel it is showing; the model must outlive the runner, and the runner must not keep pointing at a model that is being replaced/freed.
`SidePanelWebUIView`
the view hosting the WebUI; it owns both context_menu_model_ and context_menu_runner_ and builds a new runner each time a context menu is shown.
`GetLastActiveBrowser()`
GlobalBrowserCollection::GetInstance()->GetLastActiveBrowser() returns whatever browser was last active globally, which may be a different window than the one hosting this panel (or none).
`webui::GetBrowserWindowInterface(web_contents())`
resolves the BrowserWindowInterface that actually hosts this WebUI’s web_contents().

Root Cause Analysis

The advisory labels this “Improper input validation in ReadingList” (InputValidation), but the commit title and diff show a use-after-free (plus a related stale/wrong-browser dereference) — no input validation is involved. There are two coupled defects. First, in SidePanelWebUIView::ShowContextMenu(), the code assigned context_menu_model_ = std::move(menu_model) and then rebuilt context_menu_runner_ pointing at the new model. Because views::MenuRunner stores a raw_ptr to the MenuModel, replacing context_menu_model_ while an existing context_menu_runner_ still held a raw_ptr to the old model left that runner dangling; the member declaration order (context_menu_runner_ before context_menu_model_) also made destruction order wrong — the model could be destroyed before the runner that references it. The fix reorders the members so context_menu_model_ is declared before context_menu_runner_ (ensuring the runner is destroyed first) and calls context_menu_runner_.reset() before reassigning context_menu_model_, so no runner ever points at a freed model.

Second, in ReadingListPageHandler, MarkCurrentTabAsRead(), AddCurrentTab(), and the context-menu handler obtained the browser via GlobalBrowserCollection::GetInstance()->GetLastActiveBrowser(). That returns a globally-last-active browser that need not be the one hosting the panel and whose lifetime is not tied to this handler’s web_contents(), so operating through it risks acting on a stale/destroyed browser. The patch replaces those calls with webui::GetBrowserWindowInterface(web_contents()), which resolves the correct hosting browser, and adds a missing if (!browser) return; null-guard in the context-menu path. Together these remove the dangling raw_ptr to a freed MenuModel and the unsafe reliance on a possibly-stale global browser pointer.

Key insight
views::MenuRunner kept a raw_ptr to the previous MenuModel, but ShowContextMenu() replaced the model without resetting the runner (and declared them in an order that destroyed the model first), leaving a dangling pointer — a use-after-free; the fix resets the runner before swapping the model and fixes member order, while also resolving the browser from the panel’s own web_contents() instead of the global last-active browser.

Attack Path

  1. Web/UI attacker drives the Reading List side panel (WebUI) to open context menus; the panel is user-reachable UI, and the renderer side can send the triggering Mojo calls (inferred: reachability via a compromised/misbehaving WebUI renderer or rapid user action).
  2. Open a context menu ShowContextMenu() builds context_menu_model_ and a MenuRunner referencing it.
  3. Re-open before teardown trigger another ShowContextMenu() so context_menu_model_ is reassigned while the prior context_menu_runner_ still holds a raw_ptr to the old model.
  4. Dangling model pointer the old model is freed while a runner (or destruction-ordered member) still references it.
  5. Primitive subsequent use of the MenuRunner’s dangling raw_ptr to the freed MenuModel is a use-after-free in the browser process (freed-memory access; controlled reuse is (inferred)).

Impact Assessment

The UAF is in the privileged browser process, in trusted WebUI handling for the Reading List panel. Reachability requires exercising the side-panel context-menu path (user interaction or renderer-driven Mojo calls), so it is not a drive-by from arbitrary web content but is reachable from the WebUI surface. The diff substantiates a dangling raw_ptr from MenuRunner to a freed MenuModel; raw_ptr under MiraclePtr/BackupRefPtr may convert many such accesses into safe crashes, so whether this yields exploitable corruption versus a guarded crash is (inferred). The companion GetLastActiveBrowser() → GetBrowserWindowInterface() change additionally removes a wrong/stale-browser dereference. This is a lifetime bug, not input validation.

Changed Functions

FunctionChangeNotes
if
chrome/browser/ui/webui/side_panel/reading_list/reading_list_page_handler.cc
modified

Files Changed

  • chrome/browser/ui/views/side_panel/side_panel_web_ui_view.cc
  • chrome/browser/ui/views/side_panel/side_panel_web_ui_view.h
  • chrome/browser/ui/webui/side_panel/reading_list/reading_list_page_handler.cc

Audit Directions

  • `MenuRunner` / `MenuModel` lifetimes
    audit other views that own a MenuRunner and its MenuModel, verifying the runner is reset before the model is replaced and that declaration/destruction order keeps the model alive longer than the runner.
  • `raw_ptr` holders across reassignment
    search for members reassigned while another object holds a raw_ptr to the old value (menus, delegates, observers).
  • `GetLastActiveBrowser()` misuse
    review other WebUI handlers that resolve a browser via the global last-active collection instead of their own web_contents(); these can act on the wrong or destroyed window.
  • Advisory mislabel
    “Improper input validation” misclassifies this UAF; check sibling ReadingList/WebUI CVEs for the same generic tag.
From 3f44a926056f963a4e1b4c3ce51b8347008da4e1 Mon Sep 17 00:00:00 2001
From: Caroline Rising <corising@chromium.org>
Date: Mon, 19 Oct 2026 13:26:15 -0700
Subject: [PATCH] Fix UAF in reading list side panel context menu

Replace GetLastActiveBrowser() calls with
webui::GetBrowserWindowInterface() in ReadingListPageHandler. Move
context_menu_model_ declaration before context_menu_runner_ (and reset
the runner before reassigning the model) because MenuRunner holds a
raw_ptr to MenuModel.

Bug: 573389782
Change-Id: I0a05657421a9a801af8c04bf57048f2375bcfb32
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8611676
Commit-Queue: Caroline Rising <corising@chromium.org>
Reviewed-by: Alison Gale <agale@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1722276}
---
diff --git a/chrome/browser/ui/views/side_panel/side_panel_web_ui_view.cc b/chrome/browser/ui/views/side_panel/side_panel_web_ui_view.cc
index c53051c..8426071 100644
--- a/chrome/browser/ui/views/side_panel/side_panel_web_ui_view.cc
+++ b/chrome/browser/ui/views/side_panel/side_panel_web_ui_view.cc
@@ -116,6 +116,7 @@
     gfx::Point point,
     std::unique_ptr<ui::MenuModel> menu_model) {
   ConvertPointToScreen(this, &point);
+  context_menu_runner_.reset();
   context_menu_model_ = std::move(menu_model);
   context_menu_runner_ = std::make_unique<views::MenuRunner>(
       context_menu_model_.get(),
diff --git a/chrome/browser/ui/views/side_panel/side_panel_web_ui_view.h b/chrome/browser/ui/views/side_panel/side_panel_web_ui_view.h
index fb6bab8..a634928d 100644
--- a/chrome/browser/ui/views/side_panel/side_panel_web_ui_view.h
+++ b/chrome/browser/ui/views/side_panel/side_panel_web_ui_view.h
@@ -65,8 +65,8 @@
   std::unique_ptr<
       performance_manager::PageLiveStateDecorator::ScopedWithheldFromView>
       withheld_from_view_;
-  std::unique_ptr<views::MenuRunner> context_menu_runner_;
   std::unique_ptr<ui::MenuModel> context_menu_model_;
+  std::unique_ptr<views::MenuRunner> context_menu_runner_;
   // A handler to handle unhandled keyboard messages coming back from the
   // renderer process.
   views::UnhandledKeyboardEventHandler unhandled_keyboard_event_handler_;
diff --git a/chrome/browser/ui/webui/side_panel/reading_list/reading_list_page_handler.cc b/chrome/browser/ui/webui/side_panel/reading_list/reading_list_page_handler.cc
index 8dada41..f409b118 100644
--- a/chrome/browser/ui/webui/side_panel/reading_list/reading_list_page_handler.cc
+++ b/chrome/browser/ui/webui/side_panel/reading_list/reading_list_page_handler.cc
@@ -228,7 +228,7 @@
 
 void ReadingListPageHandler::MarkCurrentTabAsRead() {
   BrowserWindowInterface* browser =
-      GlobalBrowserCollection::GetInstance()->GetLastActiveBrowser();
+      webui::GetBrowserWindowInterface(web_contents());
   if (!browser) {
     return;
   }
@@ -239,7 +239,7 @@
 
 void ReadingListPageHandler::AddCurrentTab() {
   BrowserWindowInterface* browser =
-      GlobalBrowserCollection::GetInstance()->GetLastActiveBrowser();
+      webui::GetBrowserWindowInterface(web_contents());
   if (!browser) {
     return;
   }
@@ -261,7 +261,10 @@
                                                    int32_t y) {
   auto embedder = reading_list_ui_->embedder();
   BrowserWindowInterface* browser =
-      GlobalBrowserCollection::GetInstance()->GetLastActiveBrowser();
+      webui::GetBrowserWindowInterface(web_contents());
+  if (!browser) {
+    return;
+  }
   if (embedder) {
     embedder->ShowContextMenu(gfx::Point(x, y),
                               std::make_unique<ReadLaterItemContextMenu>(
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.