Medium chrome Logic Error 🔧 Commit mapped

Overview

Medium
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUse of released resource in Mobile
DescriptionUse of released resource in Mobile
ComponentMobile
Bug ClassLogic Error
Tracker517482830
Fix commita9de56747eeb (chromium/src) +384/-200
CISA KEVNot listed
CreditedGoogle
Disclosed2026-09-03

Changed Functions

FunctionChangeNotes
if
android_webview/java/src/org/chromium/android_webview/contextmenu/AwContextMenuCoordinator.java
modified
if
chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHelper.java
modified

Files Changed

  • android_webview/browser/aw_context_menu_helper.cc
  • android_webview/java/src/org/chromium/android_webview/contextmenu/AwContextMenuCoordinator.java
  • android_webview/java/src/org/chromium/android_webview/contextmenu/AwContextMenuHelper.java
  • chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHelper.java
  • chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/ContextMenuLoadUrlParamsTest.java
  • chrome/browser/ui/android/context_menu_helper.cc
From a9de56747eeb6b737003a1c4d1ef5bbca617ba69 Mon Sep 17 00:00:00 2001
From: Jenna Himawan <[email protected]>
Date: Mon, 13 Jul 2026 12:45:59 -0700
Subject: [PATCH] Plumb InitiatorNavigationState for Android context menu navigations

Bypass-Check-License: Moving files, not creating new files
Bug: 517482830
Change-Id: I7cfa48e6d171461c5ad49afd3b610ce94d575962
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8001092
Commit-Queue: Jenna Himawan <[email protected]>
Reviewed-by: Bo Liu <[email protected]>
Reviewed-by: Calder Kitagawa <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1661311}
---

diff --git a/android_webview/browser/aw_context_menu_helper.cc b/android_webview/browser/aw_context_menu_helper.cc
index a8c4c0d..e8cc7148 100644
--- a/android_webview/browser/aw_context_menu_helper.cc
+++ b/android_webview/browser/aw_context_menu_helper.cc
@@ -6,7 +6,7 @@
 
 #include "android_webview/browser_jni_headers/AwContextMenuHelper_jni.h"
 #include "components/embedder_support/android/contextmenu/context_menu_builder.h"
-#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_frame_host.h"
 #include "ui/android/view_android.h"
 
 using base::android::JavaRef;
@@ -33,9 +33,8 @@
   gfx::NativeView view = GetWebContents().GetNativeView();
   Java_AwContextMenuHelper_showContextMenu(
       env, java_obj_,
-      context_menu::BuildJavaContextMenuParams(
-          params, nullptr, render_frame_host.GetProcess()->GetID(),
-          render_frame_host.GetFrameToken().value()),
+      context_menu::BuildJavaContextMenuParams(params, nullptr,
+                                               render_frame_host),
       view->GetContainerView());
 }
 
diff --git a/android_webview/java/src/org/chromium/android_webview/contextmenu/AwContextMenuCoordinator.java b/android_webview/java/src/org/chromium/android_webview/contextmenu/AwContextMenuCoordinator.java
index c3520c0e..adef660 100644
--- a/android_webview/java/src/org/chromium/android_webview/contextmenu/AwContextMenuCoordinator.java
+++ b/android_webview/java/src/org/chromium/android_webview/contextmenu/AwContextMenuCoordinator.java
@@ -68,6 +68,7 @@
     private WebContentsObserver mWebContentsObserver;
     private final boolean mIsDragDropEnabled;
     private final boolean mUsePopupWindow;
+    private boolean mDismissed;
 
     AwContextMenuCoordinator(
             WindowAndroid windowAndroid,
@@ -97,6 +98,9 @@
     }
 
     public void dismiss() {
+        if (mDismissed) return;
+        mDismissed = true;
+
         if (mWebContentsObserver != null) {
             mWebContentsObserver.observe(null);
         }
@@ -115,6 +119,8 @@
             mCurrentPopulator.onMenuClosed();
             mCurrentPopulator = null;
         }
+
+        mParams.destroy();
     }
 
     void displayMenu() {
diff --git a/android_webview/java/src/org/chromium/android_webview/contextmenu/AwContextMenuHelper.java b/android_webview/java/src/org/chromium/android_webview/contextmenu/AwContextMenuHelper.java
index c4c61e2..591f796 100644
--- a/android_webview/java/src/org/chromium/android_webview/contextmenu/AwContextMenuHelper.java
+++ b/android_webview/java/src/org/chromium/android_webview/contextmenu/AwContextMenuHelper.java
@@ -64,6 +64,7 @@
                 || windowAndroid.getActivity().get() == null
                 || windowAndroid.getContext().get() == null) {
             Log.w(TAG, "Could not create context menu");
+            params.destroy();
             return false;
         }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHelper.java
