Chrome · Chrome for iOS
CVE-2026-17912
Logic Error in Chrome for iOS
Overview
Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Files Changed
ios/chrome/browser/app_launcher/model/app_launcher_abuse_detector.mmios/chrome/browser/app_launcher/model/app_launcher_abuse_detector_unittest.mm
Patch
From 6ab3893ee239d4d0e6d026ca24ec423261eeb973 Mon Sep 17 00:00:00 2001 From: Gauthier Ambard <[email protected]> Date: Mon, 22 Jun 2026 13:58:31 -0700 Subject: [PATCH] [ios] Scope AppLauncherAbuseDetector tracking to origin Refactor AppLauncherAbuseDetector to use the source page's origin instead of the full URL (including path and query) for the tracking key. Previously, using the full URL allowed path or query mutations between launch attempts to generate new keys, resetting the consecutive launch counter. Transitioning to `url::Origin` scopes the tracking key strictly to the scheme, host, and port of the source page. This ensures all consecutive launches from the same origin are consolidated, regardless of path or query changes. Note on trade-off: Scoping to origin means different pages on the same site will now share the same launch limit. Fixed: 504202939 Change-Id: I15fe9878b198bab82a509f2bd08455085724e3dd Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7964560 Commit-Queue: Mike Dougherty <[email protected]> Auto-Submit: Gauthier Ambard <[email protected]> Reviewed-by: Mike Dougherty <[email protected]> Cr-Commit-Position: refs/heads/main@{#1650562} --- diff --git a/ios/chrome/browser/app_launcher/model/app_launcher_abuse_detector.mm b/ios/chrome/browser/app_launcher/model/app_launcher_abuse_detector.mm index f8249a5..e1faced 100644 --- a/ios/chrome/browser/app_launcher/model/app_launcher_abuse_detector.mm +++ b/ios/chrome/browser/app_launcher/model/app_launcher_abuse_detector.mm @@ -7,13 +7,14 @@ #import "base/strings/sys_string_conversions.h" #import "ios/chrome/browser/app_launcher/model/app_launching_state.h" #import "url/gurl.h" +#import "url/origin.h" const int kMaxAllowedConsecutiveExternalAppLaunches = 2; @interface AppLauncherAbuseDetector () // Maps between external application redirection key and state. -// the key is a space separated combination of the absolute string for the -// original source URL, and the scheme of the external Application URL. +// the key is a space separated combination of the serialization of the +// origin of the source URL, and the scheme of the external Application URL. @property(nonatomic, strong) NSMutableDictionary<NSString*, AppLaunchingState*>* appLaunchingStates; // Generates key for `appURL` and `sourceURL` to be used to retrieve state from @@ -28,9 +29,10 @@ + (NSString*)stateKeyForAppURL:(const GURL&)appURL sourceURL:(const GURL&)sourcePageURL { - return - [NSString stringWithFormat:@"%s %s", sourcePageURL.GetContent().c_str(), - appURL.GetScheme().c_str()]; + return [NSString + stringWithFormat:@"%s %s", + url::Origin::Create(sourcePageURL).Serialize().c_str(), + appURL.GetScheme().c_str()]; } - (instancetype)init { diff --git a/ios/chrome/browser/app_launcher/model/app_launcher_abuse_detector_unittest.mm b/ios/chrome/browser/app_launcher/model/app_launcher_abuse_detector_unittest.mm index a1d9b65..5de835d 100644 --- a/ios/chrome/browser/app_launcher/model/app_launcher_abuse_detector_unittest.mm +++ b/ios/chrome/browser/app_launcher/model/app_launcher_abuse_detector_unittest.mm @@ -42,6 +42,40 @@ fromSourcePageURL:kSourceUrl1]); } +// Tests cases when the same app is launched repeatedly from the same origin +// but different paths (simulating history.replaceState). +TEST_F(AppLauncherAbuseDetectorTest, + TestRepeatedAppLaunches_SameOriginDifferentPaths) { + const GURL kSourceUrl1("http://www.google.com/path1"); + const GURL kSourceUrl2("http://www.google.com/path2"); + const GURL kSourceUrl3("http://www.google.com/path3"); + const GURL kAppUrl("facetime://+154"); + + AppLauncherAbuseDetector* abuseDetector = + [[AppLauncherAbuseDetector alloc] init]; + + // First launch attempt + EXPECT_EQ(ExternalAppLaunchPolicyAllow, + [abuseDetector launchPolicyForURL:kAppUrl + fromSourcePageURL:kSourceUrl1]); + [abuseDetector didRequestLaunchExternalAppURL:kAppUrl + fromSourcePageURL:kSourceUrl1]; + + // Second launch attempt (path changed) + EXPECT_EQ(ExternalAppLaunchPolicyAllow, + [abuseDetector launchPolicyForURL:kAppUrl + fromSourcePageURL:kSourceUrl2]); + [abuseDetector didRequestLaunchExternalAppURL:kAppUrl + fromSourcePageURL:kSourceUrl2]; + + // Third launch attempt (path changed again) + [abuseDetector didRequestLaunchExternalAppURL:kAppUrl + fromSourcePageURL:kSourceUrl3]; + EXPECT_EQ(ExternalAppLaunchPolicyPrompt, + [abuseDetector launchPolicyForURL:kAppUrl + fromSourcePageURL:kSourceUrl3]); +} + // Tests cases when same app is launched repeatedly from different sources. TEST_F(AppLauncherAbuseDetectorTest, TestRepeatedAppLaunches_SameAppDifferentSources) {
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/ios/chrome/browser/app_launcher/model/app_launcher_abuse_detector_unittest.mm b/ios/chrome/browser/app_launcher/model/app_launcher_abuse_detector_unittest.mm
index a1d9b65..5de835d 100644
--- a/ios/chrome/browser/app_launcher/model/app_launcher_abuse_detector_unittest.mm
+++ b/ios/chrome/browser/app_launcher/model/app_launcher_abuse_detector_unittest.mm
@@ -42,6 +42,40 @@
fromSourcePageURL:kSourceUrl1]);
}
+// Tests cases when the same app is launched repeatedly from the same origin
+// but different paths (simulating history.replaceState).
+TEST_F(AppLauncherAbuseDetectorTest,
+ TestRepeatedAppLaunches_SameOriginDifferentPaths) {
+ const GURL kSourceUrl1("http://www.google.com/path1");
+ const GURL kSourceUrl2("http://www.google.com/path2");
+ const GURL kSourceUrl3("http://www.google.com/path3");
+ const GURL kAppUrl("facetime://+154");
+
+ AppLauncherAbuseDetector* abuseDetector =
+ [[AppLauncherAbuseDetector alloc] init];
+
+ // First launch attempt
+ EXPECT_EQ(ExternalAppLaunchPolicyAllow,
+ [abuseDetector launchPolicyForURL:kAppUrl
+ fromSourcePageURL:kSourceUrl1]);
+ [abuseDetector didRequestLaunchExternalAppURL:kAppUrl
+ fromSourcePageURL:kSourceUrl1];
+
+ // Second launch attempt (path changed)
+ EXPECT_EQ(ExternalAppLaunchPolicyAllow,
+ [abuseDetector launchPolicyForURL:kAppUrl
+ fromSourcePageURL:kSourceUrl2]);
+ [abuseDetector didRequestLaunchExternalAppURL:kAppUrl
+ fromSourcePageURL:kSourceUrl2];
+
+ // Third launch attempt (path changed again)
+ [abuseDetector didRequestLaunchExternalAppURL:kAppUrl
+ fromSourcePageURL:kSourceUrl3];
+ EXPECT_EQ(ExternalAppLaunchPolicyPrompt,
+ [abuseDetector launchPolicyForURL:kAppUrl
+ fromSourcePageURL:kSourceUrl3]);
+}
+
// Tests cases when same app is launched repeatedly from different sources.
TEST_F(AppLauncherAbuseDetectorTest,
TestRepeatedAppLaunches_SameAppDifferentSources) {
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.
References
On This Page