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 <[email protected]> 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 <[email protected]> Commit-Queue: Patrick Meenan <[email protected]> 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