Chrome · CacheStorage
CVE-2026-85053
Logic Error in CacheStorage
Overview
High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
TEST_Fcontent/browser/worker_host/shared_worker_host_unittest.cc |
modified | |
TESTnet/base/network_isolation_key_unittest.cc |
modified |
Files Changed
content/browser/worker_host/shared_worker_host.cccontent/browser/worker_host/shared_worker_host.hcontent/browser/worker_host/shared_worker_host_unittest.ccnet/base/network_isolation_key_unittest.cc
Patch
From 0b4f1821f123f397738a9ca6fd9f1666c55f9d45 Mon Sep 17 00:00:00 2001
From: Chris Fredrickson <cfredric@chromium.org>
Date: Mon, 31 Aug 2026 14:44:07 -0700
Subject: [PATCH] Ensure SharedWorkers use distinct code caches based on SiteForCookies
Without partitioning the code cache based on this property of the
SharedWorker, two shared workers with the same StorageKey would share
the code cache, even if one is not supposed to have access to 3P cookies
and the other is.
Fixed: 552689418
Change-Id: Ice36567846bfab93b6242cfc526b0191f992a7ad
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8308172
Commit-Queue: Chris Fredrickson <cfredric@chromium.org>
Reviewed-by: Joe Mason <joenotcharles@google.com>
Reviewed-by: mmenke <mmenke@chromium.org>
Reviewed-by: Asami Doi <asamidoi@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1689294}
---
diff --git a/content/browser/worker_host/shared_worker_host.cc b/content/browser/worker_host/shared_worker_host.cc
index 851958db..8917db9 100644
--- a/content/browser/worker_host/shared_worker_host.cc
+++ b/content/browser/worker_host/shared_worker_host.cc
@@ -94,6 +94,20 @@
source);
}
+net::IsolationInfo ComputeIsolationInfoWithPartition(
+ const blink::StorageKey& storage_key,
+ net::NetworkIsolationPartition partition) {
+ net::IsolationInfo isolation_info = storage_key.ToPartialNetIsolationInfo();
+ if (partition != net::NetworkIsolationPartition::kGeneral &&
+ !isolation_info.IsEmpty()) {
+ return net::IsolationInfo::Create(
+ isolation_info.request_type(), *isolation_info.top_frame_origin(),
+ *isolation_info.frame_origin(), isolation_info.site_for_cookies(),
+ isolation_info.nonce(), partition);
+ }
+ return isolation_info;
+}
+
} // namespace
namespace content {
@@ -971,6 +985,14 @@
return weak_factory_.GetWeakPtr();
}
+net::NetworkIsolationPartition SharedWorkerHost::GetNetworkIsolationPartition()
+ const {
+ return instance_.same_site_cookies() ==
+ blink::mojom::SharedWorkerSameSiteCookies::kNone
+ ? net::NetworkIsolationPartition::kSharedWorkerSameSiteCookiesNone
+ : net::NetworkIsolationPartition::kGeneral;
+}
+
net::NetworkIsolationKey SharedWorkerHost::GetNetworkIsolationKey() const {
// Note: Since shared workers are partitioned by the storage key, we'll use
// the storage key to create a NIK that matches the current partitioning
@@ -978,15 +1000,15 @@
// different top-level sites will be able to share the same shared worker, so
// it doesn't make sense to incorporate the top-level site into the NIK in
// that case either.
- return GetWorkerStorageKey()
- .ToPartialNetIsolationInfo()
+ return ComputeIsolationInfoWithPartition(GetWorkerStorageKey(),
+ GetNetworkIsolationPartition())
.network_isolation_key();
}
net::NetworkAnonymizationKey SharedWorkerHost::GetNetworkAnonymizationKey()
const {
- return GetWorkerStorageKey()
- .ToPartialNetIsolationInfo()
+ return ComputeIsolationInfoWithPartition(GetWorkerStorageKey(),
+ GetNetworkIsolationPartition())
.network_anonymization_key();
}
diff --git a/content/browser/worker_host/shared_worker_host.h b/content/browser/worker_host/shared_worker_host.h
index 18d345a..3e8ef4a 100644
--- a/content/browser/worker_host/shared_worker_host.h
+++ b/content/browser/worker_host/shared_worker_host.h
@@ -34,6 +34,7 @@
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/bindings/unique_receiver_set.h"
#include "net/base/network_isolation_key.h"
+#include "net/base/network_isolation_partition.h"
#include "services/device/public/cpp/compute_pressure/buildflags.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "services/network/public/cpp/cross_origin_embedder_policy.h"
@@ -240,6 +241,8 @@
base::WeakPtr<SharedWorkerHost> AsWeakPtr();
+ net::NetworkIsolationPartition GetNetworkIsolationPartition() const;
+
net::NetworkIsolationKey GetNetworkIsolationKey() const;
net::NetworkAnonymizationKey GetNetworkAnonymizationKey() const;
diff --git a/content/browser/worker_host/shared_worker_host_unittest.cc b/content/browser/worker_host/shared_worker_host_unittest.cc
index 925de9e0..68eb091d 100644
--- a/content/browser/worker_host/shared_worker_host_unittest.cc
+++ b/content/browser/worker_host/shared_worker_host_unittest.cc
@@ -86,6 +86,18 @@
base::WeakPtr<SharedWorkerHost> CreateHostWithExtendedLifetime(
bool extended_lifetime) {
+ return CreateHostWithParams(blink::mojom::SharedWorkerSameSiteCookies::kAll,
+ extended_lifetime);
+ }
+
+ base::WeakPtr<SharedWorkerHost> CreateHostWithSameSiteCookies(
+ blink::mojom::SharedWorkerSameSiteCookies same_site_cookies) {
+ return CreateHostWithParams(same_site_cookies, /*extended_lifetime=*/false);
+ }
+
+ base::WeakPtr<SharedWorkerHost> CreateHostWithParams(
+ blink::mojom::SharedWorkerSameSiteCookies same_site_cookies,
+ bool extended_lifetime) {
blink::StorageKey creator_storage_key =
blink::StorageKey::CreateFirstParty(url::Origin::Create(kWorkerUrl));
bool is_opaque_origin_enabled = base::FeatureList::IsEnabled(
@@ -99,7 +111,7 @@
network::mojom::CredentialsMode::kSameOrigin, "name",
creator_storage_key, worker_storage_key, renderer_origin,
blink::mojom::SharedWorkerCreationContextType::kSecure,
- blink::mojom::SharedWorkerSameSiteCookies::kAll, extended_lifetime);
+ same_site_cookies, extended_lifetime);
auto host = std::make_unique<SharedWorkerHost>(
&service_, instance, site_instance_,
std::vector<network::mojom::ContentSecurityPolicyPtr>(),
@@ -667,4 +679,37 @@
}
}
+TEST_F(SharedWorkerHostTest, NetworkIsolationPartitionForSameSiteCookies) {
+ base::WeakPtr<SharedWorkerHost> host_all = CreateHostWithSameSiteCookies(
+ blink::mojom::SharedWorkerSameSiteCookies::kAll);
+ base::WeakPtr<SharedWorkerHost> host_none = CreateHostWithSameSiteCookies(
+ blink::mojom::SharedWorkerSameSiteCookies::kNone);
+
+ ASSERT_TRUE(host_all);
+ ASSERT_TRUE(host_none);
+
+ EXPECT_EQ(host_all->GetNetworkIsolationPartition(),
+ net::NetworkIsolationPartition::kGeneral);
+ EXPECT_EQ(host_none->GetNetworkIsolationPartition(),
+ net::NetworkIsolationPartition::kSharedWorkerSameSiteCookiesNone);
+
+ EXPECT_EQ(host_all->GetNetworkIsolationKey().GetNetworkIsolationPartition(),
+ net::NetworkIsolationPartition::kGeneral);
+ EXPECT_EQ(host_none->GetNetworkIsolationKey().GetNetworkIsolationPartition(),
+ net::NetworkIsolationPartition::kSharedWorkerSameSiteCookiesNone);
+ EXPECT_NE(host_all->GetNetworkIsolationKey(),
+ host_none->GetNetworkIsolationKey());
+ EXPECT_NE(host_all->GetNetworkIsolationKey().ToCacheKeyString(),
+ host_none->GetNetworkIsolationKey().ToCacheKeyString());
+
+ EXPECT_EQ(
+ host_all->GetNetworkAnonymizationKey().network_isolation_partition(),
+ net::NetworkIsolationPartition::kGeneral);
+ EXPECT_EQ(
+ host_none->GetNetworkAnonymizationKey().network_isolation_partition(),
+ net::NetworkIsolationPartition::kSharedWorkerSameSiteCookiesNone);
+ EXPECT_NE(host_all->GetNetworkAnonymizationKey(),
+ host_none->GetNetworkAnonymizationKey());
+}
+
} // namespace content
diff --git a/net/base/network_isolation_key_unittest.cc b/net/base/network_isolation_key_unittest.cc
index 89131568..d75938a 100644
--- a/net/base/network_isolation_key_unittest.cc
+++ b/net/base/network_isolation_key_unittest.cc
@@ -133,6 +133,24 @@
EXPECT_TRUE(key4.IsTransient());
}
+TEST(NetworkIsolationKeyTest, SharedWorkerSameSiteCookiesNonePartition) {
+ SchemefulSite site1 = SchemefulSite(GURL("http://a.test/"));
+ SchemefulSite site2 = SchemefulSite(GURL("http://b.test/"));
+
+ NetworkIsolationKey general_key(site1, site2, /*nonce=*/std::nullopt,
+ NetworkIsolationPartition::kGeneral);
+
+ NetworkIsolationKey shared_worker_none_key(
+ site1, site2, /*nonce=*/std::nullopt,
+ NetworkIsolationPartition::kSharedWorkerSameSiteCookiesNone);
+
+ EXPECT_EQ(NetworkIsolationPartition::kSharedWorkerSameSiteCookiesNone,
+ shared_worker_none_key.GetNetworkIsolationPartition());
+ EXPECT_EQ(site1.Serialize() + " " + site2.Serialize() + " 4",
+ shared_worker_none_key.ToCacheKeyString());
+ EXPECT_NE(general_key, shared_worker_none_key);
+}
+
TEST(NetworkIsolationKeyTest, CreateEmptyWithPartition) {
NetworkIsolationKey key = NetworkIsolationKey::CreateEmptyWithPartition(
NetworkIsolationPartition::kDnsOverHttps);
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/content/browser/worker_host/shared_worker_host_unittest.cc b/content/browser/worker_host/shared_worker_host_unittest.cc
index 925de9e0..68eb091d 100644
--- a/content/browser/worker_host/shared_worker_host_unittest.cc
+++ b/content/browser/worker_host/shared_worker_host_unittest.cc
@@ -86,6 +86,18 @@
base::WeakPtr<SharedWorkerHost> CreateHostWithExtendedLifetime(
bool extended_lifetime) {
+ return CreateHostWithParams(blink::mojom::SharedWorkerSameSiteCookies::kAll,
+ extended_lifetime);
+ }
+
+ base::WeakPtr<SharedWorkerHost> CreateHostWithSameSiteCookies(
+ blink::mojom::SharedWorkerSameSiteCookies same_site_cookies) {
+ return CreateHostWithParams(same_site_cookies, /*extended_lifetime=*/false);
+ }
+
+ base::WeakPtr<SharedWorkerHost> CreateHostWithParams(
+ blink::mojom::SharedWorkerSameSiteCookies same_site_cookies,
+ bool extended_lifetime) {
blink::StorageKey creator_storage_key =
blink::StorageKey::CreateFirstParty(url::Origin::Create(kWorkerUrl));
bool is_opaque_origin_enabled = base::FeatureList::IsEnabled(
@@ -99,7 +111,7 @@
network::mojom::CredentialsMode::kSameOrigin, "name",
creator_storage_key, worker_storage_key, renderer_origin,
blink::mojom::SharedWorkerCreationContextType::kSecure,
- blink::mojom::SharedWorkerSameSiteCookies::kAll, extended_lifetime);
+ same_site_cookies, extended_lifetime);
auto host = std::make_unique<SharedWorkerHost>(
&service_, instance, site_instance_,
std::vector<network::mojom::ContentSecurityPolicyPtr>(),
@@ -667,4 +679,37 @@
}
}
+TEST_F(SharedWorkerHostTest, NetworkIsolationPartitionForSameSiteCookies) {
+ base::WeakPtr<SharedWorkerHost> host_all = CreateHostWithSameSiteCookies(
+ blink::mojom::SharedWorkerSameSiteCookies::kAll);
+ base::WeakPtr<SharedWorkerHost> host_none = CreateHostWithSameSiteCookies(
+ blink::mojom::SharedWorkerSameSiteCookies::kNone);
+
+ ASSERT_TRUE(host_all);
+ ASSERT_TRUE(host_none);
+
+ EXPECT_EQ(host_all->GetNetworkIsolationPartition(),
+ net::NetworkIsolationPartition::kGeneral);
+ EXPECT_EQ(host_none->GetNetworkIsolationPartition(),
+ net::NetworkIsolationPartition::kSharedWorkerSameSiteCookiesNone);
+
+ EXPECT_EQ(host_all->GetNetworkIsolationKey().GetNetworkIsolationPartition(),
+ net::NetworkIsolationPartition::kGeneral);
+ EXPECT_EQ(host_none->GetNetworkIsolationKey().GetNetworkIsolationPartition(),
+ net::NetworkIsolationPartition::kSharedWorkerSameSiteCookiesNone);
+ EXPECT_NE(host_all->GetNetworkIsolationKey(),
+ host_none->GetNetworkIsolationKey());
+ EXPECT_NE(host_all->GetNetworkIsolationKey().ToCacheKeyString(),
+ host_none->GetNetworkIsolationKey().ToCacheKeyString());
+
+ EXPECT_EQ(
+ host_all->GetNetworkAnonymizationKey().network_isolation_partition(),
+ net::NetworkIsolationPartition::kGeneral);
+ EXPECT_EQ(
+ host_none->GetNetworkAnonymizationKey().network_isolation_partition(),
+ net::NetworkIsolationPartition::kSharedWorkerSameSiteCookiesNone);
+ EXPECT_NE(host_all->GetNetworkAnonymizationKey(),
+ host_none->GetNetworkAnonymizationKey());
+}
+
} // namespace content
diff --git a/net/base/network_isolation_key_unittest.cc b/net/base/network_isolation_key_unittest.cc
index 89131568..d75938a 100644
--- a/net/base/network_isolation_key_unittest.cc
+++ b/net/base/network_isolation_key_unittest.cc
@@ -133,6 +133,24 @@
EXPECT_TRUE(key4.IsTransient());
}
+TEST(NetworkIsolationKeyTest, SharedWorkerSameSiteCookiesNonePartition) {
+ SchemefulSite site1 = SchemefulSite(GURL("http://a.test/"));
+ SchemefulSite site2 = SchemefulSite(GURL("http://b.test/"));
+
+ NetworkIsolationKey general_key(site1, site2, /*nonce=*/std::nullopt,
+ NetworkIsolationPartition::kGeneral);
+
+ NetworkIsolationKey shared_worker_none_key(
+ site1, site2, /*nonce=*/std::nullopt,
+ NetworkIsolationPartition::kSharedWorkerSameSiteCookiesNone);
+
+ EXPECT_EQ(NetworkIsolationPartition::kSharedWorkerSameSiteCookiesNone,
+ shared_worker_none_key.GetNetworkIsolationPartition());
+ EXPECT_EQ(site1.Serialize() + " " + site2.Serialize() + " 4",
+ shared_worker_none_key.ToCacheKeyString());
+ EXPECT_NE(general_key, shared_worker_none_key);
+}
+
TEST(NetworkIsolationKeyTest, CreateEmptyWithPartition) {
NetworkIsolationKey key = NetworkIsolationKey::CreateEmptyWithPartition(
NetworkIsolationPartition::kDnsOverHttps);
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