Low chrome Logic Error 🔧 Commit mapped

Overview

Low
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactIncorrect security UI in Chrome for iOS
DescriptionIncorrect security UI in Chrome for iOS
ComponentChrome for iOS
Bug ClassLogic Error
Tracker401816601
Fix commit571f18ee74a8 (chromium/src) +30/-6
CISA KEVNot listed
CreditedAmeen Basha M K
Disclosed2026-06-30

Changed Functions

FunctionChangeNotes
if
ios/chrome/browser/download/ui/download_manager_view_controller.mm
modified

Files Changed

  • ios/chrome/browser/download/coordinator/download_manager_coordinator.mm
  • ios/chrome/browser/download/ui/download_egtest_util.mm
  • ios/chrome/browser/download/ui/download_manager_view_controller.mm
  • ios/chrome/browser/download/ui/download_manager_view_controller_protocol.h
  • ios/chrome/browser/save_to_drive/ui_bundled/save_to_drive_egtest.mm
From 571f18ee74a8a70fcbe5535840e984a90b60ea06 Mon Sep 17 00:00:00 2001
From: Quentin Pubert <[email protected]>
Date: Thu, 21 May 2026 03:39:42 -0700
Subject: [PATCH] [iOS] Add tapjacking protection to download action button

Adds a 500ms delay before accepting clicks on download manager buttons
after they become visible. This is implemented by disabling the current
action button whenever the download manager is presented or the current
action button changes, and starting a timer which re-enables the button
after 500ms.

Bug: 401816601
Change-Id: Icc11147b29a487a556031d1b4969386fca97530d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7828659
Reviewed-by: Olivier Robin <[email protected]>
Auto-Submit: Quentin Pubert <[email protected]>
Commit-Queue: Quentin Pubert <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1634158}
---

diff --git a/ios/chrome/browser/download/coordinator/download_manager_coordinator.mm b/ios/chrome/browser/download/coordinator/download_manager_coordinator.mm
index 9fbf1e9..5786eb8 100644
--- a/ios/chrome/browser/download/coordinator/download_manager_coordinator.mm
+++ b/ios/chrome/browser/download/coordinator/download_manager_coordinator.mm
@@ -373,6 +373,7 @@
 
 - (void)containedPresenterDidPresent:(id<ContainedPresenter>)presenter {
   CHECK_EQ(presenter, self.presenter, base::NotFatalUntil::M150);
+  [_viewController disableCurrentButtonTemporarily];
 }
 
 - (void)containedPresenterDidDismiss:(id<ContainedPresenter>)presenter {
diff --git a/ios/chrome/browser/download/ui/download_egtest_util.mm b/ios/chrome/browser/download/ui/download_egtest_util.mm
index 021ad13..dea013a 100644
--- a/ios/chrome/browser/download/ui/download_egtest_util.mm
+++ b/ios/chrome/browser/download/ui/download_egtest_util.mm
@@ -13,7 +13,9 @@
 namespace download {
 
 id<GREYMatcher> DownloadButton() {
-  return grey_accessibilityID(kDownloadManagerDownloadAccessibilityIdentifier);
+  return grey_allOf(
+      grey_accessibilityID(kDownloadManagerDownloadAccessibilityIdentifier),
+      grey_enabled(), nil);
 }
 
 std::unique_ptr<net::test_server::HttpResponse> GetResponse(
diff --git a/ios/chrome/browser/download/ui/download_manager_view_controller.mm b/ios/chrome/browser/download/ui/download_manager_view_controller.mm
index 1e4ff7c7..9b23b37 100644
--- a/ios/chrome/browser/download/ui/download_manager_view_controller.mm
+++ b/ios/chrome/browser/download/ui/download_manager_view_controller.mm
@@ -7,6 +7,7 @@
 #import "base/feature_list.h"
 #import "base/ios/block_types.h"
 #import "base/strings/sys_string_conversions.h"
+#import "base/timer/timer.h"
 #import "components/strings/grit/components_strings.h"
 #import "ios/chrome/browser/download/ui/download_manager_constants.h"
 #import "ios/chrome/browser/download/ui/download_manager_view_controller+Testing.h"
@@ -169,6 +170,9 @@
   BOOL _needsTransitioningToButton;
   BOOL _needsTransitioningToProgress;
   BOOL _canOpenFile;
+
+  // Timer to disable buttons after presentation (to prevent tapjacking).
+  base::OneShotTimer _tapjackingProtectionTimer;
 }
 
 @property(nonatomic, strong) UIImageView* leadingIcon;
@@ -475,6 +479,15 @@
   }
 }
 
