Low chrome Logic Error 🔧 Commit mapped

Overview

Low
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactObservable discrepancy in Prefetch
DescriptionObservable discrepancy in Prefetch
ComponentPrefetch
Bug ClassLogic Error
Tracker497433347
Fix commit9a5cd9188517 (chromium/src) +11/-3
CISA KEVNot listed
CreditedGoogle
Disclosed2026-09-08

Background

Prefetch
Chromium’s speculative loading mechanism that fetches a resource before navigation, implemented in content::PrefetchService.
StoragePartition
the isolated storage container (cookies, cache, service workers) that a BrowserContext assigns to a given origin or embedder context.
Default storage partition
the StoragePartition returned by BrowserContext::GetDefaultStoragePartition(), used for ordinary top-level browsing.
Renderer initiator info
the GetRendererInitiatorInfo() record on a prefetch request that ties the request back to the RenderFrameHost that initiated it.

Root Cause Analysis

The eligibility check in content/browser/preloading/prefetch/prefetch_service.cc only compared default_storage_partition against GetStoragePartitionForUrl(params.url), verifying that the target URL mapped to the default partition. It never verified that the initiating frame itself lived in the default partition, so a prefetch begun from a frame hosted in a non-default StoragePartition was still treated as eligible and serviced through the default partition. This violated the invariant that prefetch’s cookie and service-worker checks must run against the same partition as the initiator, producing an observable cross-partition discrepancy.

The fix computes initiator_storage_partition from renderer_info->GetRenderFrameHost()->GetStoragePartition() and adds it as a rejection condition, so any prefetch whose initiator is not in the default partition is finished as PreloadingEligibility::kNonDefaultStoragePartition.

Key insight
The single mistake was checking only the target URL’s storage partition while ignoring the initiating frame’s storage partition, allowing a non-default-partition frame to trigger a default-partition prefetch; the fix closes this by deriving and comparing initiator_storage_partition before allowing prefetch to proceed.

Attack Path

  1. Host a frame in a non-default partition An embedder scenario places a frame (with an initiating RenderFrameHost) inside a non-default StoragePartition.
  2. Trigger a prefetch That frame initiates a prefetch whose target URL resolves to the default storage partition.
  3. Bypass the partition guard The old check passes because only the target URL’s partition matched the default, so eligibility is granted.
  4. Observe the discrepancy Cookie and service-worker state from the default partition influence the prefetch behavior, exposing an observable difference across the partition boundary.

Impact Assessment

An attacker gains an observable discrepancy across storage partitions, letting a frame in a non-default partition infer default-partition state (for example cookie or service-worker presence) via prefetch behavior. This occurs in the browser process’s prefetch eligibility path and requires the ability to initiate a prefetch from a frame residing in a non-default StoragePartition. Consistent with the metadata, the impact is a low-severity information/observability leak rather than memory corruption.

Files Changed

  • content/browser/preloading/prefetch/prefetch_service.cc

Audit Directions

  • Initiator-vs-target partition parity
    Wherever prefetch, prerender, or speculative loading makes an eligibility decision, confirm the initiator’s StoragePartition is validated, not just the target URL’s.
  • Optional initiator info
    Audit uses of GetRendererInitiatorInfo() and GetRenderFrameHost() for null cases, ensuring a missing initiator defaults safely to the default partition as the fix does.
  • Cross-partition observability
    Review other browser-process checks that gate on cookies or service workers to ensure they run against a single consistent partition, avoiding observable discrepancies across partition boundaries.
From 9a5cd91885172d12f35c0f826c5f9c729973231b Mon Sep 17 00:00:00 2001
From: Test User <[email protected]>
Date: Thu, 25 Jun 2026 22:27:43 -0700
Subject: [PATCH] Bugfix: This CL fixes a bug reported in crbug.com/497491557

Analysis Document:
https://docs.google.com/document/d/16iYyG4o-2tAOFEJ1mIkzk6_EQmxMbjM9sX40sLNBUiE/edit?resourcekey=0-JEFuIGKb8N7MgyRLpV9TtA&tab=t.0#heading=h.25s5vbi8dmhl

Bug: 497491557
Change-Id: I788105707bec3c840395a00fc1817e84f219fe5f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7901928
Commit-Queue: Minoru Chikamune <[email protected]>
Reviewed-by: Kouhei Ueno <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1652905}
---

diff --git a/content/browser/preloading/prefetch/prefetch_service.cc b/content/browser/preloading/prefetch/prefetch_service.cc
index 4f9956a..0aaf4203 100644
--- a/content/browser/preloading/prefetch/prefetch_service.cc
+++ b/content/browser/preloading/prefetch/prefetch_service.cc
@@ -947,9 +947,17 @@
   // check for service workers and existing cookies.
   StoragePartition* default_storage_partition =
       browser_context_->GetDefaultStoragePartition();
-  if (default_storage_partition !=
-      browser_context_->GetStoragePartitionForUrl(params.url,
-                                                  /*can_create=*/false)) {
+  StoragePartition* initiator_storage_partition = default_storage_partition;
+  if (auto* renderer_info = params.request().GetRendererInitiatorInfo()) {
+    if (auto* rfh = renderer_info->GetRenderFrameHost()) {
+      initiator_storage_partition = rfh->GetStoragePartition();
+    }
+  }
+
+  if (initiator_storage_partition != default_storage_partition ||
+      default_storage_partition !=
+          browser_context_->GetStoragePartitionForUrl(params.url,
+                                                      /*can_create=*/false)) {
     std::move(params).Finish(
         PreloadingEligibility::kNonDefaultStoragePartition);
     return;
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.