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 <cbiesinger@chromium.org>
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".
R=goto@chromium.org
Fixed: 502212647
Change-Id: I778134f302a119796aca7a8cbfeccdd9f956c33a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7829839
Commit-Queue: Christian Biesinger <cbiesinger@chromium.org>
Auto-Submit: Christian Biesinger <cbiesinger@chromium.org>
Reviewed-by: Sam Goto <goto@chromium.org>
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 = "test@example.com";
+ 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("test@example.com"), "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 = "test@example.com";
+ 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("test@example.com"), "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