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 <yoichio@chromium.org>
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 <bashi@chromium.org>
Commit-Queue: Yoichi Osato <yoichio@chromium.org>
Reviewed-by: Charlie Reis <creis@chromium.org>
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