Chrome · StorageAccessAPI
CVE-2026-79060
Logic Error in StorageAccessAPI
Overview
Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifchrome/browser/top_level_storage_access_api/top_level_storage_access_permission_context.cc |
modified | |
TEST_Fchrome/browser/top_level_storage_access_api/top_level_storage_access_permission_context_unittest.cc |
modified | |
TopLevelStorageAccessPermissionContextAPIWithFirstPartySetsTestchrome/browser/top_level_storage_access_api/top_level_storage_access_permission_context_unittest.cc |
modified |
Files Changed
chrome/browser/bad_message.hchrome/browser/top_level_storage_access_api/BUILD.gnchrome/browser/top_level_storage_access_api/top_level_storage_access_permission_context.ccchrome/browser/top_level_storage_access_api/top_level_storage_access_permission_context_unittest.cctools/metrics/histograms/metadata/stability/enums.xml
Patch
From a3c67583da1402dba1ddd1242a9417f227e6e5b2 Mon Sep 17 00:00:00 2001
From: Chris Fredrickson <cfredric@chromium.org>
Date: Mon, 20 Jul 2026 07:57:52 -0700
Subject: [PATCH] Kill compromised same-site renderers in rsaFor permission context
Same-site permissions requests are never sent by well-behaved renderers,
since there is no privacy boundary to enforce there (generally
speaking). However, a compromised renderer could request (and get)
permission, and then read permission from a credentialless frame,
because the browser process did not properly enforce the cross-site
condition.
Fixed: 519254827
Change-Id: I232efae5ceda718ef0db01071cef1eae482b0afa
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8110978
Reviewed-by: Lei Zhang <thestig@chromium.org>
Reviewed-by: Alexei Svitkine <asvitkine@chromium.org>
Auto-Submit: Chris Fredrickson <cfredric@chromium.org>
Commit-Queue: Alexei Svitkine <asvitkine@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1664684}
---
diff --git a/chrome/browser/bad_message.h b/chrome/browser/bad_message.h
index 220ecd6..32c12993 100644
--- a/chrome/browser/bad_message.h
+++ b/chrome/browser/bad_message.h
@@ -34,6 +34,7 @@
RFH_INVALID_WEB_FRAME_URL = 11,
PVM_PRINT_FENCED_FRAME = 12,
SAGPC_INVALID_PERMISSION_REQUEST_CONTEXT = 13,
+ TLSAPC_INVALID_PERMISSION_REQUEST_CONTEXT = 14,
// Please add new elements here. The naming convention is abbreviated class
// name (e.g. RenderFrameHost becomes RFH) plus a unique description of the
diff --git a/chrome/browser/top_level_storage_access_api/BUILD.gn b/chrome/browser/top_level_storage_access_api/BUILD.gn
index 73a7a6de..fb5019a 100644
--- a/chrome/browser/top_level_storage_access_api/BUILD.gn
+++ b/chrome/browser/top_level_storage_access_api/BUILD.gn
@@ -15,6 +15,7 @@
]
deps = [
+ "//chrome/browser:bad_message",
"//chrome/browser/content_settings:content_settings_factory",
"//chrome/browser/first_party_sets",
"//chrome/common",
diff --git a/chrome/browser/top_level_storage_access_api/top_level_storage_access_permission_context.cc b/chrome/browser/top_level_storage_access_api/top_level_storage_access_permission_context.cc
index aa49836..8122509e 100644
--- a/chrome/browser/top_level_storage_access_api/top_level_storage_access_permission_context.cc
+++ b/chrome/browser/top_level_storage_access_api/top_level_storage_access_permission_context.cc
@@ -10,6 +10,7 @@
#include "base/functional/bind.h"
#include "base/metrics/histogram_functions.h"
#include "base/notreached.h"
+#include "chrome/browser/bad_message.h"
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
#include "chrome/browser/first_party_sets/first_party_sets_policy_service.h"
#include "chrome/browser/first_party_sets/first_party_sets_policy_service_factory.h"
@@ -36,6 +37,7 @@
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/features_generated.h"
#include "third_party/blink/public/mojom/devtools/console_message.mojom-shared.h"
+#include "third_party/blink/public/mojom/permissions/permission_status.mojom-shared.h"
namespace {
@@ -95,6 +97,22 @@
return;
}
+ net::SchemefulSite embedding_site(request_data->embedding_origin);
+ net::SchemefulSite requesting_site(request_data->requesting_origin);
+
+ if (requesting_site == embedding_site) {
+ // Well-behaved renderers don't send same-site permissions requests, since
+ // there is no privacy boundary within a site. This must be a compromised
+ // renderer.
+ bad_message::ReceivedBadMessage(
+ rfh->GetProcess(), bad_message::BadMessageReason::
+ TLSAPC_INVALID_PERMISSION_REQUEST_CONTEXT);
+ std::move(callback).Run(content::PermissionResult(
+ blink::mojom::PermissionStatus::DENIED,
+ content::PermissionStatusSource::UNSPECIFIED));
+ return;
+ }
+
if (!request_data->user_gesture || !rfh->HasTransientUserActivation() ||
!request_data->requesting_origin.is_valid() ||
!request_data->embedding_origin.is_valid()) {
@@ -111,9 +129,6 @@
return;
}
- net::SchemefulSite embedding_site(request_data->embedding_origin);
- net::SchemefulSite requesting_site(request_data->requesting_origin);
-
first_party_sets::FirstPartySetsPolicyServiceFactory::GetForBrowserContext(
browser_context())
->ComputeFirstPartySetMetadata(
diff --git a/chrome/browser/top_level_storage_access_api/top_level_storage_access_permission_context_unittest.cc b/chrome/browser/top_level_storage_access_api/top_level_storage_access_permission_context_unittest.cc
index c451452..2af14b8 100644
--- a/chrome/browser/top_level_storage_access_api/top_level_storage_access_permission_context_unittest.cc
+++ b/chrome/browser/top_level_storage_access_api/top_level_storage_access_permission_context_unittest.cc
@@ -24,6 +24,7 @@
#include "content/public/browser/permission_result.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_features.h"
+#include "content/public/test/mock_render_process_host.h"
#include "content/public/test/navigation_simulator.h"
#include "content/public/test/test_renderer_host.h"
#include "content/public/test/web_contents_tester.h"
@@ -233,6 +234,20 @@
.status);
}
+TEST_F(TopLevelStorageAccessPermissionContextTest, SameSiteDisallowed) {
+ TopLevelStorageAccessPermissionContext permission_context(profile());
+ NavigateAndCommit(GetTopLevelURL());
+
+ EXPECT_EQ(
+ DecidePermissionSync(&permission_context, /*user_gesture=*/true,
+ GetDummyEmbeddingUrl(), GetDummyEmbeddingUrl()),
+ PermissionStatus::DENIED);
+
+ EXPECT_EQ(1, static_cast<content::MockRenderProcessHost*>(
+ web_contents()->GetPrimaryMainFrame()->GetProcess())
+ ->bad_msg_count());
+}
+
class TopLevelStorageAccessPermissionContextAPIWithFirstPartySetsTest
: public TopLevelStorageAccessPermissionContextTest {
public:
diff --git a/tools/metrics/histograms/metadata/stability/enums.xml b/tools/metrics/histograms/metadata/stability/enums.xml
index b6a79ff..2e12749 100644
--- a/tools/metrics/histograms/metadata/stability/enums.xml
+++ b/tools/metrics/histograms/metadata/stability/enums.xml
@@ -131,6 +131,7 @@
<int value="11" label="RFH_INVALID_WEB_FRAME_URL"/>
<int value="12" label="PVM_PRINT_FENCED_FRAME"/>
<int value="13" label="SAGPC_INVALID_PERMISSION_REQUEST_CONTEXT"/>
+ <int value="14" label="TLSAPC_INVALID_PERMISSION_REQUEST_CONTEXT"/>
</enum>
<enum name="BadMessageReasonContent">
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/chrome/browser/top_level_storage_access_api/top_level_storage_access_permission_context_unittest.cc b/chrome/browser/top_level_storage_access_api/top_level_storage_access_permission_context_unittest.cc
index c451452..2af14b8 100644
--- a/chrome/browser/top_level_storage_access_api/top_level_storage_access_permission_context_unittest.cc
+++ b/chrome/browser/top_level_storage_access_api/top_level_storage_access_permission_context_unittest.cc
@@ -24,6 +24,7 @@
#include "content/public/browser/permission_result.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_features.h"
+#include "content/public/test/mock_render_process_host.h"
#include "content/public/test/navigation_simulator.h"
#include "content/public/test/test_renderer_host.h"
#include "content/public/test/web_contents_tester.h"
@@ -233,6 +234,20 @@
.status);
}
+TEST_F(TopLevelStorageAccessPermissionContextTest, SameSiteDisallowed) {
+ TopLevelStorageAccessPermissionContext permission_context(profile());
+ NavigateAndCommit(GetTopLevelURL());
+
+ EXPECT_EQ(
+ DecidePermissionSync(&permission_context, /*user_gesture=*/true,
+ GetDummyEmbeddingUrl(), GetDummyEmbeddingUrl()),
+ PermissionStatus::DENIED);
+
+ EXPECT_EQ(1, static_cast<content::MockRenderProcessHost*>(
+ web_contents()->GetPrimaryMainFrame()->GetProcess())
+ ->bad_msg_count());
+}
+
class TopLevelStorageAccessPermissionContextAPIWithFirstPartySetsTest
: public TopLevelStorageAccessPermissionContextTest {
public:
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