+- (void)disableCurrentButtonTemporarily {
+  __weak __typeof(self.currentButton) weakButton = self.currentButton;
+  weakButton.enabled = NO;
+  _tapjackingProtectionTimer.Start(FROM_HERE, base::Milliseconds(500),
+                                   base::BindOnce(^{
+                                     weakButton.enabled = YES;
+                                   }));
+}
+
 #pragma mark - UI elements
 
 - (UIImageView*)leadingIcon {
@@ -794,6 +807,7 @@
   if (currentButton != _currentButton) {
     [_currentButton removeFromSuperview];
     _currentButton = currentButton;
+    [self disableCurrentButtonTemporarily];
     [self updateActionButtonLayout];
     // Reset possibly animated properties in case an animation was interrupted.
     _currentButton.hidden = NO;
diff --git a/ios/chrome/browser/download/ui/download_manager_view_controller_protocol.h b/ios/chrome/browser/download/ui/download_manager_view_controller_protocol.h
index 03370052d..c47a45c 100644
--- a/ios/chrome/browser/download/ui/download_manager_view_controller_protocol.h
+++ b/ios/chrome/browser/download/ui/download_manager_view_controller_protocol.h
@@ -33,6 +33,10 @@
 - (void)setFullscreenBrowserAgent:
     (FullscreenBrowserAgent*)fullscreenBrowserAgent;
 
+// Disables the current action button temporarily to prevent tapjacking.
+// Must be called after presenting the view controller.
+- (void)disableCurrentButtonTemporarily;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_DOWNLOAD_UI_DOWNLOAD_MANAGER_VIEW_CONTROLLER_PROTOCOL_H_
diff --git a/ios/chrome/browser/save_to_drive/ui_bundled/save_to_drive_egtest.mm b/ios/chrome/browser/save_to_drive/ui_bundled/save_to_drive_egtest.mm
index 2bbad79..51e3324 100644
--- a/ios/chrome/browser/save_to_drive/ui_bundled/save_to_drive_egtest.mm
+++ b/ios/chrome/browser/save_to_drive/ui_bundled/save_to_drive_egtest.mm
@@ -44,14 +44,17 @@
 // instead of the "DOWNLOAD" button when multiple destinations are available for
 // downloads.
 id<GREYMatcher> SaveEllipsisButton() {
-  return grey_accessibilityID(
-      kDownloadManagerSaveEllipsisAccessibilityIdentifier);
+  return grey_allOf(
+      grey_accessibilityID(kDownloadManagerSaveEllipsisAccessibilityIdentifier),
+      grey_enabled(), nil);
 }
 
 // Matcher for "DOWNLOAD" button when one destination is available for
 // downloads.
 id<GREYMatcher> DownloadButton() {
-  return grey_accessibilityID(kDownloadManagerDownloadAccessibilityIdentifier);
+  return grey_allOf(
+      grey_accessibilityID(kDownloadManagerDownloadAccessibilityIdentifier),
+      grey_enabled(), nil);
 }
 
 // Matcher for "Files" destination button in File destination picker UI.
@@ -81,14 +84,14 @@
 id<GREYMatcher> DownloadManagerGetTheAppButton() {
   return grey_allOf(
       grey_accessibilityID(kDownloadManagerInstallAppAccessibilityIdentifier),
-      grey_interactable(), nil);
+      grey_enabled(), grey_interactable(), nil);
 }
 
 // Matcher for "TRY AGAIN" button on Download Manager UI.
 id<GREYMatcher> DownloadManagerTryAgainButton() {
   return grey_allOf(
       grey_accessibilityID(kDownloadManagerTryAgainAccessibilityIdentifier),
-      grey_interactable(), nil);
+      grey_enabled(), grey_interactable(), nil);
 }
 
 // Matcher for the account picker.
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.