Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUse after free in Chrome for iOS
DescriptionUse after free in Chrome for iOS
ComponentChrome for iOS
Bug ClassUAF
Tracker507251069
Fix commitac119035679e (chromium/src) +10/-0
CISA KEVNot listed
CreditedGoogle
Disclosed2026-06-02

Files Changed

  • ios/chrome/browser/omnibox/coordinator/popup/omnibox_popup_coordinator.mm
  • ios/chrome/browser/omnibox/ui/popup/omnibox_popup_view_controller.h
  • ios/chrome/browser/omnibox/ui/popup/omnibox_popup_view_controller.mm
From ac119035679e533a51a3b8362f64b958cb2c94f7 Mon Sep 17 00:00:00 2001
From: Matt Reichhoff <mreichhoff@chromium.org>
Date: Thu, 30 Apr 2026 08:26:24 -0700
Subject: [PATCH] [iOS] Add disconnect function in omnibox popup view controller

Ensure we null out pointers.

Bug: 507251069
Change-Id: I2a1ac021d1bbd71dec8fa9027467ad3754a65dd7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7807906
Commit-Queue: Matt Reichhoff <mreichhoff@chromium.org>
Reviewed-by: Ameur Hosni <ameurhosni@google.com>
Cr-Commit-Position: refs/heads/main@{#1623222}
---

diff --git a/ios/chrome/browser/omnibox/coordinator/popup/omnibox_popup_coordinator.mm b/ios/chrome/browser/omnibox/coordinator/popup/omnibox_popup_coordinator.mm
index 7734fbc..c7e0b59d 100644
--- a/ios/chrome/browser/omnibox/coordinator/popup/omnibox_popup_coordinator.mm
+++ b/ios/chrome/browser/omnibox/coordinator/popup/omnibox_popup_coordinator.mm
@@ -173,6 +173,7 @@
   [self.sharingCoordinator stop];
   self.sharingCoordinator = nil;
 
+  [self.popupViewController disconnect];
   self.popupViewController = nil;
   self.mediator = nil;
   self.autocompleteController = nullptr;
diff --git a/ios/chrome/browser/omnibox/ui/popup/omnibox_popup_view_controller.h b/ios/chrome/browser/omnibox/ui/popup/omnibox_popup_view_controller.h
index 8b5a970..278c4b5 100644
--- a/ios/chrome/browser/omnibox/ui/popup/omnibox_popup_view_controller.h
+++ b/ios/chrome/browser/omnibox/ui/popup/omnibox_popup_view_controller.h
@@ -73,6 +73,9 @@
 /// Toggle visibility of the omnibox debugger view.
 - (void)toggleOmniboxDebuggerView;
 
+/// Disconnects properties before destruction.
+- (void)disconnect;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_OMNIBOX_UI_POPUP_OMNIBOX_POPUP_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/omnibox/ui/popup/omnibox_popup_view_controller.mm b/ios/chrome/browser/omnibox/ui/popup/omnibox_popup_view_controller.mm
index b0f0e31d..e910033 100644
--- a/ios/chrome/browser/omnibox/ui/popup/omnibox_popup_view_controller.mm
+++ b/ios/chrome/browser/omnibox/ui/popup/omnibox_popup_view_controller.mm
@@ -194,6 +194,12 @@
   }
 }
 
