Chrome · Related-Website-Sets
CVE-2026-14059
Logic Error in Related-Website-Sets
Overview
Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Files Changed
chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.ccchrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
Patch
From b718cffa859d24d37ea592172ce97447d54b5c82 Mon Sep 17 00:00:00 2001
From: Chris Fredrickson <cfredric@chromium.org>
Date: Thu, 07 May 2026 11:02:15 -0700
Subject: [PATCH] [RWS] Fix failure to clear rsaFor permissions
Fixed: 502363986
Change-Id: If13ece11a835cb5d725e2116d8061c852d3ea299
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7828839
Commit-Queue: Chris Fredrickson <cfredric@chromium.org>
Auto-Submit: Chris Fredrickson <cfredric@chromium.org>
Reviewed-by: Christian Dullweber <dullweber@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1627070}
---
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
index 4e140e65..4ffdec443 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
@@ -1471,8 +1471,14 @@
std::ranges::any_of(
filter_builder->GetOrigins(),
[&](const url::Origin& origin) -> bool {
- return setting.primary_pattern.Matches(
- origin.GetURL()) ||
+ // TopLevelStorageAccessPermissionContext creates
+ // grants using (origin, site) patterns. We explicitly
+ // use the primary pattern's site here to ensure any
+ // permission granted to subdomains of an RWS site are
+ // properly cleared.
+ return net::SchemefulSite(setting.primary_pattern
+ .ToRepresentativeUrl())
+ .IsSameSiteWith(origin) ||
setting.secondary_pattern.Matches(
origin.GetURL());
});
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
index 04936d7..8135162 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
@@ -4739,3 +4739,65 @@
testing::Values(FilterOrigins::kByPrimaryUrl,
FilterOrigins::kBySecondaryUrl,
FilterOrigins::kByBothUrls)));
+
+// Regression test for https://crbug.com/502363986.
+TEST_F(ChromeBrowsingDataRemoverDelegateTest,
+ RWSRevocationIncludesSubdomainKeyedRSAForGrants) {
+ HostContentSettingsMap* settings_map =
+ HostContentSettingsMapFactory::GetForProfile(GetProfile());
+
+ // a.test & b.test are assumed to be in an RWS together, but b.test will be
+ // removed from the set and have its data cleared.
+ const GURL kTopLevel("https://a.test");
+ const GURL kRequestedSubdomain("https://accounts.b.test");
+
+ content_settings::ContentSettingConstraints rws_constraints;
+ rws_constraints.set_lifetime(base::Days(30));
+ rws_constraints.set_decided_by_related_website_sets(true);
+ settings_map->SetContentSettingDefaultScope(
+ kRequestedSubdomain, kTopLevel,
+ ContentSettingsType::TOP_LEVEL_STORAGE_ACCESS, CONTENT_SETTING_ALLOW,
+ rws_constraints);
+ settings_map->SetContentSettingCustomScope(
+ ContentSettingsPattern::FromURLNoWildcard(kRequestedSubdomain),
+ ContentSettingsPattern::FromURLToSchemefulSitePattern(kTopLevel),
+ ContentSettingsType::STORAGE_ACCESS, CONTENT_SETTING_ALLOW,
+ rws_constraints);
+
+ // 1 wildcard setting each, plus 1 specific setting each.
+ ASSERT_EQ(
+ settings_map->GetSettingsForOneType(ContentSettingsType::STORAGE_ACCESS)
+ .size(),
+ 2u);
+ ASSERT_EQ(
+ settings_map
+ ->GetSettingsForOneType(ContentSettingsType::TOP_LEVEL_STORAGE_ACCESS)
+ .size(),
+ 2u);
+
+ std::unique_ptr<BrowsingDataFilterBuilder> filter_builder(
+ BrowsingDataFilterBuilder::Create(
+ BrowsingDataFilterBuilder::Mode::kDelete));
+ // RWS data clearing is site-based (see FirstPartySetsSiteDataRemover).
+ filter_builder->AddOrigin(
+ url::Origin::Create(net::SchemefulSite(kRequestedSubdomain).GetURL()));
+
+ BlockUntilOriginDataRemoved(
+ base::Time(), base::Time::Max(),
+ content::BrowsingDataRemover::DATA_TYPE_RELATED_WEBSITE_SETS_PERMISSIONS,
+ std::move(filter_builder));
+
+ EXPECT_EQ(
+ settings_map
+ ->GetSettingsForOneType(ContentSettingsType::TOP_LEVEL_STORAGE_ACCESS)
+ .size(),
+ 1u);
+ EXPECT_EQ(
+ settings_map->GetSettingsForOneType(ContentSettingsType::STORAGE_ACCESS)
+ .size(),
+ 1u);
+ EXPECT_EQ(
+ settings_map->GetContentSetting(kRequestedSubdomain, kTopLevel,
+ ContentSettingsType::STORAGE_ACCESS),
+ CONTENT_SETTING_ASK);
+}
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
index 04936d7..8135162 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
@@ -4739,3 +4739,65 @@
testing::Values(FilterOrigins::kByPrimaryUrl,
FilterOrigins::kBySecondaryUrl,
FilterOrigins::kByBothUrls)));
+
+// Regression test for https://crbug.com/502363986.
+TEST_F(ChromeBrowsingDataRemoverDelegateTest,
+ RWSRevocationIncludesSubdomainKeyedRSAForGrants) {
+ HostContentSettingsMap* settings_map =
+ HostContentSettingsMapFactory::GetForProfile(GetProfile());
+
+ // a.test & b.test are assumed to be in an RWS together, but b.test will be
+ // removed from the set and have its data cleared.
+ const GURL kTopLevel("https://a.test");
+ const GURL kRequestedSubdomain("https://accounts.b.test");
+
+ content_settings::ContentSettingConstraints rws_constraints;
+ rws_constraints.set_lifetime(base::Days(30));
+ rws_constraints.set_decided_by_related_website_sets(true);
+ settings_map->SetContentSettingDefaultScope(
+ kRequestedSubdomain, kTopLevel,
+ ContentSettingsType::TOP_LEVEL_STORAGE_ACCESS, CONTENT_SETTING_ALLOW,
+ rws_constraints);
+ settings_map->SetContentSettingCustomScope(
+ ContentSettingsPattern::FromURLNoWildcard(kRequestedSubdomain),
+ ContentSettingsPattern::FromURLToSchemefulSitePattern(kTopLevel),
+ ContentSettingsType::STORAGE_ACCESS, CONTENT_SETTING_ALLOW,
+ rws_constraints);
+
+ // 1 wildcard setting each, plus 1 specific setting each.
+ ASSERT_EQ(
+ settings_map->GetSettingsForOneType(ContentSettingsType::STORAGE_ACCESS)
+ .size(),
+ 2u);
+ ASSERT_EQ(
+ settings_map
+ ->GetSettingsForOneType(ContentSettingsType::TOP_LEVEL_STORAGE_ACCESS)
+ .size(),
+ 2u);
+
+ std::unique_ptr<BrowsingDataFilterBuilder> filter_builder(
+ BrowsingDataFilterBuilder::Create(
+ BrowsingDataFilterBuilder::Mode::kDelete));
+ // RWS data clearing is site-based (see FirstPartySetsSiteDataRemover).
+ filter_builder->AddOrigin(
+ url::Origin::Create(net::SchemefulSite(kRequestedSubdomain).GetURL()));
+
+ BlockUntilOriginDataRemoved(
+ base::Time(), base::Time::Max(),
+ content::BrowsingDataRemover::DATA_TYPE_RELATED_WEBSITE_SETS_PERMISSIONS,
+ std::move(filter_builder));
+
+ EXPECT_EQ(
+ settings_map
+ ->GetSettingsForOneType(ContentSettingsType::TOP_LEVEL_STORAGE_ACCESS)
+ .size(),
+ 1u);
+ EXPECT_EQ(
+ settings_map->GetSettingsForOneType(ContentSettingsType::STORAGE_ACCESS)
+ .size(),
+ 1u);
+ EXPECT_EQ(
+ settings_map->GetContentSetting(kRequestedSubdomain, kTopLevel,
+ ContentSettingsType::STORAGE_ACCESS),
+ CONTENT_SETTING_ASK);
+}
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