index 0e42eb0..84bb744d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHelper.java
@@ -85,6 +85,8 @@
         dismissContextMenu();
         if (mCurrentNativeDelegate != null) mCurrentNativeDelegate.destroy();
         if (mPopulatorFactory != null) mPopulatorFactory.onDestroy();
+        destroyContextMenuParams(mCurrentContextMenuParams);
+        mCurrentContextMenuParams = null;
         var removedValue = sContextMenuHelperMap.remove(mNativeContextMenuHelper);
         assert removedValue == this;
         mNativeContextMenuHelper = 0;
@@ -94,6 +96,8 @@
     private void setPopulatorFactory(ContextMenuPopulatorFactory populatorFactory) {
         dismissContextMenu();
         if (mCurrentNativeDelegate != null) mCurrentNativeDelegate.destroy();
+        destroyContextMenuParams(mCurrentContextMenuParams);
+        mCurrentContextMenuParams = null;
         mCurrentPopulator = null;
         if (mPopulatorFactory != null) mPopulatorFactory.onDestroy();
         mPopulatorFactory = populatorFactory;
@@ -101,6 +105,7 @@
 
     /**
      * Starts showing a context menu for {@code view} based on {@code params}.
+     *
      * @param params The {@link ContextMenuParams} that indicate what menu items to show.
      * @param renderFrameHost {@link RenderFrameHost} to get the encoded images from.
      * @param view container view for the menu.
@@ -112,7 +117,10 @@
             RenderFrameHost renderFrameHost,
             View view,
             float topContentOffsetPx) {
-        if (params.isFile()) return;
+        if (params.isFile()) {
+            destroyContextMenuParams(params);
+            return;
+        }
 
         final WindowAndroid windowAndroid = mWebContents.getTopLevelNativeWindow();
 
@@ -124,6 +132,7 @@
                 || mPopulatorFactory == null
                 || !mPopulatorFactory.isEnabled()
                 || mCurrentContextMenu != null) {
+            destroyContextMenuParams(params);
             return;
         }
 
@@ -162,6 +171,8 @@
                         // Has no effect if the classification already succeeded.
                         mChipDelegate.onMenuClosed();
                     }
+                    destroyContextMenuParams(mCurrentContextMenuParams);
+                    mCurrentContextMenuParams = null;
                     if (mNativeContextMenuHelper == 0) return;
                     ContextMenuHelperJni.get().onContextMenuClosed(mNativeContextMenuHelper);
                 };
@@ -263,6 +274,12 @@
         return assertNonNull(sContextMenuHelperMap.get(nativeContextMenuHelper));
     }
 
+    private static void destroyContextMenuParams(@Nullable ContextMenuParams params) {
+        if (params != null) {
+            params.destroy();
+        }
+    }
+
     @NativeMethods
     interface Natives {
         void onContextMenuClosed(long nativeContextMenuHelper);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/ContextMenuLoadUrlParamsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/ContextMenuLoadUrlParamsTest.java
index 03cb17b..c812319 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/ContextMenuLoadUrlParamsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/ContextMenuLoadUrlParamsTest.java
@@ -9,7 +9,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
 
 import android.app.Activity;
 import android.content.Context;
@@ -195,7 +194,6 @@
         AdditionalNavigationParams navigationParams =
                 sOpenNewTabLoadUrlParams.getAdditionalNavigationParams();
         assertNotNull(navigationParams);
-        assertTrue(navigationParams.getInitiatorProcessId().isValid());
     }
 
     /**
diff --git a/chrome/browser/ui/android/context_menu_helper.cc b/chrome/browser/ui/android/context_menu_helper.cc
index 2d50e5fc..2205a9b 100644
--- a/chrome/browser/ui/android/context_menu_helper.cc
+++ b/chrome/browser/ui/android/context_menu_helper.cc
@@ -16,7 +16,6 @@
 #include "components/embedder_support/android/contextmenu/context_menu_builder.h"
 #include "content/public/browser/context_menu_params.h"
 #include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/render_process_host.h"
 #include "extensions/buildflags/buildflags.h"
 #include "third_party/blink/public/mojom/context_menu/context_menu.mojom.h"
 #include "ui/android/view_android.h"
@@ -72,10 +71,8 @@
 
   Java_ContextMenuHelper_showContextMenu(
       env, GetJavaObject(env),
-      context_menu::BuildJavaContextMenuParams(
-          context_menu_params_, model_ptr,
-          render_frame_host.GetProcess()->GetID(),
-          render_frame_host.GetFrameToken().value()),
+      context_menu::BuildJavaContextMenuParams(context_menu_params_, model_ptr,
+                                               render_frame_host),
       render_frame_host.GetJavaRenderFrameHost(), view->GetContainerView(),
       view->content_offset() * view->GetDipScale());
 }
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/content/browser/android/additional_navigation_params_browsertest.cc b/content/browser/android/additional_navigation_params_browsertest.cc
new file mode 100644
index 0000000..afad9807
--- /dev/null
+++ b/content/browser/android/additional_navigation_params_browsertest.cc
@@ -0,0 +1,98 @@
+// Copyright 2026 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/android/additional_navigation_params.h"
+
+#include "base/android/jni_android.h"
+#include "base/functional/callback_helpers.h"
+#include "base/run_loop.h"
+#include "base/test/run_until.h"
+#include "content/browser/renderer_host/render_frame_host_impl.h"
+#include "content/browser/storage_partition_impl.h"
+#include "content/public/browser/android/additional_navigation_params_android.h"
+#include "content/public/browser/initiator_navigation_state.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/common/child_process_id.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/public/test/content_browser_test_utils.h"
+#include "content/public/test/test_utils.h"
+#include "content/shell/browser/shell.h"
+#include "net/dns/mock_host_resolver.h"
+#include "third_party/blink/public/common/tokens/tokens.h"
+#include "url/gurl.h"
+
+namespace content {
+
+class AdditionalNavigationParamsBrowserTest : public ContentBrowserTest {
+ public:
+  void SetUpOnMainThread() override {
+    host_resolver()->AddRule("*", "127.0.0.1");
+    ASSERT_TRUE(embedded_test_server()->Start());
+    ContentBrowserTest::SetUpOnMainThread();
+  }
+
+  WebContents* web_contents() { return shell()->web_contents(); }
+};
+
+// AdditionalNavigationParams carries the initiator frame token across an
+// arbitrary delay before it is consumed by NavigationController::LoadUrl. The
+// initiator frame may be detached during that delay, so creating the params
+// must keep the frame's PolicyContainerHost reachable for the lifetime of the
+// returned keep-alive handle.
+IN_PROC_BROWSER_TEST_F(AdditionalNavigationParamsBrowserTest,
+                       InitiatorPolicyContainerHostKeptAliveAfterFrameDetach) {
+  ASSERT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL(
+                   "a.com", "/cross_site_iframe_factory.html?a.com(b.com)")));
+
+  RenderFrameHostImpl* child_rfh =
+      static_cast<RenderFrameHostImpl*>(ChildFrameAt(web_contents(), 0));
+  ASSERT_TRUE(child_rfh);
+
+  const blink::LocalFrameToken child_token = child_rfh->GetFrameToken();
+  const ChildProcessId child_process_id = child_rfh->GetProcess()->GetID();
+
+  base::android::ScopedJavaLocalRef<jobject> java_params =
+      CreateJavaAdditionalNavigationParams(
+          base::android::AttachCurrentThread(), *child_rfh,
+          /*attribution_src_token=*/std::nullopt);
+  ASSERT_TRUE(java_params);
+
+  // Detach the initiator frame while still holding the params.
+  RenderFrameDeletedObserver deleted_observer(child_rfh);
+  ASSERT_TRUE(
+      ExecJs(web_contents(), "document.querySelector('iframe').remove();"));
+  ASSERT_TRUE(deleted_observer.WaitUntilDeleted());
+  ASSERT_FALSE(
+      RenderFrameHostImpl::FromFrameToken(child_process_id, child_token));
+
+  // Verify round-trip extraction of frame token and process ID even after frame
+  // detachment.
+  std::optional<blink::LocalFrameToken> extracted_frame_token =
+      GetInitiatorFrameTokenFromJavaAdditionalNavigationParams(
+          base::android::AttachCurrentThread(), java_params);
+  EXPECT_TRUE(extracted_frame_token.has_value());
+  EXPECT_EQ(extracted_frame_token.value(), child_token);
+
+  ChildProcessId extracted_process_id =
+      GetInitiatorProcessIdFromJavaAdditionalNavigationParams(
+          base::android::AttachCurrentThread(), java_params);
+  EXPECT_FALSE(extracted_process_id.is_null());
+  EXPECT_EQ(extracted_process_id, child_process_id);
+
+  // We can get the state from the Java object.
+  scoped_refptr<InitiatorNavigationState> taken_state =
+      TakeNativeStateFromJavaAdditionalNavigationParams(
+          base::android::AttachCurrentThread(), java_params);
+  EXPECT_TRUE(taken_state);
+
+  // Clean up the Java object to satisfy LifetimeAssert and release native
+  // state.
+  DestroyJavaAdditionalNavigationParams(base::android::AttachCurrentThread(),
+                                        java_params);
+}
+
+}  // namespace content
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index a2b70da..6dfdf63 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -2299,6 +2299,7 @@
     sources += [
       "../browser/accessibility/android_granularity_movement_browsertest.cc",
       "../browser/accessibility/ime_accessibility_browsertest.cc",
+      "../browser/android/additional_navigation_params_browsertest.cc",
       "../browser/android/nfc_host_browsertest.cc",
       "../browser/android/render_widget_host_connector_browsertest.cc",
       "../browser/android/render_widget_host_connector_browsertest.h",
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.