High chrome Logic Error 🔧 Commit mapped

Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInsufficient policy enforcement in Chrome for iOS
DescriptionInsufficient policy enforcement in Chrome for iOS
ComponentChrome for iOS
Bug ClassLogic Error
Tracker476591032
Fix commitd19ac426145b (chromium/src) +130/-0
CISA KEVNot listed
Creditedmaitai
Disclosed2026-06-30

Changed Functions

FunctionChangeNotes
TEST_F
ios/chrome/browser/app_launcher/model/app_launcher_browser_agent_unittest.mm
modified

Files Changed

  • ios/chrome/app/strings/ios_strings.grd
  • ios/chrome/app/strings/ios_strings_grd/IDS_IOS_OPEN_SHORTCUTS_URL.png.sha1
  • ios/chrome/browser/app_launcher/model/app_launcher_browser_agent.mm
  • ios/chrome/browser/app_launcher/model/app_launcher_browser_agent_unittest.mm
  • ios/chrome/browser/app_launcher/model/app_launcher_tab_helper.mm
  • ios/chrome/browser/app_launcher/model/app_launcher_tab_helper_delegate.h
  • ios/chrome/browser/overlays/model/public/web_content_area/app_launcher_overlay.h
  • ios/chrome/browser/overlays/model/public/web_content_area/app_launcher_overlay.mm
From d19ac426145be6a3e365965013bad11f17d84d90 Mon Sep 17 00:00:00 2001
From: Mike Dougherty <[email protected]>
Date: Wed, 13 May 2026 15:18:18 -0700
Subject: [PATCH] Show alert before opening a shortcuts URL

Fixed: 476591032
Change-Id: I66358c662fd9f3f65d66e5e18fd1b32c67c822e7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7838361
Reviewed-by: Calder Kitagawa <[email protected]>
Reviewed-by: Rohit Rao <[email protected]>
Commit-Queue: Mike Dougherty <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1630265}
---

diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd
index 379000d..f8392bab 100644
--- a/ios/chrome/app/strings/ios_strings.grd
+++ b/ios/chrome/app/strings/ios_strings.grd
@@ -4892,6 +4892,9 @@
       <message name="IDS_IOS_OPEN_SETTINGS" desc="Text of the button that will take the user to the Settings page to configure the default browser [iOS only]">
         Open Settings
       </message>
+      <message name="IDS_IOS_OPEN_SHORTCUTS_URL" desc="Alert to let the user know that the website is trying to open the Shortcuts application. [iOS only]">
+        This site is trying to open the &quot;Shortcuts&quot; application.
+      </message>
       <message name="IDS_IOS_OPEN_SOURCE_LICENSES" desc="The label to access the open source licenses, displayed in the application settings [Length: 30em] [iOS only]">
         Open source licenses
       </message>
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_OPEN_SHORTCUTS_URL.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_OPEN_SHORTCUTS_URL.png.sha1
new file mode 100644
index 0000000..537b46f
--- /dev/null
+++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_OPEN_SHORTCUTS_URL.png.sha1
@@ -0,0 +1 @@
+b0ee844e67c69601c46b7b2f9e8b65f2a44d2916
\ No newline at end of file
diff --git a/ios/chrome/browser/app_launcher/model/app_launcher_browser_agent.mm b/ios/chrome/browser/app_launcher/model/app_launcher_browser_agent.mm
index 598e3d12..7a842eb 100644
--- a/ios/chrome/browser/app_launcher/model/app_launcher_browser_agent.mm
+++ b/ios/chrome/browser/app_launcher/model/app_launcher_browser_agent.mm
@@ -98,6 +98,11 @@
       UMA_HISTOGRAM_BOOLEAN("Tab.ExternalApplicationOpened.Failed",
                             user_accepted);
       break;
+    case app_launcher_overlays::AppLaunchConfirmationRequestCause::
+        kShortcutsURL:
+      UMA_HISTOGRAM_BOOLEAN("Tab.ExternalApplicationOpened.ShortcutsURL",
+                            user_accepted);
+      break;
   }
 }
 
@@ -147,6 +152,9 @@
     case AppLauncherAlertCause::kAppLaunchFailed:
       return app_launcher_overlays::AppLaunchConfirmationRequestCause::
           kAppLaunchFailed;
+    case AppLauncherAlertCause::kShortcutsURL:
+      return app_launcher_overlays::AppLaunchConfirmationRequestCause::
+          kShortcutsURL;
   }
 }
 
diff --git a/ios/chrome/browser/app_launcher/model/app_launcher_browser_agent_unittest.mm b/ios/chrome/browser/app_launcher/model/app_launcher_browser_agent_unittest.mm
index 1580013..dddef67 100644
--- a/ios/chrome/browser/app_launcher/model/app_launcher_browser_agent_unittest.mm
+++ b/ios/chrome/browser/app_launcher/model/app_launcher_browser_agent_unittest.mm
@@ -431,6 +431,79 @@
   [application_ verify];
 }
 
