Low CVSS 6.5 chrome Input Validation 🔧 Commit mapped

Overview

Low
Severity
6.5
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInsufficient validation of untrusted input in Navigation
DescriptionInsufficient validation of untrusted input in Navigation
ComponentNavigation
Sub-componentContent
Bug ClassInput Validation
Tracker520005624
Fix commit02caf58c9b9d (chromium/src) +50/-5
CWECWE-20 (Improper input validation)
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N
CISA KEVNot listed
CreditedGoogle
Reported2026-06-04 (per vendor advisory)
Fix landed2026-06-26 (public git)
Disclosed2026-07-29
Patch gap33 days — fix public in source before the advisory

Changed Functions

FunctionChangeNotes
if
content/browser/renderer_host/render_frame_host_impl.cc
modified

Files Changed

  • content/browser/back_forward_cache_browsertest.cc
  • content/browser/renderer_host/render_frame_host_impl.cc
  • content/browser/renderer_host/render_frame_host_impl.h
From 02caf58c9b9d3e71e45df3c8a3db9642ea7ced62 Mon Sep 17 00:00:00 2001
From: Tzarial <zork@google.com>
Date: Fri, 26 Jun 2026 10:16:34 -0700
Subject: [PATCH] [agy][content] Ignore history user activation from inactive RFHs.

DidConsumeHistoryUserActivation IPC can be sent by a compromised
renderer on behalf of a subframe RenderFrameHost while its page is in
the BackForwardCache. Since its FrameTreeNode's frame_tree_ still
references the primary FrameTree, walking that tree would consume
the history user activation state on an unrelated active page.

This CL adds a check to ensure we only process this IPC when the
RenderFrameHost is in kActive state, matching the security pattern of
UpdateUserActivationState.

Fixed: 520005624
Test: RenderFrameHostImplTest.DidConsumeHistoryUserActivationNonActive
Change-Id: Ide3168f3e6bb0c285e6f1a0fc90b8076f605a2af
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7989439
Commit-Queue: Tzarial <zork@chromium.org>
Reviewed-by: Arthur Sonzogni <arthursonzogni@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1653252}
---

diff --git a/content/browser/back_forward_cache_browsertest.cc b/content/browser/back_forward_cache_browsertest.cc
index 21dd284..8b84b1f2 100644
--- a/content/browser/back_forward_cache_browsertest.cc
+++ b/content/browser/back_forward_cache_browsertest.cc
@@ -3691,6 +3691,46 @@
   ExpectRestored(FROM_HERE);
 }
 
