CVE-2026-10958
Overview
Files Changed
ios/chrome/browser/omnibox/coordinator/popup/omnibox_popup_coordinator.mmios/chrome/browser/omnibox/ui/popup/omnibox_popup_view_controller.hios/chrome/browser/omnibox/ui/popup/omnibox_popup_view_controller.mm
Patch
From ac119035679e533a51a3b8362f64b958cb2c94f7 Mon Sep 17 00:00:00 2001 From: Matt Reichhoff <[email protected]> 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 <[email protected]> Reviewed-by: Ameur Hosni <[email protected]> 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 {
Original Bug Report
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.mmios/chrome/browser/omnibox/ui/popup/omnibox_popup_view_controller.mmios/chrome/browser/favicon/ui_bundled/favicon_attributes_provider.mmios/chrome/browser/omnibox/ui/popup/omnibox_popup_view_controller.hios/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:
- UI Transition: The
SceneControllerinitiates an animated transition to the Tab Grid (TabToGridAnimation). This animation lasts roughly 300ms. During this time, theTabGridTransitionHandlerretains theBrowserLayoutViewController, which in turn keeps theBrowserViewControllerand its childOmniboxPopupViewControlleralive in memory. - Profile Destruction: Simultaneously,
OTRPRofileDestroyerProfileAgentschedules the destruction of the OTR profile. This happens rapidly, typically within 2-5ms, after a quick roundtrip to the IO thread. TheBrowserCoordinatoris stopped, andprofile->DestroyOffTheRecordProfile()is called. This synchronously destroys allKeyedServiceinstances, including theLargeIconService, 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.
- An attacker hosts a malicious website.
- The user opens the malicious website in a Chrome iOS Incognito tab.
- The attacker’s site prompts the user to interact with the omnibox, bringing up the autocomplete popup containing carousel items.
- 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). - If this is the only Incognito tab open, the OTR profile is rapidly destroyed.
- The UI begins a 300ms transition animation to the Tab Grid.
- 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
- Clear Pointers Explicitly: In
OmniboxPopupCoordinator -stop, explicitly call a teardown method onOmniboxPopupViewControllerto nil outlargeIconService,largeIconCache, and theFaviconAttributesProviderbefore the service is destroyed. - Use Safe Pointers: Instead of using
@property(assign)for C++ objects, wrap the C++ pointers in an Objective-C class holding abase::WeakPtr<LargeIconService>(if supported by the service) or ensureraw_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.