CVE-2026-87595
Overview
Background
- SSRF (server-side request forgery)
- a class of bug where an application is coerced into issuing network requests to attacker-chosen destinations rather than intended ones.
- `ImageDataFetcher`
- a Chrome
image_fetchercomponent that downloads raw image bytes for a given URL through aSharedURLLoaderFactory. - Omnibox favicon fetching
- the iOS omnibox popup asynchronously downloads favicon/entity images whose URLs are supplied by autocomplete suggestions, via
OmniboxImageFetcher. - `GURL::SchemeIsHTTPOrHTTPS`
- a
GURLpredicate that returns true only when the URL’s scheme ishttporhttps.
Root Cause Analysis
The iOS omnibox rendered suggestion images by handing a suggestion-supplied imageURL straight to -[OmniboxImageFetcher fetchImage:completion:], which passed it to an ImageDataFetcher with no scheme restriction and no download-size ceiling. Because the image URL originates from autocomplete/suggestion data rather than a trusted constant, an attacker who could influence a suggestion’s image URL could point the fetch at a non-web scheme or an unbounded resource, causing the client to emit a request it should never make — the SSRF condition, plus an unbounded-download resource risk. The invariant violated is that a favicon fetch should only ever traverse http/https and should be size-limited.
The fix restores this by
- capping the
ImageDataFetcheratkMaxFaviconDownloadBytes(5 MiB) in the popup coordinator and - short-circuiting the fetch’s completion for any URL that is not
SchemeIsHTTPOrHTTPS(). Note that the added scheme guard callscompletion(nil)without a followingreturn, so control still falls through to the cache/fetch statements; the practical mitigation is that the scheme is now checked at all and the size is bounded, but the early exit is not a hard abort of the method.
http/https allowlist check and a 5 MiB download cap so non-web and oversized fetches are refused.Attack Path
- Influence a suggestion image URL An attacker gets a crafted autocomplete/suggestion entry whose associated favicon/image URL uses a non-HTTP(S) scheme or an unbounded resource to reach the omnibox popup.
- Trigger the fetch
Displaying the suggestion causes
-[OmniboxImageFetcher fetchImage:completion:]to be invoked with the attacker-controlledimageURL. - Unrestricted request emitted
Pre-patch, the URL is forwarded to
ImageDataFetcherwith no scheme check, so the client issues a request to the attacker-chosen destination (SSRF), and with no size limit it may download an arbitrarily large payload. - Consequence
The attacker gains an out-of-context request initiated by the app and/or resource consumption; any escalation beyond the emitted request and download is
(inferred)and not demonstrated by the patch.
Impact Assessment
(inferred) rather than established by the diff.Changed Functions
| Function | Change | Notes |
|---|---|---|
ifios/chrome/browser/omnibox/model/omnibox_image_fetcher.mm |
modified |
Files Changed
ios/chrome/browser/omnibox/model/omnibox_image_fetcher.mmios/chrome/browser/omnibox/coordinator/popup/omnibox_popup_coordinator.mm
Audit Directions
- Suggestion/UI-supplied URLs handed to fetchersAudit other omnibox and suggestion surfaces that pass externally-derived URLs to
ImageDataFetcher/ImageFetcherwithout validatingSchemeIsHTTPOrHTTPS()or setting a download limit. - Guards that signal but do not abortLook for early-exit checks that call a completion/callback but omit
return, allowing the guarded code to still execute the sink it was meant to prevent. - Unbounded network downloadsReview image/asset fetchers that omit
SetImageDownloadLimitor an equivalent size cap, since these enable resource-exhaustion and large-response abuse.
Patch
From c1b361f469d29daac4b4062daeb3ee01ba3aa81c Mon Sep 17 00:00:00 2001 From: Stepan Khapugin <[email protected]> Date: Tue, 28 Jul 2026 04:30:19 -0700 Subject: [PATCH] [iOS][omnibox] Limit favicon downloads to HTTP(s) and <5Mb. Fixed: 513726466 Change-Id: Idcca8a9717368bbc1b52ce13b8f0ef76776d8856 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8073746 Commit-Queue: Stepan Khapugin <[email protected]> Reviewed-by: Radu Nitescu <[email protected]> Cr-Commit-Position: refs/heads/main@{#1669358} --- 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 aa31021e..7493f817 100644 --- a/ios/chrome/browser/omnibox/coordinator/popup/omnibox_popup_coordinator.mm +++ b/ios/chrome/browser/omnibox/coordinator/popup/omnibox_popup_coordinator.mm @@ -50,6 +50,12 @@ #import "services/network/public/cpp/shared_url_loader_factory.h" #import "ui/base/device_form_factor.h" +namespace { + +const int64_t kMaxFaviconDownloadBytes = 1024 * 1024 * 5; + +} // namespace + @interface OmniboxPopupCoordinator () <OmniboxPopupMediatorProtocolProvider, OmniboxPopupMediatorSharingDelegate> @@ -100,6 +106,7 @@ std::unique_ptr<image_fetcher::ImageDataFetcher> imageFetcher = std::make_unique<image_fetcher::ImageDataFetcher>( self.profile->GetSharedURLLoaderFactory()); + imageFetcher->SetImageDownloadLimit(kMaxFaviconDownloadBytes); _omniboxImageFetcher = [[OmniboxImageFetcher alloc] initWithFaviconLoader:IOSChromeFaviconLoaderFactory::GetForProfile( diff --git a/ios/chrome/browser/omnibox/model/omnibox_image_fetcher.mm b/ios/chrome/browser/omnibox/model/omnibox_image_fetcher.mm index 133d961d..099a642 100644 --- a/ios/chrome/browser/omnibox/model/omnibox_image_fetcher.mm +++ b/ios/chrome/browser/omnibox/model/omnibox_image_fetcher.mm @@ -45,6 +45,11 @@ } - (void)fetchImage:(GURL)imageURL completion:(void (^)(UIImage*))completion { + // As a precaution, don't fetch images from nonstandard schemes. + if (!imageURL.SchemeIsHTTPOrHTTPS()) { + completion(nil); + } + NSString* URL = [NSString cr_fromString:imageURL.spec()]; UIImage* cachedImage = [_cachedImages objectForKey:URL]; if (cachedImage) {