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 <rgod@google.com>
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 <sugoi@chromium.org>
Commit-Queue: Rafał Godlewski <rgod@google.com>
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@example.com";
- 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