+// Tests that the browser agent shows an alert when opening a shortcuts URL.
+TEST_F(AppLauncherBrowserAgentTest, ShortcutsURLRequestShowsAlert) {
+  const base::HistogramTester histogram_tester;
+  const GURL kShortcutsUrl("shortcuts://1234");
+  const GURL kSourcePageUrl("http://www.chromium.test");
+  web::WebState* web_state =
+      AddWebState(/*opener=*/nullptr, /*nav_item_count=*/1);
+
+  // Request an app launch for kShortcutsUrl while the abuse detector returns
+  // ExternalAppLaunchPolicyPrompt.
+  abuse_detectors_[web_state].policy = ExternalAppLaunchPolicyPrompt;
+  AppLauncherTabHelper::FromWebState(web_state)->RequestToLaunchApp(
+      kShortcutsUrl, kSourcePageUrl, /*link_transition=*/true,
+      /*is_user_initiated=*/true, /*user_tapped_recently=*/true);
+
+  // Add a response allowing the navigation.
+  OverlayRequestQueue* queue = OverlayRequestQueue::FromWebState(
+      web_state, OverlayModality::kWebContentArea);
+  queue->front_request()->GetCallbackManager()->SetCompletionResponse(
+      OverlayResponse::CreateWithInfo<AllowAppLaunchResponse>());
+
+  // Cancel requests in the queue so that the completion callback is executed,
+  // expecting that the application will open the URL.
+  OCMExpect([application_ openURL:net::NSURLWithGURL(kShortcutsUrl)
+                          options:@{}
+                completionHandler:[OCMArg isNotNil]]);
+  queue->CancelAllRequests();
+
+  histogram_tester.ExpectBucketCount(
+      "Tab.ExternalApplicationOpened.ShortcutsURL",
+      /*true*/ 1, 1);
+
+  // Verify that the application attempts to open the URL.
+  [application_ verify];
+}
+
+// Tests that the browser agent shows an alert when opening a workflow
+// (Shortcuts appplication) URL.
+TEST_F(AppLauncherBrowserAgentTest, WorkflowURLRequestShowsAlert) {
+  const base::HistogramTester histogram_tester;
+  const GURL kWorkflowUrl("workflow://1234");
+  const GURL kSourcePageUrl("http://www.chromium.test");
+  web::WebState* web_state =
+      AddWebState(/*opener=*/nullptr, /*nav_item_count=*/1);
+
+  // Request an app launch for kShortcutsUrl while the abuse detector returns
+  // ExternalAppLaunchPolicyPrompt.
+  abuse_detectors_[web_state].policy = ExternalAppLaunchPolicyPrompt;
+  AppLauncherTabHelper::FromWebState(web_state)->RequestToLaunchApp(
+      kWorkflowUrl, kSourcePageUrl, /*link_transition=*/true,
+      /*is_user_initiated=*/true, /*user_tapped_recently=*/true);
+
+  // Add a response allowing the navigation.
+  OverlayRequestQueue* queue = OverlayRequestQueue::FromWebState(
+      web_state, OverlayModality::kWebContentArea);
+  queue->front_request()->GetCallbackManager()->SetCompletionResponse(
+      OverlayResponse::CreateWithInfo<AllowAppLaunchResponse>());
+
+  // Cancel requests in the queue so that the completion callback is executed,
+  // expecting that the application will open the URL.
+  OCMExpect([application_ openURL:net::NSURLWithGURL(kWorkflowUrl)
+                          options:@{}
+                completionHandler:[OCMArg isNotNil]]);
+  queue->CancelAllRequests();
+
+  histogram_tester.ExpectBucketCount(
+      "Tab.ExternalApplicationOpened.ShortcutsURL",
+      /*true*/ 1, 1);
+
+  // Verify that the application attempts to open the URL.
+  [application_ verify];
+}
+
 // Tests that completion is called on scene state activation
 TEST_F(AppLauncherBrowserAgentTest, CompletionCalledOnSceneActivation) {
   const GURL kAppUrl("some-app://1234");
diff --git a/ios/chrome/browser/app_launcher/model/app_launcher_tab_helper.mm b/ios/chrome/browser/app_launcher/model/app_launcher_tab_helper.mm
index 7c248fc..507aa5e 100644
--- a/ios/chrome/browser/app_launcher/model/app_launcher_tab_helper.mm
+++ b/ios/chrome/browser/app_launcher/model/app_launcher_tab_helper.mm
@@ -139,6 +139,15 @@
     return;
   }
 
