CVE-2026-79005
Overview
Background
- Storage Access API (SAA)
- lets an embedded cross-site document obtain access to its unpartitioned cookies/storage. A document that has storage access can keep that status for a self-initiated navigation of its own frame, but only when the navigation stays fully same-origin.
- `net::StorageAccessApiStatus`
- the per-request status the browser attaches to a navigation. It is
kNonewhen the load must not carry SAA-granted access. - `common_params.initiator_origin`
- the initiator origin of a navigation as reported by the renderer.
ChildProcessSecurityPolicyonly checks that the process may host that origin, so a compromised renderer can claim any other origin that lives in the same process. - `previous_document_rfh->GetLastCommittedOrigin()`
- the origin the browser itself recorded as committed in the frame’s current (previous) document, which the renderer cannot spoof.
Root Cause Analysis
The function the commit message names ShouldLoadWithStorageAccess() in content/browser/renderer_host/navigation_request.cc decides whether a navigation inherits storage access (the hunk shows only part of its body, not its signature). After confirming that the navigation is self-initiated, it requires the navigation to be “fully same-origin” before returning anything other than kNone. Before the patch, that same-origin test compared common_params.initiator_origin, a renderer-supplied value, against response_url. As the commit message explains, this value is only validated as an origin the process may host, so a compromised renderer could report a different origin hosted in the same process (for example another same-site origin). The navigation would then appear same-origin with a response_url that is not actually same-origin with the document holding storage access. The violated invariant is that security decisions in the browser must use browser-tracked state rather than renderer claims.
The fix replaces the initiator_origin comparison with previous_document_rfh->GetLastCommittedOrigin().IsSameOriginWith(response_url). It also drops the null-initiator_origin branch, which is no longer needed. The commit explains that this is equivalent for honest renderers because a self-initiated navigation’s initiator is always the frame’s previous RFH. The check stays as strict for honest renderers and can no longer be bypassed by a forged origin.
initiator_origin. The fix anchors it to the browser-side last committed origin of the previous document.Attack Path
- Compromised renderer precondition the attacker already controls a renderer process (e.g. through a separate renderer bug) that hosts an embedded document which has been granted storage access, and the same process also hosts at least one other origin.
- Self-initiated navigation with a forged initiator
the renderer starts a navigation of that frame and reports
initiator_originas another origin living in the same process, chosen to be same-origin with the navigation’s destination rather than with the frame’s actual document. This passesChildProcessSecurityPolicyvalidation. - Same-origin check passes falsely
ShouldLoadWithStorageAccess()compared the forgedinitiator_originwithresponse_url, found them same-origin, and (absent a cross-origin redirect) did not returnkNone. - Load carries storage access the destination is loaded with SAA status and therefore with unpartitioned cookies, even though the document that held the grant is not same-origin with it (inferred: the precise extent of the extra access depends on how the grant is scoped, which the diff does not show).
Impact Assessment
initiator_origin to another origin in the same process. The gain is that a navigation which should not inherit storage access is loaded with SAA status, giving it unpartitioned cookie access across an origin boundary within the process’s site (inferred). The commit author describes the impact as probably limited. Ordinary web content without a renderer compromise cannot reach the bug, and no exploited-in-the-wild status is given.Files Changed
content/browser/renderer_host/navigation_request.cc
Audit Directions
- Renderer-supplied origins in browser decisionsgrep for
initiator_origin,request_initiatorand similar renderer-reported origins used in permission, cookie-partitioning or storage-access checks.ChildProcessSecurityPolicyvalidation only bounds them to the process lock, not to the exact frame. - Shared-process same-site originsreview checks that are origin-granular (not site-granular) but rely on values a process can forge, because site-per-process puts multiple same-site origins in one renderer.
- Equivalent browser-side statewherever the browser has an authoritative equivalent (
GetLastCommittedOrigin(), the RFH’sStorageKey,NavigationRequeststate), prefer it over IPC parameters, especially in code about inheriting grants across navigations.
Patch
From fe692728450f6a95d10bdd753dcb7f8af14aeb81 Mon Sep 17 00:00:00 2001
From: Alex Moshchuk <alexmos@chromium.org>
Date: Fri, 17 Jul 2026 09:09:47 -0700
Subject: [PATCH] Use browser-side origin for checks in ShouldLoadWithStorageAccess().
Currently, the same-origin check in ShouldLoadWithStorageAccess() uses
the renderer-provided initiator_origin. While this is validated via
ChildProcessSecurityPolicy, it could be forged to another origin
living in the same process. While the impact of that might be limited,
it's better to be safe and use the browser-side last committed origin
of previous_document_rfh. This should be correct because the
navigation in question is already guaranteed to be self-initiated
(i.e., the navigation's initiator is always the same as the frame's
previous RFH).
Bug: 517540292
Change-Id: I5706e9a0a5ce7fc47e9be9de3f07cfc7ec364532
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8109159
Reviewed-by: Chris Fredrickson <cfredric@chromium.org>
Commit-Queue: Alex Moshchuk <alexmos@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1663940}
---
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index 1a9c2983..876fda9 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -1175,8 +1175,8 @@
// Navigation was not self-initiated.
return net::StorageAccessApiStatus::kNone;
}
- if (!common_params.initiator_origin ||
- !common_params.initiator_origin->IsSameOriginWith(response_url) ||
+ if (!previous_document_rfh->GetLastCommittedOrigin().IsSameOriginWith(
+ response_url) ||
did_encounter_cross_origin_redirect) {
// Navigation is not fully same-origin.
return net::StorageAccessApiStatus::kNone;