Chrome · Passwords
CVE-2026-14143
Logic Error in Passwords
Overview
Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifios/chrome/browser/passwords/bottom_sheet/coordinator/passkey_creation_bottom_sheet_mediator.mm |
modified |
Files Changed
components/webauthn/ios/passkey_tab_helper.hcomponents/webauthn/ios/passkey_tab_helper.mmios/chrome/browser/passwords/bottom_sheet/coordinator/passkey_creation_bottom_sheet_mediator.mmios/chrome/browser/passwords/bottom_sheet/ui/passkey_creation_bottom_sheet_consumer.hios/chrome/browser/passwords/bottom_sheet/ui/passkey_creation_bottom_sheet_view_controller.mmios/chrome/browser/passwords/bottom_sheet/ui/passkey_creation_bottom_sheet_view_controller_unittest.mm
Patch
From 2cbdf7e9709ac470e737a2e2919e05356e5c19c6 Mon Sep 17 00:00:00 2001 From: Rafał Godlewski <[email protected]> Date: Fri, 29 May 2026 05:49:51 -0700 Subject: [PATCH] [iOS][WebAuthn] Use rp_id in passkey creation bottom sheet Display the actual RP ID from the WebAuthn request in the passkey creation bottom sheet, instead of using the top-level frame's last committed URL, as it might differ for cross-origin subframes. Fixed: 514075028 Change-Id: Ie890dd05dd522b7d297c1aefcd12475585312051 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7883325 Reviewed-by: Alexis Hétu <[email protected]> Commit-Queue: Rafał Godlewski <[email protected]> Cr-Commit-Position: refs/heads/main@{#1638418} --- diff --git a/components/webauthn/ios/passkey_tab_helper.h b/components/webauthn/ios/passkey_tab_helper.h index 3b10c2f..57fa512d 100644 --- a/components/webauthn/ios/passkey_tab_helper.h +++ b/components/webauthn/ios/passkey_tab_helper.h @@ -111,6 +111,10 @@ // have a username. std::string UsernameForRequest(const std::string& request_id); + // Returns the relying party identifier associated with the current request ID + // or an empty string if the request is not found. + std::string RelyingPartyIdForRequest(const std::string& request_id); + // Sets the passkey command handler. void SetIOSPasskeyClientCommandsHandler(id<IOSPasskeyClientCommands> handler); diff --git a/components/webauthn/ios/passkey_tab_helper.mm b/components/webauthn/ios/passkey_tab_helper.mm index fc19c054..dcaaa1c 100644 --- a/components/webauthn/ios/passkey_tab_helper.mm +++ b/components/webauthn/ios/passkey_tab_helper.mm @@ -740,6 +740,23 @@ return ""; } +std::string PasskeyTabHelper::RelyingPartyIdForRequest( + const std::string& request_id) { + // Check registration requests first. + auto registration_it = registration_requests_.find(request_id); + if (registration_it != registration_requests_.end()) { + return registration_it->second.RpId(); + } + + // Check assertion requests next. + auto assertion_it = assertion_requests_.find(request_id); + if (assertion_it != assertion_requests_.end()) { + return assertion_it->second.RpId(); + } + + return ""; +} + std::optional<bool> PasskeyTabHelper::ShouldPerformUserVerification( const std::string& request_id, bool is_biometric_authentication_enabled) const { diff --git a/ios/chrome/browser/passwords/bottom_sheet/coordinator/passkey_creation_bottom_sheet_mediator.mm b/ios/chrome/browser/passwords/bottom_sheet/coordinator/passkey_creation_bottom_sheet_mediator.mm index 69394dde..76e689d7 100644 --- a/ios/chrome/browser/passwords/bottom_sheet/coordinator/passkey_creation_bottom_sheet_mediator.mm +++ b/ios/chrome/browser/passwords/bottom_sheet/coordinator/passkey_creation_bottom_sheet_mediator.mm @@ -42,9 +42,6 @@ // Module containing the reauthentication mechanism. id<ReauthenticationProtocol> _reauthModule; - - // URL of the current page the bottom sheet is being displayed on. - GURL _URL; } - (instancetype) @@ -66,7 +63,6 @@ _requestInfo = std::move(requestInfo); _accountForSaving = accountForSaving; _reauthModule = reauthModule; - _URL = webStateList->GetActiveWebState()->GetLastCommittedURL(); _mediatorDelegate = mediatorDelegate; } return self; @@ -176,8 +172,15 @@ #pragma mark - Accessors - (void)setConsumer:(id<PasskeyCreationBottomSheetConsumer>)consumer { + NSString* rpId = [self rpId]; + if (!rpId) { + // The RP ID should not be empty, dismiss the flow. + [_mediatorDelegate dismissPasskeyCreation]; + return; + } + _consumer = consumer; - [_consumer setUsername:[self username] email:[self email] url:_URL]; + [_consumer setUsername:[self username] email:[self email] rpId:rpId]; } #pragma mark - WebStateListObserving @@ -198,6 +201,22 @@ #pragma mark - Private +// Returns the relying party identifier for the passkey request. +- (NSString*)rpId { + webauthn::PasskeyTabHelper* passkeyTabHelper = [self passkeyTabHelper]; + if (!passkeyTabHelper || !_requestInfo.has_value()) { + return nil; + } + + std::string rpId = + passkeyTabHelper->RelyingPartyIdForRequest(_requestInfo->request_id); + if (rpId.empty()) { + return nil; + } + + return base::SysUTF8ToNSString(rpId); +} + // Returns the username for the passkey request. - (NSString*)username { webauthn::PasskeyTabHelper* passkeyTabHelper = [self passkeyTabHelper]; diff --git a/ios/chrome/browser/passwords/bottom_sheet/ui/passkey_creation_bottom_sheet_consumer.h b/ios/chrome/browser/passwords/bottom_sheet/ui/passkey_creation_bottom_sheet_consumer.h index 12b3e4a..7c1f4de 100644 --- a/ios/chrome/browser/passwords/bottom_sheet/ui/passkey_creation_bottom_sheet_consumer.h +++ b/ios/chrome/browser/passwords/bottom_sheet/ui/passkey_creation_bottom_sheet_consumer.h @@ -7,13 +7,14 @@ #import <Foundation/Foundation.h> -#import "url/gurl.h" - // Delegate for the passkey creation bottom sheet. @protocol PasskeyCreationBottomSheetConsumer -// Sets the username, email and url for the current passkey request. -- (void)setUsername:(NSString*)username email:(NSString*)email url:(GURL)URL; +// Sets the username, email and relying party identifier for the current passkey +// request. +- (void)setUsername:(NSString*)username + email:(NSString*)email + rpId:(NSString*)rpId; @end diff --git a/ios/chrome/browser/passwords/bottom_sheet/ui/passkey_creation_bottom_sheet_view_controller.mm b/ios/chrome/browser/passwords/bottom_sheet/ui/passkey_creation_bottom_sheet_view_controller.mm index 015f54e..331b9a2 100644 --- a/ios/chrome/browser/passwords/bottom_sheet/ui/passkey_creation_bottom_sheet_view_controller.mm +++ b/ios/chrome/browser/passwords/bottom_sheet/ui/passkey_creation_bottom_sheet_view_controller.mm @@ -160,8 +160,8 @@ // The email for the passkey request. NSString* _email; - // URL of the current page the bottom sheet is being displayed on. - GURL _url; + // Relying party identifier of the passkey request. + NSString* _rpId; // The passkey creation handler for user actions. __weak id<BrowserCoordinatorCommands> _handler; @@ -217,10 +217,12 @@ #pragma mark - PasskeyCreationBottomSheetConsumer -- (void)setUsername:(NSString*)username email:(NSString*)email url:(GURL)url { +- (void)setUsername:(NSString*)username + email:(NSString*)email + rpId:(NSString*)rpId { _username = username; _email = email; - _url = url; + _rpId = rpId; } #pragma mark - Private @@ -249,8 +251,9 @@ faviconView.contentMode = UIViewContentModeScaleAspectFit; faviconView.tintColor = [UIColor colorNamed:kTextPrimaryColor]; + GURL pageURL("https://" + base::SysNSStringToUTF8(_rpId)); _faviconLoader->FaviconForPageUrl( - _url, kFaviconSize, kFaviconSize, + pageURL, kFaviconSize, kFaviconSize, /*fallback_to_google_server=*/true, ^(FaviconAttributes* attributes, bool cached) { [faviconView configureWithAttributes:attributes]; @@ -262,7 +265,7 @@ usernameLabel.text = _username; UILabel* domainLabel = CreateDomainLabel(); - domainLabel.text = base::SysUTF8ToNSString(_url.host()); + domainLabel.text = _rpId; UIStackView* textStack = CreateLabelsStackView(@[ usernameLabel, domainLabel ]); diff --git a/ios/chrome/browser/passwords/bottom_sheet/ui/passkey_creation_bottom_sheet_view_controller_unittest.mm b/ios/chrome/browser/passwords/bottom_sheet/ui/passkey_creation_bottom_sheet_view_controller_unittest.mm index 3512a092..6331d17 100644 --- a/ios/chrome/browser/passwords/bottom_sheet/ui/passkey_creation_bottom_sheet_view_controller_unittest.mm +++ b/ios/chrome/browser/passwords/bottom_sheet/ui/passkey_creation_bottom_sheet_view_controller_unittest.mm @@ -21,7 +21,6 @@
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/ios/chrome/browser/passwords/bottom_sheet/ui/passkey_creation_bottom_sheet_view_controller_unittest.mm b/ios/chrome/browser/passwords/bottom_sheet/ui/passkey_creation_bottom_sheet_view_controller_unittest.mm
index 3512a092..6331d17 100644
--- a/ios/chrome/browser/passwords/bottom_sheet/ui/passkey_creation_bottom_sheet_view_controller_unittest.mm
+++ b/ios/chrome/browser/passwords/bottom_sheet/ui/passkey_creation_bottom_sheet_view_controller_unittest.mm
@@ -21,7 +21,6 @@
#import "third_party/ocmock/OCMock/OCMock.h"
#import "third_party/ocmock/gtest_support.h"
#import "ui/base/l10n/l10n_util.h"
-#import "url/gurl.h"
// Tests for PasskeyCreationBottomSheetViewController.
class PasskeyCreationBottomSheetViewControllerTest : public PlatformTest {
@@ -42,9 +41,9 @@
TEST_F(PasskeyCreationBottomSheetViewControllerTest, BasicInformation) {
NSString* username = @"user";
NSString* email = @"[email protected]";
- GURL url("https://example.com");
+ NSString* rpId = @"example.com";
- [view_controller_ setUsername:username email:email url:url];
+ [view_controller_ setUsername:username email:email rpId:rpId];
[view_controller_ loadView];
[view_controller_ viewDidLoad];
@@ -71,7 +70,7 @@
base::apple::ObjCCast<UILabel>(labelsStackView.arrangedSubviews[1]);
EXPECT_NSEQ(username, usernameLabel.text);
- EXPECT_NSEQ(base::SysUTF8ToNSString(url.host()), domainLabel.text);
+ EXPECT_NSEQ(rpId, domainLabel.text);
// Verifies the button stack configuration.
EXPECT_NSEQ(
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