Chrome · Network
CVE-2026-8572
Logic Error in Network
Overview
Medium
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifservices/network/restricted_cookie_manager.cc |
modified | |
TEST_Pservices/network/restricted_cookie_manager_unittest.cc |
modified |
Files Changed
services/network/restricted_cookie_manager.ccservices/network/restricted_cookie_manager_unittest.cc
Patch
From 225000ab6d13272cf32d41ea8cdba1ff65835a86 Mon Sep 17 00:00:00 2001 From: Yoichi Osato <[email protected]> Date: Mon, 30 Mar 2026 22:09:41 -0700 Subject: [PATCH] Report mojo bad message for incorrect site_for_cookies and top_frame_origin RestrictedCookieManager now explicitly reports a bad message and terminates the connection if the renderer provides an incorrect site_for_cookies or top_frame_origin. Previously, these mismatches were only logged as errors without further action. This change ensures that inconsistencies between the renderer's provided context and the browser's bound state are treated as protocol violations. Fixed: 495405493 Change-Id: Ifcecd1250f4fc9d5015369ac9df7914e317d8974 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7707502 Reviewed-by: Kenichi Ishibashi <[email protected]> Commit-Queue: Yoichi Osato <[email protected]> Reviewed-by: Charlie Reis <[email protected]> Cr-Commit-Position: refs/heads/main@{#1607622} --- diff --git a/services/network/restricted_cookie_manager.cc b/services/network/restricted_cookie_manager.cc index e12ef95d..84099f23 100644 --- a/services/network/restricted_cookie_manager.cc +++ b/services/network/restricted_cookie_manager.cc @@ -1145,20 +1145,20 @@ bool site_for_cookies_ok = BoundSiteForCookies().IsEquivalent(site_for_cookies); - // TODO(crbug.com/402207912): Switch back to a DCEHCK once this condition - // always holds again. if (!site_for_cookies_ok) { LOG(ERROR) << "site_for_cookies from renderer='" << site_for_cookies.ToDebugString() << "' from browser='" << BoundSiteForCookies().ToDebugString() << "';"; + receiver_.ReportBadMessage("Incorrect site_for_cookies"); + return false; } bool top_frame_origin_ok = (top_frame_origin == BoundTopFrameOrigin()); - // TODO(crbug.com/402207912): Switch back to a DCEHCK once this condition - // always holds again. if (!top_frame_origin_ok) { LOG(ERROR) << "top_frame_origin from renderer='" << top_frame_origin << "' from browser='" << BoundTopFrameOrigin() << "';"; + receiver_.ReportBadMessage("Incorrect top_frame_origin"); + return false; } if (metrics_subsampler_.ShouldSample(net::kHistogramSampleProbability)) { diff --git a/services/network/restricted_cookie_manager_unittest.cc b/services/network/restricted_cookie_manager_unittest.cc index ebbcd2db..1219d50 100644 --- a/services/network/restricted_cookie_manager_unittest.cc +++ b/services/network/restricted_cookie_manager_unittest.cc @@ -429,7 +429,10 @@ return std::make_unique<TestCookieChangeListener>(std::move(receiver)); } - void ExpectBadMessage() { expecting_bad_message_ = true; } + void ExpectBadMessage(const std::string& reason = "") { + expecting_bad_message_ = true; + expected_bad_message_reason_ = reason; + } bool received_bad_message() { return received_bad_message_; } @@ -438,6 +441,9 @@ protected: void OnBadMessage(const std::string& reason) { EXPECT_TRUE(expecting_bad_message_) << "Unexpected bad message: " << reason; + if (!expected_bad_message_reason_.empty()) { + EXPECT_EQ(expected_bad_message_reason_, reason); + } received_bad_message_ = true; } @@ -485,6 +491,7 @@ mojo::Receiver<mojom::RestrictedCookieManager> receiver_; std::unique_ptr<RestrictedCookieManagerSync> sync_service_; bool expecting_bad_message_ = false; + std::string expected_bad_message_reason_; bool received_bad_message_ = false; }; @@ -550,7 +557,7 @@ auto options = mojom::CookieManagerGetOptions::New(); options->name = "new-name"; options->match_type = mojom::CookieMatchType::EQUALS; - ExpectBadMessage(); + ExpectBadMessage("Incorrect url origin"); std::vector<net::CanonicalCookie> cookies = sync_service_->GetAllForUrl( kDefaultUrl, kDefaultSiteForCookies, kDefaultOrigin, net::StorageAccessApiStatus::kNone, std::move(options)); @@ -779,7 +786,7 @@ SetSessionCookie("other-cookie-name", "other-cookie-value", "notexample.com", "/"); - ExpectBadMessage(); + ExpectBadMessage("Incorrect url origin"); EXPECT_THAT(sync_service_->GetAllForUrl( kOtherUrlWithPath, kDefaultSiteForCookies, kDefaultOrigin, net::StorageAccessApiStatus::kNone, GetAllCookiesOptions()), @@ -787,6 +794,24 @@ EXPECT_TRUE(received_bad_message()); } +TEST_P(RestrictedCookieManagerTest, GetAllForUrlFromWrongSiteForCookies) { + ExpectBadMessage("Incorrect site_for_cookies"); + EXPECT_THAT(sync_service_->GetAllForUrl( + kDefaultUrlWithPath, kOtherSiteForCookies, kDefaultOrigin, + net::StorageAccessApiStatus::kNone, GetAllCookiesOptions()), + IsEmpty()); + EXPECT_TRUE(received_bad_message()); +} + +TEST_P(RestrictedCookieManagerTest, GetAllForUrlFromWrongTopFrameOrigin) { + ExpectBadMessage("Incorrect top_frame_origin"); + EXPECT_THAT(sync_service_->GetAllForUrl( + kDefaultUrlWithPath, kDefaultSiteForCookies, kOtherOrigin, + net::StorageAccessApiStatus::kNone, GetAllCookiesOptions()), + IsEmpty()); + EXPECT_TRUE(received_bad_message()); +} + TEST_P(RestrictedCookieManagerTest, GetAllForUrlFromOpaqueOrigin) { SetSessionCookie("cookie-name", "cookie-value", "example.com", "/"); @@ -794,7 +819,7 @@ ASSERT_TRUE(opaque_origin.opaque()); service_->OverrideOriginForTesting(opaque_origin); - ExpectBadMessage(); + ExpectBadMessage("Access is denied in this context"); EXPECT_THAT(sync_service_->GetAllForUrl( kDefaultUrlWithPath, kDefaultSiteForCookies, kDefaultOrigin, net::StorageAccessApiStatus::kNone, GetAllCookiesOptions()), @@ -877,7 +902,7 @@ SetSessionCookie("other-cookie-name", "other-cookie-value", "notexample.com", "/"); - ExpectBadMessage(); + ExpectBadMessage("Incorrect url origin"); std::string cookies_out; base::ReadOnlySharedMemoryRegion mapped_region; uint64_t version; @@ -1358,7 +1383,7 @@ } TEST_P(RestrictedCookieManagerTest, SetCanonicalCookieFromWrongOrigin) { - ExpectBadMessage(); + ExpectBadMessage("Incorrect url origin"); EXPECT_FALSE(sync_service_->SetCanonicalCookie( mojom::RestrictedCanonicalCookieParams::New( "new-name", "new-value", "notexample.com", "/", base::Time(), @@ -1376,7 +1401,7 @@ ASSERT_TRUE(opaque_origin.opaque()); service_->OverrideOriginForTesting(opaque_origin); - ExpectBadMessage(); + ExpectBadMessage("Access is denied in this context"); EXPECT_FALSE(sync_service_->SetCanonicalCookie( mojom::RestrictedCanonicalCookieParams::New( "new-name", "new-value", "example.com", "/", base::Time(), @@ -1390,7 +1415,7 @@ } TEST_P(RestrictedCookieManagerTest, SetCanonicalCookieWithMismatchingDomain) { - ExpectBadMessage(); + ExpectBadMessage("Setting cookies on other domains is disallowed."); EXPECT_FALSE(sync_service_->SetCanonicalCookie( mojom::RestrictedCanonicalCookieParams::New( "new-name", "new-value", "not-example.com", "/", base::Time(), @@ -1404,7 +1429,7 @@ } TEST_P(RestrictedCookieManagerTest, SetCookieFromStringWrongOrigin) { - ExpectBadMessage(); + ExpectBadMessage("Incorrect url origin"); auto response = sync_service_->SetCookieFromString( kOtherUrlWithPath, kDefaultSiteForCookies, kDefaultOrigin, net::StorageAccessApiStatus::kNone, /*get_version_shared_memory=*/false, @@ -1712,7 +1737,7 @@ mojo::PendingRemote<network::mojom::CookieChangeListener> bad_listener_remote; mojo::PendingReceiver<network::mojom::CookieChangeListener> bad_receiver = bad_listener_remote.InitWithNewPipeAndPassReceiver(); - ExpectBadMessage(); + ExpectBadMessage("Incorrect url origin"); sync_service_->AddChangeListener( kOtherUrlWithPath, kDefaultSiteForCookies, kDefaultOrigin, net::StorageAccessApiStatus::kNone, std::move(bad_listener_remote)); @@ -1753,7 +1778,7 @@ mojo::PendingRemote<network::mojom::CookieChangeListener> bad_listener_remote; mojo::PendingReceiver<network::mojom::CookieChangeListener> bad_receiver = bad_listener_remote.InitWithNewPipeAndPassReceiver(); - ExpectBadMessage(); + ExpectBadMessage("Access is denied in this context"); sync_service_->AddChangeListener( kDefaultUrlWithPath, kDefaultSiteForCookies, kDefaultOrigin,
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/services/network/restricted_cookie_manager_unittest.cc b/services/network/restricted_cookie_manager_unittest.cc
index ebbcd2db..1219d50 100644
--- a/services/network/restricted_cookie_manager_unittest.cc
+++ b/services/network/restricted_cookie_manager_unittest.cc
@@ -429,7 +429,10 @@
return std::make_unique<TestCookieChangeListener>(std::move(receiver));
}
- void ExpectBadMessage() { expecting_bad_message_ = true; }
+ void ExpectBadMessage(const std::string& reason = "") {
+ expecting_bad_message_ = true;
+ expected_bad_message_reason_ = reason;
+ }
bool received_bad_message() { return received_bad_message_; }
@@ -438,6 +441,9 @@
protected:
void OnBadMessage(const std::string& reason) {
EXPECT_TRUE(expecting_bad_message_) << "Unexpected bad message: " << reason;
+ if (!expected_bad_message_reason_.empty()) {
+ EXPECT_EQ(expected_bad_message_reason_, reason);
+ }
received_bad_message_ = true;
}
@@ -485,6 +491,7 @@
mojo::Receiver<mojom::RestrictedCookieManager> receiver_;
std::unique_ptr<RestrictedCookieManagerSync> sync_service_;
bool expecting_bad_message_ = false;
+ std::string expected_bad_message_reason_;
bool received_bad_message_ = false;
};
@@ -550,7 +557,7 @@
auto options = mojom::CookieManagerGetOptions::New();
options->name = "new-name";
options->match_type = mojom::CookieMatchType::EQUALS;
- ExpectBadMessage();
+ ExpectBadMessage("Incorrect url origin");
std::vector<net::CanonicalCookie> cookies = sync_service_->GetAllForUrl(
kDefaultUrl, kDefaultSiteForCookies, kDefaultOrigin,
net::StorageAccessApiStatus::kNone, std::move(options));
@@ -779,7 +786,7 @@
SetSessionCookie("other-cookie-name", "other-cookie-value", "notexample.com",
"/");
- ExpectBadMessage();
+ ExpectBadMessage("Incorrect url origin");
EXPECT_THAT(sync_service_->GetAllForUrl(
kOtherUrlWithPath, kDefaultSiteForCookies, kDefaultOrigin,
net::StorageAccessApiStatus::kNone, GetAllCookiesOptions()),
@@ -787,6 +794,24 @@
EXPECT_TRUE(received_bad_message());
}
+TEST_P(RestrictedCookieManagerTest, GetAllForUrlFromWrongSiteForCookies) {
+ ExpectBadMessage("Incorrect site_for_cookies");
+ EXPECT_THAT(sync_service_->GetAllForUrl(
+ kDefaultUrlWithPath, kOtherSiteForCookies, kDefaultOrigin,
+ net::StorageAccessApiStatus::kNone, GetAllCookiesOptions()),
+ IsEmpty());
+ EXPECT_TRUE(received_bad_message());
+}
+
+TEST_P(RestrictedCookieManagerTest, GetAllForUrlFromWrongTopFrameOrigin) {
+ ExpectBadMessage("Incorrect top_frame_origin");
+ EXPECT_THAT(sync_service_->GetAllForUrl(
+ kDefaultUrlWithPath, kDefaultSiteForCookies, kOtherOrigin,
+ net::StorageAccessApiStatus::kNone, GetAllCookiesOptions()),
+ IsEmpty());
+ EXPECT_TRUE(received_bad_message());
+}
+
TEST_P(RestrictedCookieManagerTest, GetAllForUrlFromOpaqueOrigin) {
SetSessionCookie("cookie-name", "cookie-value", "example.com", "/");
@@ -794,7 +819,7 @@
ASSERT_TRUE(opaque_origin.opaque());
service_->OverrideOriginForTesting(opaque_origin);
- ExpectBadMessage();
+ ExpectBadMessage("Access is denied in this context");
EXPECT_THAT(sync_service_->GetAllForUrl(
kDefaultUrlWithPath, kDefaultSiteForCookies, kDefaultOrigin,
net::StorageAccessApiStatus::kNone, GetAllCookiesOptions()),
@@ -877,7 +902,7 @@
SetSessionCookie("other-cookie-name", "other-cookie-value", "notexample.com",
"/");
- ExpectBadMessage();
+ ExpectBadMessage("Incorrect url origin");
std::string cookies_out;
base::ReadOnlySharedMemoryRegion mapped_region;
uint64_t version;
@@ -1358,7 +1383,7 @@
}
TEST_P(RestrictedCookieManagerTest, SetCanonicalCookieFromWrongOrigin) {
- ExpectBadMessage();
+ ExpectBadMessage("Incorrect url origin");
EXPECT_FALSE(sync_service_->SetCanonicalCookie(
mojom::RestrictedCanonicalCookieParams::New(
"new-name", "new-value", "notexample.com", "/", base::Time(),
@@ -1376,7 +1401,7 @@
ASSERT_TRUE(opaque_origin.opaque());
service_->OverrideOriginForTesting(opaque_origin);
- ExpectBadMessage();
+ ExpectBadMessage("Access is denied in this context");
EXPECT_FALSE(sync_service_->SetCanonicalCookie(
mojom::RestrictedCanonicalCookieParams::New(
"new-name", "new-value", "example.com", "/", base::Time(),
@@ -1390,7 +1415,7 @@
}
TEST_P(RestrictedCookieManagerTest, SetCanonicalCookieWithMismatchingDomain) {
- ExpectBadMessage();
+ ExpectBadMessage("Setting cookies on other domains is disallowed.");
EXPECT_FALSE(sync_service_->SetCanonicalCookie(
mojom::RestrictedCanonicalCookieParams::New(
"new-name", "new-value", "not-example.com", "/", base::Time(),
@@ -1404,7 +1429,7 @@
}
TEST_P(RestrictedCookieManagerTest, SetCookieFromStringWrongOrigin) {
- ExpectBadMessage();
+ ExpectBadMessage("Incorrect url origin");
auto response = sync_service_->SetCookieFromString(
kOtherUrlWithPath, kDefaultSiteForCookies, kDefaultOrigin,
net::StorageAccessApiStatus::kNone, /*get_version_shared_memory=*/false,
@@ -1712,7 +1737,7 @@
mojo::PendingRemote<network::mojom::CookieChangeListener> bad_listener_remote;
mojo::PendingReceiver<network::mojom::CookieChangeListener> bad_receiver =
bad_listener_remote.InitWithNewPipeAndPassReceiver();
- ExpectBadMessage();
+ ExpectBadMessage("Incorrect url origin");
sync_service_->AddChangeListener(
kOtherUrlWithPath, kDefaultSiteForCookies, kDefaultOrigin,
net::StorageAccessApiStatus::kNone, std::move(bad_listener_remote));
@@ -1753,7 +1778,7 @@
mojo::PendingRemote<network::mojom::CookieChangeListener> bad_listener_remote;
mojo::PendingReceiver<network::mojom::CookieChangeListener> bad_receiver =
bad_listener_remote.InitWithNewPipeAndPassReceiver();
- ExpectBadMessage();
+ ExpectBadMessage("Access is denied in this context");
sync_service_->AddChangeListener(
kDefaultUrlWithPath, kDefaultSiteForCookies, kDefaultOrigin,
net::StorageAccessApiStatus::kNone, std::move(bad_listener_remote));
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