Chrome · Passwords
CVE-2026-87583
Logic Error in Passwords
Overview
Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
TEST_Fchrome/browser/touch_to_fill/password_manager/touch_to_fill_password_manager_webauthn_delegate_unittest.cc |
modified | |
GURLchrome/browser/webauthn/touch_to_fill_credential_receiver.h |
modified |
Files Changed
chrome/browser/touch_to_fill/password_manager/touch_to_fill_password_manager_credential_delegate.ccchrome/browser/touch_to_fill/password_manager/touch_to_fill_password_manager_credential_delegate.hchrome/browser/touch_to_fill/password_manager/touch_to_fill_password_manager_delegate.hchrome/browser/touch_to_fill/password_manager/touch_to_fill_password_manager_webauthn_delegate.ccchrome/browser/touch_to_fill/password_manager/touch_to_fill_password_manager_webauthn_delegate.hchrome/browser/touch_to_fill/password_manager/touch_to_fill_password_manager_webauthn_delegate_unittest.ccchrome/browser/webauthn/android/webauthn_request_delegate_android.ccchrome/browser/webauthn/android/webauthn_request_delegate_android.hchrome/browser/webauthn/touch_to_fill_credential_receiver.h
Patch
From 49e2dbf4709abf6b1de30e5a27bcdac76e872bec Mon Sep 17 00:00:00 2001
From: Friedrich Horschig <friedrichh@chromium.org>
Date: Tue, 28 Jul 2026 06:46:55 -0700
Subject: [PATCH] [Android][WebAuthn] Fix frame origin retrieval in TTF Delegate
Prior to this CL, the origin of the parent frame would always be used
when the "No Passkeys bottom sheet" shows up for a request originating
from a subframe.
This CL fixes the display issue and the const correctness of the getter.
Fixed: 533116484
Change-Id: Ib1ecba0e949754d487637c30e8aae0a430212c02
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8163621
Reviewed-by: Adem Derinel <derinel@google.com>
Commit-Queue: Friedrich Hauser <friedrichh@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1669428}
---
diff --git a/chrome/browser/touch_to_fill/password_manager/touch_to_fill_password_manager_credential_delegate.cc b/chrome/browser/touch_to_fill/password_manager/touch_to_fill_password_manager_credential_delegate.cc
index 1e874b6..7cc957d4 100644
--- a/chrome/browser/touch_to_fill/password_manager/touch_to_fill_password_manager_credential_delegate.cc
+++ b/chrome/browser/touch_to_fill/password_manager/touch_to_fill_password_manager_credential_delegate.cc
@@ -228,12 +228,13 @@
std::move(action_completed).Run();
}
-GURL TouchToFillPasswordManagerCredentialDelegate::GetFrameUrl() {
+GURL TouchToFillPasswordManagerCredentialDelegate::GetFrameUrl() const {
CHECK(filler_);
return filler_->GetFrameUrl();
}
-url::Origin TouchToFillPasswordManagerCredentialDelegate::GetFrameOrigin() {
+url::Origin TouchToFillPasswordManagerCredentialDelegate::GetFrameOrigin()
+ const {
CHECK(filler_);
return filler_->GetFrameOrigin();
}
diff --git a/chrome/browser/touch_to_fill/password_manager/touch_to_fill_password_manager_credential_delegate.h b/chrome/browser/touch_to_fill/password_manager/touch_to_fill_password_manager_credential_delegate.h
index c820880..245a2af3 100644
--- a/chrome/browser/touch_to_fill/password_manager/touch_to_fill_password_manager_credential_delegate.h
+++ b/chrome/browser/touch_to_fill/password_manager/touch_to_fill_password_manager_credential_delegate.h
@@ -126,8 +126,8 @@
void OnHybridSignInSelected(base::OnceClosure action_completed) override;
void OnDismiss(base::OnceClosure action_completed) override;
void OnCredManDismissed(base::OnceClosure action_completed) override;
- GURL GetFrameUrl() override;
- url::Origin GetFrameOrigin() override;
+ GURL GetFrameUrl() const override;
+ url::Origin GetFrameOrigin() const override;
bool ShouldShowTouchToFill() override;
bool ShouldTriggerSubmission() override;
bool ShouldShowHybridOption() override;
diff --git a/chrome/browser/touch_to_fill/password_manager/touch_to_fill_password_manager_delegate.h b/chrome/browser/touch_to_fill/password_manager/touch_to_fill_password_manager_delegate.h
index 7aff6db..11fd5cc 100644
--- a/chrome/browser/touch_to_fill/password_manager/touch_to_fill_password_manager_delegate.h
+++ b/chrome/browser/touch_to_fill/password_manager/touch_to_fill_password_manager_delegate.h
@@ -64,11 +64,11 @@
// Gets the last committed URL for the frame that triggered this sheet to be
// created.
- virtual GURL GetFrameUrl() = 0;
+ virtual GURL GetFrameUrl() const = 0;
// Gets the last committed origin for the frame that triggered this sheet to
// be created.
- virtual url::Origin GetFrameOrigin() = 0;
+ virtual url::Origin GetFrameOrigin() const = 0;
// Returns whether TTF is eligible for showing for the currently focused field
// (e. g. it should not be triggered for the new password field).
diff --git a/chrome/browser/touch_to_fill/password_manager/touch_to_fill_password_manager_webauthn_delegate.cc b/chrome/browser/touch_to_fill/password_manager/touch_to_fill_password_manager_webauthn_delegate.cc
index b40b068..ab61e7a 100644
--- a/chrome/browser/touch_to_fill/password_manager/touch_to_fill_password_manager_webauthn_delegate.cc
+++ b/chrome/browser/touch_to_fill/password_manager/touch_to_fill_password_manager_webauthn_delegate.cc
@@ -82,16 +82,13 @@
std::move(action_completed).Run();
}
-GURL TouchToFillPasswordManagerWebAuthnDelegate::GetFrameUrl() {
- return credential_receiver_->web_contents()->GetLastCommittedURL();
+GURL TouchToFillPasswordManagerWebAuthnDelegate::GetFrameUrl() const {
+ return credential_receiver_ ? credential_receiver_->GetFrameUrl() : GURL();
}
-url::Origin TouchToFillPasswordManagerWebAuthnDelegate::GetFrameOrigin() {
- return credential_receiver_->web_contents()
- ? credential_receiver_->web_contents()
- ->GetPrimaryMainFrame()
- ->GetLastCommittedOrigin()
- : url::Origin();
+url::Origin TouchToFillPasswordManagerWebAuthnDelegate::GetFrameOrigin() const {
+ return credential_receiver_ ? credential_receiver_->GetFrameOrigin()
+ : url::Origin();
}
bool TouchToFillPasswordManagerWebAuthnDelegate::ShouldShowTouchToFill() {
diff --git a/chrome/browser/touch_to_fill/password_manager/touch_to_fill_password_manager_webauthn_delegate.h b/chrome/browser/touch_to_fill/password_manager/touch_to_fill_password_manager_webauthn_delegate.h
index 56b3cf1..39aada9 100644
--- a/chrome/browser/touch_to_fill/password_manager/touch_to_fill_password_manager_webauthn_delegate.h
+++ b/chrome/browser/touch_to_fill/password_manager/touch_to_fill_password_manager_webauthn_delegate.h
@@ -68,8 +68,8 @@
void OnHybridSignInSelected(base::OnceClosure action_completed) override;
void OnDismiss(base::OnceClosure action_completed) override;
void OnCredManDismissed(base::OnceClosure action_completed) override;
- GURL GetFrameUrl() override;
- url::Origin GetFrameOrigin() override;
+ GURL GetFrameUrl() const override;
+ url::Origin GetFrameOrigin() const override;
bool ShouldShowTouchToFill() override;
bool ShouldTriggerSubmission() override;
bool ShouldShowHybridOption() override;
diff --git a/chrome/browser/touch_to_fill/password_manager/touch_to_fill_password_manager_webauthn_delegate_unittest.cc b/chrome/browser/touch_to_fill/password_manager/touch_to_fill_password_manager_webauthn_delegate_unittest.cc
index 02d1027..172a8cd 100644
--- a/chrome/browser/touch_to_fill/password_manager/touch_to_fill_password_manager_webauthn_delegate_unittest.cc
+++ b/chrome/browser/touch_to_fill/password_manager/touch_to_fill_password_manager_webauthn_delegate_unittest.cc
@@ -100,6 +100,14 @@
MOCK_METHOD(void, OnHybridSignInSelected, (), (override));
content::WebContents* web_contents() override { return web_contents_; }
+ GURL GetFrameUrl() const override {
+ return web_contents_ ? web_contents_->GetLastCommittedURL() : GURL();
+ }
+ url::Origin GetFrameOrigin() const override {
+ return web_contents_
+ ? web_contents_->GetPrimaryMainFrame()->GetLastCommittedOrigin()
+ : url::Origin();
+ }
private:
raw_ptr<content::WebContents> web_contents_;
@@ -373,3 +381,25 @@
std::vector<TouchToFillPasswordManagerView::Credential>,
bool)>(webauthn::sorting::SortTouchToFillCredentials)));
}
+
+TEST_F(TouchToFillPasswordManagerWebAuthnDelegateTest, GetFrameUrlAndOrigin) {
+ auto delegate = MakeTouchToFillPasswordManagerControllerDelegate(
+ /*should_show_hybrid_option=*/false,
+ /*is_immediate=*/true,
+ /*sorting_callback=*/base::NullCallback());
+
+ EXPECT_EQ(delegate->GetFrameUrl(), GURL(kExampleCom));
+ EXPECT_EQ(delegate->GetFrameOrigin(), url::Origin::Create(GURL(kExampleCom)));
+}
+
+TEST_F(TouchToFillPasswordManagerWebAuthnDelegateTest,
+ GetFrameUrlAndOriginNullReceiver) {
+ TouchToFillPasswordManagerWebAuthnDelegate delegate(
+ /*receiver=*/nullptr,
+ /*sort_credentials_callback=*/base::NullCallback(),
+ /*should_show_hybrid_option=*/false,
+ /*is_immediate=*/true);
+
+ EXPECT_EQ(delegate.GetFrameUrl(), GURL());
+ EXPECT_TRUE(delegate.GetFrameOrigin().opaque());
+}
diff --git a/chrome/browser/webauthn/android/webauthn_request_delegate_android.cc b/chrome/browser/webauthn/android/webauthn_request_delegate_android.cc
index cde7019e..c9ee628b 100644
--- a/chrome/browser/webauthn/android/webauthn_request_delegate_android.cc
+++ b/chrome/browser/webauthn/android/webauthn_request_delegate_android.cc
@@ -251,3 +251,11 @@
content::WebContents* WebAuthnRequestDelegateAndroid::web_contents() {
return content::WebContents::FromRenderFrameHost(&render_frame_host());
}
+
+GURL WebAuthnRequestDelegateAndroid::GetFrameUrl() const {
+ return render_frame_host().GetLastCommittedURL();
+}
+
+url::Origin WebAuthnRequestDelegateAndroid::GetFrameOrigin() const {
+ return render_frame_host().GetLastCommittedOrigin();
+}
diff --git a/chrome/browser/webauthn/android/webauthn_request_delegate_android.h b/chrome/browser/webauthn/android/webauthn_request_delegate_android.h
index 0b067c6..ee9392d 100644
--- a/chrome/browser/webauthn/android/webauthn_request_delegate_android.h
+++ b/chrome/browser/webauthn/android/webauthn_request_delegate_android.h
@@ -80,6 +80,8 @@
void OnCredentialSelectionDeclined() override;
void OnHybridSignInSelected() override;
content::WebContents* web_contents() override;
+ GURL GetFrameUrl() const override;
+ url::Origin GetFrameOrigin() const override;
// Returns a delegate associated with the |frame_host|. It creates one if
// one does not already exist.
diff --git a/chrome/browser/webauthn/touch_to_fill_credential_receiver.h b/chrome/browser/webauthn/touch_to_fill_credential_receiver.h
index c963c31..4da9f8d1b 100644
--- a/chrome/browser/webauthn/touch_to_fill_credential_receiver.h
+++ b/chrome/browser/webauthn/touch_to_fill_credential_receiver.h
@@ -9,6 +9,9 @@
#include <vector>
#include "chrome/browser/webauthn/shared_types.h"
+#include "url/origin.h"
+
+class GURL;
namespace content {
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/chrome/browser/touch_to_fill/password_manager/touch_to_fill_password_manager_webauthn_delegate_unittest.cc b/chrome/browser/touch_to_fill/password_manager/touch_to_fill_password_manager_webauthn_delegate_unittest.cc
index 02d1027..172a8cd 100644
--- a/chrome/browser/touch_to_fill/password_manager/touch_to_fill_password_manager_webauthn_delegate_unittest.cc
+++ b/chrome/browser/touch_to_fill/password_manager/touch_to_fill_password_manager_webauthn_delegate_unittest.cc
@@ -100,6 +100,14 @@
MOCK_METHOD(void, OnHybridSignInSelected, (), (override));
content::WebContents* web_contents() override { return web_contents_; }
+ GURL GetFrameUrl() const override {
+ return web_contents_ ? web_contents_->GetLastCommittedURL() : GURL();
+ }
+ url::Origin GetFrameOrigin() const override {
+ return web_contents_
+ ? web_contents_->GetPrimaryMainFrame()->GetLastCommittedOrigin()
+ : url::Origin();
+ }
private:
raw_ptr<content::WebContents> web_contents_;
@@ -373,3 +381,25 @@
std::vector<TouchToFillPasswordManagerView::Credential>,
bool)>(webauthn::sorting::SortTouchToFillCredentials)));
}
+
+TEST_F(TouchToFillPasswordManagerWebAuthnDelegateTest, GetFrameUrlAndOrigin) {
+ auto delegate = MakeTouchToFillPasswordManagerControllerDelegate(
+ /*should_show_hybrid_option=*/false,
+ /*is_immediate=*/true,
+ /*sorting_callback=*/base::NullCallback());
+
+ EXPECT_EQ(delegate->GetFrameUrl(), GURL(kExampleCom));
+ EXPECT_EQ(delegate->GetFrameOrigin(), url::Origin::Create(GURL(kExampleCom)));
+}
+
+TEST_F(TouchToFillPasswordManagerWebAuthnDelegateTest,
+ GetFrameUrlAndOriginNullReceiver) {
+ TouchToFillPasswordManagerWebAuthnDelegate delegate(
+ /*receiver=*/nullptr,
+ /*sort_credentials_callback=*/base::NullCallback(),
+ /*should_show_hybrid_option=*/false,
+ /*is_immediate=*/true);
+
+ EXPECT_EQ(delegate.GetFrameUrl(), GURL());
+ EXPECT_TRUE(delegate.GetFrameOrigin().opaque());
+}
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