+// Regression test for https://crbug.com/520005624.
+// Ensures that receiving a DidConsumeHistoryUserActivation IPC from a subframe
+// that is in the BackForwardCache is ignored and does not clear history user
+// activation of the active page.
+IN_PROC_BROWSER_TEST_F(
+    BackForwardCacheBrowserTest,
+    DidConsumeHistoryUserActivationFromCachedSubframeIsIgnored) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  GURL url_ab(embedded_test_server()->GetURL(
+      "a.com", "/cross_site_iframe_factory.html?a(b)"));
+  GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html"));
+
+  // 1) Navigate to A(B).
+  ASSERT_TRUE(NavigateToURL(shell(), url_ab));
+  RenderFrameHostImplWrapper rfh_a(current_frame_host());
+  RenderFrameHostImplWrapper rfh_b(rfh_a->child_at(0)->current_frame_host());
+
+  // 2) Navigate to C.
+  ASSERT_TRUE(NavigateToURL(shell(), url_c));
+  RenderFrameHostImplWrapper rfh_c(current_frame_host());
+
+  // Verify A(B) is in the BackForwardCache.
+  ASSERT_TRUE(rfh_a->IsInBackForwardCache());
+  ASSERT_TRUE(rfh_b->IsInBackForwardCache());
+
+  // 3) Set history user activation active on the active page C.
+  rfh_c->UpdateUserActivationState(
+      blink::mojom::UserActivationUpdateType::kNotifyActivation,
+      blink::mojom::UserActivationNotificationType::kInteraction);
+  EXPECT_TRUE(rfh_c->IsHistoryUserActivationActive());
+
+  // 4) Simulate receiving DidConsumeHistoryUserActivation from B (which is in
+  // BFCache).
+  rfh_b->DidConsumeHistoryUserActivation();
+
+  // 5) The history user activation on active page C must NOT be consumed.
+  EXPECT_TRUE(rfh_c->IsHistoryUserActivationActive());
+}
+
 // BEFORE ADDING A NEW TEST HERE
 // Read the note at the top about the other files you could add it to.
 }  // namespace content
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index 860abec..6e0b31c 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -9632,12 +9632,15 @@
 }
 
 void RenderFrameHostImpl::DidConsumeHistoryUserActivation() {
-  // owner_ may be null for IsPendingDeletion() or IsInBackForwardCache(), in
-  // which case the history user activation is managed by a different active
-  // RenderFrameHost.
-  if (owner_) {
-    owner_->DidConsumeHistoryUserActivation();
+  // This IPC is only sent from an active document, but might be received after
+  // the transition to the backforward cache or after entering pending
+  // deletion. It must be ignored as it would affect the state of the primary
+  // page instead of the old one.
+  if (lifecycle_state() != LifecycleStateImpl::kActive) {
+    return;
   }
+  CHECK(owner_);  // See `owner_` invariants about `lifecycle_state_`.
+  owner_->DidConsumeHistoryUserActivation();
 }
 
 void RenderFrameHostImpl::HadStickyUserActivationBeforeNavigationChanged(
diff --git a/content/browser/renderer_host/render_frame_host_impl.h b/content/browser/renderer_host/render_frame_host_impl.h
index bd8c4967..2d526d8 100644
--- a/content/browser/renderer_host/render_frame_host_impl.h
+++ b/content/browser/renderer_host/render_frame_host_impl.h
@@ -3544,6 +3544,8 @@
   FRIEND_TEST_ALL_PREFIXES(
       RenderFrameHostImplTest,
       BrowserInitiatedCloseIsNotCancelledIfPageIsntPrimary);
+  FRIEND_TEST_ALL_PREFIXES(RenderFrameHostImplTest,
+                           DidConsumeHistoryUserActivationNonActive);
   FRIEND_TEST_ALL_PREFIXES(DocumentUserDataTest, CheckInPendingDeletionState);
   FRIEND_TEST_ALL_PREFIXES(WebContentsImplBrowserTest, FrozenAndUnfrozenIPC);
   FRIEND_TEST_ALL_PREFIXES(RenderFrameHostImplBrowserTest,
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/content/browser/back_forward_cache_browsertest.cc b/content/browser/back_forward_cache_browsertest.cc
index 21dd284..8b84b1f2 100644
--- a/content/browser/back_forward_cache_browsertest.cc
+++ b/content/browser/back_forward_cache_browsertest.cc
@@ -3691,6 +3691,46 @@
   ExpectRestored(FROM_HERE);
 }
 
+// Regression test for https://crbug.com/520005624.
+// Ensures that receiving a DidConsumeHistoryUserActivation IPC from a subframe
+// that is in the BackForwardCache is ignored and does not clear history user
+// activation of the active page.
+IN_PROC_BROWSER_TEST_F(
+    BackForwardCacheBrowserTest,
+    DidConsumeHistoryUserActivationFromCachedSubframeIsIgnored) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  GURL url_ab(embedded_test_server()->GetURL(
+      "a.com", "/cross_site_iframe_factory.html?a(b)"));
+  GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html"));
+
+  // 1) Navigate to A(B).
+  ASSERT_TRUE(NavigateToURL(shell(), url_ab));
+  RenderFrameHostImplWrapper rfh_a(current_frame_host());
+  RenderFrameHostImplWrapper rfh_b(rfh_a->child_at(0)->current_frame_host());
+
+  // 2) Navigate to C.
+  ASSERT_TRUE(NavigateToURL(shell(), url_c));
+  RenderFrameHostImplWrapper rfh_c(current_frame_host());
+
+  // Verify A(B) is in the BackForwardCache.
+  ASSERT_TRUE(rfh_a->IsInBackForwardCache());
+  ASSERT_TRUE(rfh_b->IsInBackForwardCache());
+
+  // 3) Set history user activation active on the active page C.
+  rfh_c->UpdateUserActivationState(
+      blink::mojom::UserActivationUpdateType::kNotifyActivation,
+      blink::mojom::UserActivationNotificationType::kInteraction);
+  EXPECT_TRUE(rfh_c->IsHistoryUserActivationActive());
+
+  // 4) Simulate receiving DidConsumeHistoryUserActivation from B (which is in
+  // BFCache).
+  rfh_b->DidConsumeHistoryUserActivation();
+
+  // 5) The history user activation on active page C must NOT be consumed.
+  EXPECT_TRUE(rfh_c->IsHistoryUserActivationActive());
+}
+
 // BEFORE ADDING A NEW TEST HERE
 // Read the note at the top about the other files you could add it to.
 }  // namespace content
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.