+  // Prompt user before launching shortcuts. See crbug.com/476591032 for more
+  // context.
+  constexpr char kShortcutsScheme[] = "shortcuts";
+  constexpr char kWorkflowScheme[] = "workflow";
+  if (url.SchemeIs(kShortcutsScheme) || url.SchemeIs(kWorkflowScheme)) {
+    ShowAppLaunchAlert(AppLauncherAlertCause::kShortcutsURL, url);
+    return;
+  }
+
   // 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) {
diff --git a/ios/chrome/browser/app_launcher/model/app_launcher_tab_helper_delegate.h b/ios/chrome/browser/app_launcher/model/app_launcher_tab_helper_delegate.h
index 8ea8c68..d12b3261 100644
--- a/ios/chrome/browser/app_launcher/model/app_launcher_tab_helper_delegate.h
+++ b/ios/chrome/browser/app_launcher/model/app_launcher_tab_helper_delegate.h
@@ -16,6 +16,7 @@
   kRepeatedLaunchDetected,
   kOpenFromIncognito,
   kNoUserInteraction,
+  kShortcutsURL,
   kAppLaunchFailed,
 };
 
diff --git a/ios/chrome/browser/overlays/model/public/web_content_area/app_launcher_overlay.h b/ios/chrome/browser/overlays/model/public/web_content_area/app_launcher_overlay.h
index 6cbd64d5..99ff0553 100644
--- a/ios/chrome/browser/overlays/model/public/web_content_area/app_launcher_overlay.h
+++ b/ios/chrome/browser/overlays/model/public/web_content_area/app_launcher_overlay.h
@@ -17,6 +17,7 @@
   kOpenFromIncognito,
   kNoUserInteraction,
   kAppLaunchFailed,
+  kShortcutsURL,
 };
 
 // Configuration object for OverlayRequests for alerts notifying the user that
diff --git a/ios/chrome/browser/overlays/model/public/web_content_area/app_launcher_overlay.mm b/ios/chrome/browser/overlays/model/public/web_content_area/app_launcher_overlay.mm
index a75f582..73ee1f2 100644
--- a/ios/chrome/browser/overlays/model/public/web_content_area/app_launcher_overlay.mm
+++ b/ios/chrome/browser/overlays/model/public/web_content_area/app_launcher_overlay.mm
@@ -77,6 +77,13 @@
       reject_button_title =
           l10n_util::GetNSString(IDS_IOS_OPEN_ANOTHER_APP_BLOCK);
       break;
+    case AppLaunchConfirmationRequestCause::kShortcutsURL:
+      alert_message = l10n_util::GetNSString(IDS_IOS_OPEN_SHORTCUTS_URL);
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/ios/chrome/browser/app_launcher/model/app_launcher_browser_agent_unittest.mm b/ios/chrome/browser/app_launcher/model/app_launcher_browser_agent_unittest.mm
index 1580013..dddef67 100644
--- a/ios/chrome/browser/app_launcher/model/app_launcher_browser_agent_unittest.mm
+++ b/ios/chrome/browser/app_launcher/model/app_launcher_browser_agent_unittest.mm
@@ -431,6 +431,79 @@
   [application_ verify];
 }
 
