diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc index dcbf4f73db194..2130741e1ee38 100644 --- a/content/browser/renderer_host/navigation_request.cc +++ b/content/browser/renderer_host/navigation_request.cc @@ -1208,16 +1208,47 @@ net::StorageAccessApiStatus ShouldLoadWithStorageAccess( switch (begin_params.storage_access_api_status) { case net::StorageAccessApiStatus::kNone: return net::StorageAccessApiStatus::kNone; - case net::StorageAccessApiStatus::kAccessViaAPI: - return common_params.initiator_origin && - common_params.initiator_origin->IsSameOriginWith( - response_url) && - begin_params.initiator_frame_token && - begin_params.initiator_frame_token == - previous_document_rfh->GetFrameToken() && - !did_encounter_cross_origin_redirect - ? begin_params.storage_access_api_status - : net::StorageAccessApiStatus::kNone; + case net::StorageAccessApiStatus::kAccessViaAPI: { + bool identity_ok = + common_params.initiator_origin && + common_params.initiator_origin->IsSameOriginWith(response_url) && + begin_params.initiator_frame_token && + begin_params.initiator_frame_token == + previous_document_rfh->GetFrameToken() && + !did_encounter_cross_origin_redirect; + if (!identity_ok) { + return net::StorageAccessApiStatus::kNone; + } + // ==== POC DETECTOR ==== + // All existing browser-side checks (same-origin initiator, matching + // frame token, no cross-origin redirect) have passed. The unmodified + // code now returns the renderer-supplied kAccessViaAPI verbatim, which + // causes kStorageAccessGrantEligible to be set on the next document. + // The check that is MISSING is: did the previous document actually have + // that override? We add it here as a CHECK so that a lying renderer + // produces an observable browser-process crash instead of a silent + // Permissions-Policy bypass. + bool prev_had_override = + previous_document_rfh->document_associated_data() + .cookie_setting_overrides() + .Has(net::CookieSettingOverride::kStorageAccessGrantEligible); + LOG(ERROR) + << "[POC] ShouldLoadWithStorageAccess: renderer claims " + "kAccessViaAPI for " + << response_url + << " ; identity checks passed; previous document had " + "kStorageAccessGrantEligible = " + << (prev_had_override ? "YES" : "NO (renderer lied)"); + CHECK(prev_had_override) + << "[POC] SECURITY: renderer-supplied storage_access_api_status=" + "kAccessViaAPI accepted by ShouldLoadWithStorageAccess() even " + "though the previous document never had storage access. " + "Without this CHECK, kStorageAccessGrantEligible would be " + "laundered onto the new document, bypassing Permissions-Policy: " + "storage-access=() and gating StorageAccessHandle on a stale " + "STORAGE_ACCESS grant."; + return begin_params.storage_access_api_status; + } } } diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index 017007ee611e3..9ec348b915a04 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc @@ -6216,7 +6216,14 @@ void RenderFrameImpl::BeginNavigationInternal( info->url_request.HasUserGesture(), /*started_by_ad=*/ (info->initiator_frame_is_ad || info->is_ad_script_in_stack), - info->is_container_initiated, info->storage_access_api_status, + info->is_container_initiated, + // ==== POC INJECTION: simulate compromised renderer ==== + // A compromised renderer lies about its storage-access state on + // every BeginNavigation. The browser is supposed to validate this + // claim against the previous document's actual override state but + // does not (navigation_request.cc ShouldLoadWithStorageAccess only + // checks initiator origin / frame token / redirects). + net::StorageAccessApiStatus::kAccessViaAPI, info->has_rel_opener); bool current_frame_has_download_sandbox_flag = !frame_->IsAllowedToDownload();