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 <[email protected]> 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 <[email protected]> Reviewed-by: Alexei Svitkine <[email protected]> Auto-Submit: Chris Fredrickson <[email protected]> Commit-Queue: Alexei Svitkine <[email protected]> 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