+// Tests that the browser agent shows an alert when opening a shortcuts URL.
+TEST_F(AppLauncherBrowserAgentTest, ShortcutsURLRequestShowsAlert) {
+  const base::HistogramTester histogram_tester;
+  const GURL kShortcutsUrl("shortcuts://1234");
+  const GURL kSourcePageUrl("http://www.chromium.test");
+  web::WebState* web_state =
+      AddWebState(/*opener=*/nullptr, /*nav_item_count=*/1);
+
+  // Request an app launch for kShortcutsUrl while the abuse detector returns
+  // ExternalAppLaunchPolicyPrompt.
+  abuse_detectors_[web_state].policy = ExternalAppLaunchPolicyPrompt;
+  AppLauncherTabHelper::FromWebState(web_state)->RequestToLaunchApp(
+      kShortcutsUrl, kSourcePageUrl, /*link_transition=*/true,
+      /*is_user_initiated=*/true, /*user_tapped_recently=*/true);
+
+  // Add a response allowing the navigation.
+  OverlayRequestQueue* queue = OverlayRequestQueue::FromWebState(
+      web_state, OverlayModality::kWebContentArea);
+  queue->front_request()->GetCallbackManager()->SetCompletionResponse(
+      OverlayResponse::CreateWithInfo<AllowAppLaunchResponse>());
+
+  // Cancel requests in the queue so that the completion callback is executed,
+  // expecting that the application will open the URL.
+  OCMExpect([application_ openURL:net::NSURLWithGURL(kShortcutsUrl)
+                          options:@{}
+                completionHandler:[OCMArg isNotNil]]);
+  queue->CancelAllRequests();
+
+  histogram_tester.ExpectBucketCount(
+      "Tab.ExternalApplicationOpened.ShortcutsURL",
+      /*true*/ 1, 1);
+
+  // Verify that the application attempts to open the URL.
+  [application_ verify];
+}
+
+// Tests that the browser agent shows an alert when opening a workflow
+// (Shortcuts appplication) URL.
+TEST_F(AppLauncherBrowserAgentTest, WorkflowURLRequestShowsAlert) {
+  const base::HistogramTester histogram_tester;
+  const GURL kWorkflowUrl("workflow://1234");
+  const GURL kSourcePageUrl("http://www.chromium.test");
+  web::WebState* web_state =
+      AddWebState(/*opener=*/nullptr, /*nav_item_count=*/1);
+
+  // Request an app launch for kShortcutsUrl while the abuse detector returns
+  // ExternalAppLaunchPolicyPrompt.
+  abuse_detectors_[web_state].policy = ExternalAppLaunchPolicyPrompt;
+  AppLauncherTabHelper::FromWebState(web_state)->RequestToLaunchApp(
+      kWorkflowUrl, kSourcePageUrl, /*link_transition=*/true,
+      /*is_user_initiated=*/true, /*user_tapped_recently=*/true);
+
+  // Add a response allowing the navigation.
+  OverlayRequestQueue* queue = OverlayRequestQueue::FromWebState(
+      web_state, OverlayModality::kWebContentArea);
+  queue->front_request()->GetCallbackManager()->SetCompletionResponse(
+      OverlayResponse::CreateWithInfo<AllowAppLaunchResponse>());
+
+  // Cancel requests in the queue so that the completion callback is executed,
+  // expecting that the application will open the URL.
+  OCMExpect([application_ openURL:net::NSURLWithGURL(kWorkflowUrl)
+                          options:@{}
+                completionHandler:[OCMArg isNotNil]]);
+  queue->CancelAllRequests();
+
+  histogram_tester.ExpectBucketCount(
+      "Tab.ExternalApplicationOpened.ShortcutsURL",
+      /*true*/ 1, 1);
+
+  // Verify that the application attempts to open the URL.
+  [application_ verify];
+}
+
 // Tests that completion is called on scene state activation
 TEST_F(AppLauncherBrowserAgentTest, CompletionCalledOnSceneActivation) {
   const GURL kAppUrl("some-app://1234");
diff --git a/ios/chrome/browser/overlays/model/public/web_content_area/app_launcher_overlay_unittest.mm b/ios/chrome/browser/overlays/model/public/web_content_area/app_launcher_overlay_unittest.mm
index dc8739b..f04f2eb 100644
--- a/ios/chrome/browser/overlays/model/public/web_content_area/app_launcher_overlay_unittest.mm
+++ b/ios/chrome/browser/overlays/model/public/web_content_area/app_launcher_overlay_unittest.mm
@@ -172,3 +172,29 @@
       config->response_converter().Run(std::move(alert_response));
   EXPECT_FALSE(response);
 }
+
+// Tests that the alert overlay request is set correctly for a launch request
+// with a shortcuts URL.
+TEST_F(AppLauncherOverlayTest, ShortcutsURLRequestAlertSetup) {
+  std::unique_ptr<OverlayRequest> request = OverlayRequest::CreateWithConfig<
+      AppLaunchConfirmationRequest>(
+      app_launcher_overlays::AppLaunchConfirmationRequestCause::kShortcutsURL);
+  AlertRequest* config = request->GetConfig<AlertRequest>();
+  ASSERT_TRUE(config);
+
+  EXPECT_NSEQ(l10n_util::GetNSString(IDS_IOS_OPEN_SHORTCUTS_URL),
+              config->message());
+
+  // There is an OK button and a Cancel button in app launch alerts.
+  ASSERT_EQ(2U, config->button_configs().size());
+  const ButtonConfig& ok_button_config = config->button_configs()[0][0];
+  const ButtonConfig& cancel_button_config = config->button_configs()[1][0];
+
+  EXPECT_EQ(UIAlertActionStyleDefault, ok_button_config.style);
+  EXPECT_NSEQ(l10n_util::GetNSString(IDS_IOS_OPEN_ANOTHER_APP_ALLOW),
+              ok_button_config.title);
+
+  EXPECT_EQ(UIAlertActionStyleCancel, cancel_button_config.style);
+  EXPECT_NSEQ(l10n_util::GetNSString(IDS_IOS_OPEN_ANOTHER_APP_BLOCK),
+              cancel_button_config.title);
+}
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.