+- (void)disconnect {
+  self.largeIconService = nullptr;
+  self.largeIconCache = nullptr;
+  _carouselAttributeProvider = nil;
+}
+
 #pragma mark - Getter/Setter
 
 - (void)setHighlightedIndexPath:(NSIndexPath*)highlightedIndexPath {
Loading diff…

Original Bug Report

reported by vm...@google.com

Potential Use-After-Free in FaviconAttributesProvider due to dangling LargeIconService pointer

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 potential Use-After-Free exists in the iOS Omnibox UI. Objective-C assign properties in OmniboxPopupViewController and FaviconAttributesProvider hold raw pointers to the OTR profile-scoped LargeIconService. When an Incognito tab closes, the service is destroyed faster than the associated UI transition animation finishes, allowing a layout pass to access the freed service.

Affected files:

  • ios/chrome/browser/omnibox/coordinator/popup/omnibox_popup_coordinator.mm
  • ios/chrome/browser/omnibox/ui/popup/omnibox_popup_view_controller.mm
  • ios/chrome/browser/favicon/ui_bundled/favicon_attributes_provider.mm
  • ios/chrome/browser/omnibox/ui/popup/omnibox_popup_view_controller.h
  • ios/chrome/browser/omnibox/ui/popup/omnibox_popup_presenter.mm

Estimated timestamp from git blame: 2025-09-18

Summary

A potential Use-After-Free (UAF) vulnerability has been identified in the iOS Omnibox UI when handling Incognito (Off-The-Record) profile destruction. The OmniboxPopupViewController and FaviconAttributesProvider retain raw, non-zeroing C++ pointers to profile-scoped services, specifically LargeIconService and LargeIconCache. Because these are stored using Objective-C @property(assign), they bypass memory protections like MiraclePtr. If a layout pass occurs while the UI is transitioning out of an Incognito context, these dangling pointers can be dereferenced, leading to a virtual function call on freed memory.

Root Cause Analysis

In OmniboxPopupCoordinator -start, the coordinator fetches the LargeIconService for the Incognito profile and passes it to the OmniboxPopupViewController:

// ios/chrome/browser/omnibox/ui/popup/omnibox_popup_view_controller.h
@property(nonatomic, assign) favicon::LargeIconService* largeIconService;

This pointer is then copied into a FaviconAttributesProvider.

When the last Incognito tab is closed, two parallel processes begin:

  1. UI Transition: The SceneController initiates an animated transition to the Tab Grid (TabToGridAnimation). This animation lasts roughly 300ms. During this time, the TabGridTransitionHandler retains the BrowserLayoutViewController, which in turn keeps the BrowserViewController and its child OmniboxPopupViewController alive in memory.
  2. Profile Destruction: Simultaneously, OTRPRofileDestroyerProfileAgent schedules the destruction of the OTR profile. This happens rapidly, typically within 2-5ms, after a quick roundtrip to the IO thread. The BrowserCoordinator is stopped, and profile->DestroyOffTheRecordProfile() is called. This synchronously destroys all KeyedService instances, including the LargeIconService, freeing its memory on the heap.

The vulnerability occurs because the OmniboxPopupViewController outlives the LargeIconService by almost 300ms. During the TabToGridAnimation, the view’s frame and transform are continuously modified, triggering UIKit layout passes.

If the OmniboxPopupViewController contains a carousel suggestion, the SelfSizingTableView responds to the layout pass by calling cellForRowAtIndexPath:. This method invokes fetchFaviconForCarouselItem:, which ultimately calls the FaviconAttributesProvider:

// ios/chrome/browser/favicon/ui_bundled/favicon_attributes_provider.mm
self.largeIconService->GetLargeIconRawBitmapOrFallbackStyleForPageUrl(...); // Pure virtual call on freed vptr

Because the LargeIconService was freed milliseconds earlier, this results in a UAF and a virtual call on corrupted memory.

Potential Reproduction Steps

Note: Our tooling agent does not run code; these are suggested steps based on static analysis.

  1. An attacker hosts a malicious website.
  2. The user opens the malicious website in a Chrome iOS Incognito tab.
  3. The attacker’s site prompts the user to interact with the omnibox, bringing up the autocomplete popup containing carousel items.
  4. While the user is interacting with the omnibox, the website executes window.close() via JavaScript (or the user manually taps the ‘X’ to close the tab on an iPad background tab).
  5. If this is the only Incognito tab open, the OTR profile is rapidly destroyed.
  6. The UI begins a 300ms transition animation to the Tab Grid.
  7. During the animation, a layout pass on the still-alive omnibox popup UI triggers a fetch to the freed LargeIconService, resulting in a Use-After-Free in the browser process.

Suggested Fix

  1. Clear Pointers Explicitly: In OmniboxPopupCoordinator -stop, explicitly call a teardown method on OmniboxPopupViewController to nil out largeIconService, largeIconCache, and the FaviconAttributesProvider before the service is destroyed.
  2. Use Safe Pointers: Instead of using @property(assign) for C++ objects, wrap the C++ pointers in an Objective-C class holding a base::WeakPtr<LargeIconService> (if supported by the service) or ensure raw_ptr<T> can be utilized securely across the Objective-C++ boundary.

Evaluated with Chrome root at commit: a1e33f5848218e21d4a16ae2c1bc94e815c30c7f


Results so far have been promising, but there can be wrong deductions. If this proves to be a false positive, please close as WAI; 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