Chrome · FedCM
CVE-2026-14057
Logic Error in FedCM
Overview
Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
TEST_Fcontent/browser/webid/delegation/email_verification_request_unittest.cc |
modified | |
TESTcontent/browser/webid/delegation/email_verification_request_unittest.cc |
modified |
Files Changed
content/browser/webid/delegation/email_verification_request.cccontent/browser/webid/delegation/email_verification_request_unittest.cc
Patch
From ffe4e01b5c5c58dfb8c811d141480ac496b4fcba Mon Sep 17 00:00:00 2001 From: Christian Biesinger <[email protected]> Date: Tue, 12 May 2026 11:50:58 -0700 Subject: [PATCH] [EVP] Disallow opaque origins Prevent Email Verification Protocol (EVP) from generating browser-signed assertions for opaque-origin frames, avoiding audience collapse to "null". [email protected] Fixed: 502212647 Change-Id: I778134f302a119796aca7a8cbfeccdd9f956c33a Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7829839 Commit-Queue: Christian Biesinger <[email protected]> Auto-Submit: Christian Biesinger <[email protected]> Reviewed-by: Sam Goto <[email protected]> Cr-Commit-Position: refs/heads/main@{#1629487} --- diff --git a/content/browser/webid/delegation/email_verification_request.cc b/content/browser/webid/delegation/email_verification_request.cc index 396a894..9e631934 100644 --- a/content/browser/webid/delegation/email_verification_request.cc +++ b/content/browser/webid/delegation/email_verification_request.cc @@ -106,6 +106,11 @@ const std::string& email, const std::string& nonce, EmailVerifier::OnEmailVerifiedCallback callback) { + if (render_frame_host_->GetLastCommittedOrigin().opaque()) { + std::move(callback).Run(std::nullopt); + return; + } + // Step 3: Token Request // Step 3.1: the browser extracts the domain from the email address and diff --git a/content/browser/webid/delegation/email_verification_request_unittest.cc b/content/browser/webid/delegation/email_verification_request_unittest.cc index b1d09378..ab6ced6 100644 --- a/content/browser/webid/delegation/email_verification_request_unittest.cc +++ b/content/browser/webid/delegation/email_verification_request_unittest.cc @@ -77,6 +77,8 @@ }; TEST_F(EmailVerificationRequestTest, SuccessfulVerification) { + NavigateAndCommit(GURL("https://rp.example.com")); + auto mock_dns_request_ptr = std::make_unique<NiceMock<MockDnsRequest>>(); NiceMock<MockDnsRequest>* mock_dns_request_ = mock_dns_request_ptr.get(); auto mock_network_manager_ptr = @@ -211,6 +213,8 @@ } TEST_F(EmailVerificationRequestTest, CrossOriginIssuanceEndpointRejected) { + NavigateAndCommit(GURL("https://rp.example.com")); + auto mock_dns_request_ptr = std::make_unique<NiceMock<MockDnsRequest>>(); NiceMock<MockDnsRequest>* mock_dns_request_ = mock_dns_request_ptr.get(); auto mock_network_manager_ptr = @@ -253,6 +257,33 @@ EXPECT_FALSE(token.has_value()); } +TEST_F(EmailVerificationRequestTest, OpaqueOriginRejected) { + NavigateAndCommit(GURL("data:text/html,<html></html>")); + + auto mock_dns_request_ptr = std::make_unique<NiceMock<MockDnsRequest>>(); + NiceMock<MockDnsRequest>* mock_dns_request_ = mock_dns_request_ptr.get(); + auto mock_network_manager_ptr = + std::make_unique<NiceMock<MockEmailVerifierNetworkRequestManager>>(); + NiceMock<MockEmailVerifierNetworkRequestManager>* mock_network_manager_ = + mock_network_manager_ptr.get(); + + webid::EmailVerificationRequest email_verification_request_( + std::move(mock_network_manager_ptr), std::move(mock_dns_request_ptr), + static_cast<RenderFrameHostImpl*>(main_rfh())->GetSafeRef()); + + const std::string kEmail = "[email protected]"; + const std::string kNonce = "test_nonce"; + + EXPECT_CALL(*mock_dns_request_, SendRequest).Times(0); + EXPECT_CALL(*mock_network_manager_, FetchWellKnown).Times(0); + EXPECT_CALL(*mock_network_manager_, SendTokenRequest).Times(0); + + base::test::TestFuture<std::optional<std::string>> future; + email_verification_request_.Send(kEmail, kNonce, future.GetCallback()); + std::optional<std::string> token = future.Get(); + EXPECT_FALSE(token.has_value()); +} + TEST(EmailVerificationRequestStaticTest, ValidEmail) { EXPECT_EQ(webid::GetDomainFromEmail("[email protected]"), "example.com"); }
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/content/browser/webid/delegation/email_verification_request_unittest.cc b/content/browser/webid/delegation/email_verification_request_unittest.cc
index b1d09378..ab6ced6 100644
--- a/content/browser/webid/delegation/email_verification_request_unittest.cc
+++ b/content/browser/webid/delegation/email_verification_request_unittest.cc
@@ -77,6 +77,8 @@
};
TEST_F(EmailVerificationRequestTest, SuccessfulVerification) {
+ NavigateAndCommit(GURL("https://rp.example.com"));
+
auto mock_dns_request_ptr = std::make_unique<NiceMock<MockDnsRequest>>();
NiceMock<MockDnsRequest>* mock_dns_request_ = mock_dns_request_ptr.get();
auto mock_network_manager_ptr =
@@ -211,6 +213,8 @@
}
TEST_F(EmailVerificationRequestTest, CrossOriginIssuanceEndpointRejected) {
+ NavigateAndCommit(GURL("https://rp.example.com"));
+
auto mock_dns_request_ptr = std::make_unique<NiceMock<MockDnsRequest>>();
NiceMock<MockDnsRequest>* mock_dns_request_ = mock_dns_request_ptr.get();
auto mock_network_manager_ptr =
@@ -253,6 +257,33 @@
EXPECT_FALSE(token.has_value());
}
+TEST_F(EmailVerificationRequestTest, OpaqueOriginRejected) {
+ NavigateAndCommit(GURL("data:text/html,<html></html>"));
+
+ auto mock_dns_request_ptr = std::make_unique<NiceMock<MockDnsRequest>>();
+ NiceMock<MockDnsRequest>* mock_dns_request_ = mock_dns_request_ptr.get();
+ auto mock_network_manager_ptr =
+ std::make_unique<NiceMock<MockEmailVerifierNetworkRequestManager>>();
+ NiceMock<MockEmailVerifierNetworkRequestManager>* mock_network_manager_ =
+ mock_network_manager_ptr.get();
+
+ webid::EmailVerificationRequest email_verification_request_(
+ std::move(mock_network_manager_ptr), std::move(mock_dns_request_ptr),
+ static_cast<RenderFrameHostImpl*>(main_rfh())->GetSafeRef());
+
+ const std::string kEmail = "[email protected]";
+ const std::string kNonce = "test_nonce";
+
+ EXPECT_CALL(*mock_dns_request_, SendRequest).Times(0);
+ EXPECT_CALL(*mock_network_manager_, FetchWellKnown).Times(0);
+ EXPECT_CALL(*mock_network_manager_, SendTokenRequest).Times(0);
+
+ base::test::TestFuture<std::optional<std::string>> future;
+ email_verification_request_.Send(kEmail, kNonce, future.GetCallback());
+ std::optional<std::string> token = future.Get();
+ EXPECT_FALSE(token.has_value());
+}
+
TEST(EmailVerificationRequestStaticTest, ValidEmail) {
EXPECT_EQ(webid::GetDomainFromEmail("[email protected]"), "example.com");
}
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