Chrome · Network
CVE-2026-106234
UAF in Network
Overview
Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifservices/network/network_context.cc |
modified | |
TEST_Fservices/network/cookie_settings_unittest.cc |
modified | |
TEST_Fservices/network/network_context_unittest.cc |
modified |
Files Changed
services/network/cookie_settings_unittest.ccservices/network/network_context_unittest.ccservices/network/network_context.ccservices/network/cookie_settings.cc
Patch
From cb7afd9a9776ac9e363be4f36540895d5e5d7764 Mon Sep 17 00:00:00 2001
From: Patrick Meenan <pmeenan@chromium.org>
Date: Thu, 24 Sep 2026 10:36:46 -0700
Subject: [PATCH] Make CreateDeleteCookieOnExitPredicate self-contained
The predicate returned by CreateDeleteCookieOnExitPredicate() can be
evaluated asynchronously after cookie settings have been updated. Own a
snapshot of the cookie settings within the callback so that it does not
depend on the live CookieSettings instance, and handle empty predicates
when clearing session-only trust token data.
Bug: 564085088
Change-Id: I590f33f06cd4175cc84a0710b2e6f62da1170f09
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8436075
Reviewed-by: Tsuyoshi Horo <horo@chromium.org>
Commit-Queue: Patrick Meenan <pmeenan@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1704401}
---
diff --git a/services/network/cookie_settings.cc b/services/network/cookie_settings.cc
index 4a1bcba3..b4a7741 100644
--- a/services/network/cookie_settings.cc
+++ b/services/network/cookie_settings.cc
@@ -161,8 +161,16 @@
}
}
+ // The returned predicate may be evaluated asynchronously on a background
+ // sequence after `this` has been modified or destroyed, so bind an owned
+ // snapshot rather than `this`.
+ auto settings_snapshot = std::make_unique<CookieSettings>();
+ settings_snapshot->set_content_settings(ContentSettingsType::COOKIES,
+ settings);
+
return base::BindRepeating(&CookieSettings::ShouldDeleteCookieOnExit,
- base::Unretained(this), std::move(settings));
+ base::Owned(std::move(settings_snapshot)),
+ std::move(settings));
}
bool CookieSettings::ShouldIgnoreSameSiteRestrictions(
diff --git a/services/network/network_context.cc b/services/network/network_context.cc
index e65378a2e..4f879d0 100644
--- a/services/network/network_context.cc
+++ b/services/network/network_context.cc
@@ -1409,6 +1409,10 @@
DeleteCookiePredicate cookie_predicate =
cookie_manager_->cookie_settings().CreateDeleteCookieOnExitPredicate();
+ if (!cookie_predicate) {
+ std::move(callback).Run(false);
+ return;
+ }
auto store_predicate = base::BindRepeating(
[](DeleteCookiePredicate predicate, const std::string& origin) {
diff --git a/services/network/cookie_settings_unittest.cc b/services/network/cookie_settings_unittest.cc
index 5083b68b..584ab61 100644
--- a/services/network/cookie_settings_unittest.cc
+++ b/services/network/cookie_settings_unittest.cc
@@ -861,6 +861,29 @@
"foo.com", net::CookieSourceScheme::kNonSecure));
}
+TEST_F(CookieSettingsTest, CreateDeleteCookieOnExitPredicateOwnsSnapshot) {
+ auto settings = std::make_unique<CookieSettings>();
+ settings->set_content_settings(
+ ContentSettingsType::COOKIES,
+ {CreateSetting("https://foo.com", "*", CONTENT_SETTING_SESSION_ONLY)});
+
+ DeleteCookiePredicate predicate =
+ settings->CreateDeleteCookieOnExitPredicate();
+ ASSERT_TRUE(predicate);
+
+ // Replace the live settings so "https://foo.com" is now ALLOW.
+ settings->set_content_settings(
+ ContentSettingsType::COOKIES,
+ {CreateSetting("https://foo.com", "*", CONTENT_SETTING_ALLOW)});
+ EXPECT_TRUE(predicate.Run("foo.com", net::CookieSourceScheme::kSecure));
+
+ // Destroy the original CookieSettings instance entirely; the predicate
+ // must still safely evaluate the snapshot.
+ settings.reset();
+ EXPECT_TRUE(predicate.Run("foo.com", net::CookieSourceScheme::kSecure));
+ EXPECT_FALSE(predicate.Run("other.com", net::CookieSourceScheme::kSecure));
+}
+
TEST_F(CookieSettingsTest, GetCookieSettingSecureOriginCookiesAllowed) {
CookieSettings settings;
settings.set_secure_origin_cookies_allowed_schemes({"chrome"});
diff --git a/services/network/network_context_unittest.cc b/services/network/network_context_unittest.cc
index 309599c7..3fa2084 100644
--- a/services/network/network_context_unittest.cc
+++ b/services/network/network_context_unittest.cc
@@ -9979,6 +9979,16 @@
EXPECT_TRUE(success);
}
+TEST_F(NetworkContextTest, ClearTrustTokenSessionOnlyDataNoSessionOnlyRules) {
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(CreateNetworkContextParamsForTesting());
+ ASSERT_TRUE(network_context->trust_token_store());
+
+ base::test::TestFuture<bool> future;
+ network_context->ClearTrustTokenSessionOnlyData(future.GetCallback());
+ EXPECT_FALSE(future.Get());
+}
+
// NotifyExternalCacheHit currently assumes that the cache hits are for
// resources, so ensure that entries corresponding to subframe navigations don't
// get updated unexpectedly.
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/services/network/cookie_settings_unittest.cc b/services/network/cookie_settings_unittest.cc
index 5083b68b..584ab61 100644
--- a/services/network/cookie_settings_unittest.cc
+++ b/services/network/cookie_settings_unittest.cc
@@ -861,6 +861,29 @@
"foo.com", net::CookieSourceScheme::kNonSecure));
}
+TEST_F(CookieSettingsTest, CreateDeleteCookieOnExitPredicateOwnsSnapshot) {
+ auto settings = std::make_unique<CookieSettings>();
+ settings->set_content_settings(
+ ContentSettingsType::COOKIES,
+ {CreateSetting("https://foo.com", "*", CONTENT_SETTING_SESSION_ONLY)});
+
+ DeleteCookiePredicate predicate =
+ settings->CreateDeleteCookieOnExitPredicate();
+ ASSERT_TRUE(predicate);
+
+ // Replace the live settings so "https://foo.com" is now ALLOW.
+ settings->set_content_settings(
+ ContentSettingsType::COOKIES,
+ {CreateSetting("https://foo.com", "*", CONTENT_SETTING_ALLOW)});
+ EXPECT_TRUE(predicate.Run("foo.com", net::CookieSourceScheme::kSecure));
+
+ // Destroy the original CookieSettings instance entirely; the predicate
+ // must still safely evaluate the snapshot.
+ settings.reset();
+ EXPECT_TRUE(predicate.Run("foo.com", net::CookieSourceScheme::kSecure));
+ EXPECT_FALSE(predicate.Run("other.com", net::CookieSourceScheme::kSecure));
+}
+
TEST_F(CookieSettingsTest, GetCookieSettingSecureOriginCookiesAllowed) {
CookieSettings settings;
settings.set_secure_origin_cookies_allowed_schemes({"chrome"});
diff --git a/services/network/network_context_unittest.cc b/services/network/network_context_unittest.cc
index 309599c7..3fa2084 100644
--- a/services/network/network_context_unittest.cc
+++ b/services/network/network_context_unittest.cc
@@ -9979,6 +9979,16 @@
EXPECT_TRUE(success);
}
+TEST_F(NetworkContextTest, ClearTrustTokenSessionOnlyDataNoSessionOnlyRules) {
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(CreateNetworkContextParamsForTesting());
+ ASSERT_TRUE(network_context->trust_token_store());
+
+ base::test::TestFuture<bool> future;
+ network_context->ClearTrustTokenSessionOnlyData(future.GetCallback());
+ EXPECT_FALSE(future.Get());
+}
+
// NotifyExternalCacheHit currently assumes that the cache hits are for
// resources, so ensure that entries corresponding to subframe navigations don't
// get updated unexpectedly.
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