Low watch CVSS 5.3 chrome Policy Bypass 📄 Reporter bug report 🔧 Commit mapped

Overview

Low
Severity
5.3
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInsufficient policy enforcement in PDF
DescriptionInsufficient policy enforcement in PDF
ComponentPDF
Bug ClassPolicy Bypass
Action tierwatch — logic/policy bug — security-relevant, no memory-unsafety
Computed by PatchGap's deterministic exploitability ruler from the fixing commit. patch-now = RCE-class & attacker-reachable in a default config, or exploited in the wild; watch = real security signal below that bar; noise = no security relevance.
Tracker40058077
Fix commitb6371f6acfdb (chromium/src) +28/-17
CWECWE-284
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N
CISA KEVNot listed
CreditedNDevTK
Reported2021-11-30 · bounty $1000 (per vendor advisory)
Fix landed2026-01-29 (public git)
Disclosed2026-03-10
Patch gap40 days — fix public in source before the advisory

Background

PDF Viewer extension (`extension_misc::kPdfExtensionId`)
Chrome’s built-in PDF viewer runs as a component extension and uses extension APIs such as tabs.create and windows.create to open links from a PDF in a new tab or window.
`NavigateParams`
The browser-side description of a navigation passed to Navigate(). Its is_renderer_initiated, initiator_origin and source_site_instance fields tell the navigation stack whether to apply the stricter checks for content-initiated navigations or treat the navigation as trusted and browser-initiated.
`OpenTabHelper`
A helper in chrome/browser/extensions/open_tab_helper.cc that implements tab opening for extension functions (e.g. tabs.create) and builds NavigateParams.
Renderer-initiated vs browser-initiated
Browser-initiated navigations (e.g. typed in the omnibox) get more privilege, such as being allowed to load URLs that web content may not open. Content-originated navigations must be marked renderer-initiated with a correct initiator so those restrictions apply.

Root Cause Analysis

The supplied diff is described by its own commit message as a refactor (“Combine duplicate PDF navigation code … into a common function”). It does not clearly show the advisory’s policy-enforcement fix. Both before and after the patch, when the calling extension is the PDF Viewer, NavigateParams gets is_renderer_initiated = true, initiator_origin = extension->origin() and a source_site_instance created for that origin.

The patch moves this logic into the new static OpenTabHelper::MaybeSetPdfNavigateParams and calls it from OpenTabHelper::OpenTab (same behavior as before) and from the window-creation path in chrome/browser/extensions/api/tabs/tabs_api.cc. The commit message ties that path to WindowsCreateFunction::OnBrowserWindowCreated(), but the enclosing function is not named in the hunk. The one visible behavior change is in that tabs_api.cc path: the old if (PDF) {...} else if (set_self_as_opener_) {...} chain becomes an early return navigate_params; when the helper returns true, so any statements after the set_self_as_opener_ block are now skipped for PDF Viewer navigations. The hunk does not show what those statements are. The underlying invariant, that navigations triggered by PDF content opening new tabs or windows must be treated as renderer-initiated from the PDF extension’s origin and not as privileged browser-initiated navigations, is consistent with the advisory. However, this diff alone does not show which earlier path lacked it, so the connection between this commit and the vulnerability is not established by the diff and may lie in a related CL under bug 40058077.

Key insight
PDF-originated new-tab/new-window navigations must carry renderer-initiated status and the PDF extension’s initiator so that content-navigation policy applies. This commit centralizes that marking in OpenTabHelper::MaybeSetPdfNavigateParams and makes the window path return right after applying it, but it is mainly a consolidation, not a visibly new check.

Attack Path

  1. Deliver a crafted PDF The attacker hosts a PDF containing a link and the victim opens it in Chrome’s built-in PDF viewer.
  2. Link opened in new tab/window The PDF viewer opens the link through the extension tabs/windows APIs (OpenTabHelper::OpenTab or the window-creation path in tabs_api.cc) (inferred: a user click is likely needed to follow the link).
  3. Navigation classified by `NavigateParams` Whether the target URL is subject to renderer-initiated navigation restrictions depends on the is_renderer_initiated/initiator_origin/source_site_instance values set for PDF Viewer calls.
  4. Policy bypass if misclassified On a path that does not mark the navigation as PDF/renderer-initiated (or that later overrides those fields), the navigation could get browser-initiated privileges and reach URLs web content should not open (inferred; the diff does not show the specific bypassed check).

Impact Assessment

The advisory describes insufficient policy enforcement in PDF, rated low severity by the vendor. The advisory data provided does not report in-the-wild exploitation. Plausible impact is a navigation-policy bypass in which a link in an attacker-supplied PDF opens a tab or window with more privilege than web content should have (inferred). Preconditions are that the victim opens the PDF in Chrome’s built-in viewer and follows a link that opens a new tab or window (inferred). The diff shows no memory corruption or escalation beyond navigation classification.

Changed Functions

FunctionChangeNotes
if
chrome/browser/extensions/api/tabs/tabs_api.cc
modified
if
chrome/browser/extensions/open_tab_helper.cc
modified
BrowserWindowInterface
chrome/browser/extensions/open_tab_helper.h
modified
ExtensionFunction
chrome/browser/extensions/open_tab_helper.h
modified
GURL
chrome/browser/extensions/open_tab_helper.h
modified
WebContents
chrome/browser/extensions/open_tab_helper.h
modified

Files Changed

  • chrome/browser/extensions/api/tabs/tabs_api.cc
  • chrome/browser/extensions/open_tab_helper.cc
  • chrome/browser/extensions/open_tab_helper.h

Audit Directions

  • Other PDF-initiated navigation entry points
    Check every path through which the PDF viewer or its extension APIs navigate (TabsUpdateFunction::UpdateURL, window creation, downloads, chrome.tabs/chrome.windows calls, postMessage-driven navigations) and confirm each sets renderer-initiated status, the PDF initiator origin and a matching source_site_instance.
  • Extension API `NavigateParams` construction
    Audit extension functions that build NavigateParams for code that leaves is_renderer_initiated false or omits initiator_origin when the request can come from untrusted content. That gives browser-initiated privileges to attacker-controlled URLs.
  • Fields overwritten after the security-relevant setup
    Where NavigateParams is filled in stages (as in the tabs_api.cc path), confirm later code (set_self_as_opener_, opener/BrowsingInstance handling) cannot overwrite the initiator or site instance set for untrusted callers.
From b6371f6acfdb3ce7dbac92ff054f41123637020f Mon Sep 17 00:00:00 2001
From: Lei Zhang <[email protected]>
Date: Thu, 29 Jan 2026 14:44:40 -0800
Subject: [PATCH] Refactor common code into OpenTabHelper::MaybeSetPdfNavigateParams()

Combine duplicate PDF navigation code in OpenTabHelper::OpenTab() and
WindowsCreateFunction::OnBrowserWindowCreated() into a common function.

Bug: 40058077
Change-Id: If0de22a2514a4ae79be478e565d34ad36147b8df
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7517501
Reviewed-by: Charlie Reis <[email protected]>
Commit-Queue: Lei Zhang <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1576873}
---

diff --git a/chrome/browser/extensions/api/tabs/tabs_api.cc b/chrome/browser/extensions/api/tabs/tabs_api.cc
index c8789f35..1eef7ed 100644
--- a/chrome/browser/extensions/api/tabs/tabs_api.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_api.cc
@@ -1027,15 +1027,11 @@
     // to be compatible with the navigation capturing behavior.
     navigate_params.pwa_navigation_capturing_force_off = true;
 
-    if (extension() && extension()->id() == extension_misc::kPdfExtensionId) {
-      // Treat PDF open-in-new-window navigations consistently with other PDF
-      // navigations, as done in TabsUpdateFunction::UpdateURL().
-      navigate_params.is_renderer_initiated = true;
-      navigate_params.initiator_origin = extension()->origin();
-      navigate_params.source_site_instance =
-          content::SiteInstance::CreateForURL(
-              browser_context(), navigate_params.initiator_origin->GetURL());
-    } else if (set_self_as_opener_) {
+    if (OpenTabHelper::MaybeSetPdfNavigateParams(*this, navigate_params)) {
+      return navigate_params;
+    }
+
+    if (set_self_as_opener_) {
       // Depending on the `setSelfAsOpener` option, we need to put the new
       // contents in the same BrowsingInstance as their opener.  See also
       // https://crbug.com/713888.
diff --git a/chrome/browser/extensions/open_tab_helper.cc b/chrome/browser/extensions/open_tab_helper.cc
index 1f1aaadc..4591ee08 100644
--- a/chrome/browser/extensions/open_tab_helper.cc
+++ b/chrome/browser/extensions/open_tab_helper.cc
@@ -204,14 +204,7 @@
   // the navigation capturing behavior.
   navigate_params.pwa_navigation_capturing_force_off = true;
 
-  if (extension && extension->id() == extension_misc::kPdfExtensionId) {
-    // Treat PDF open-in-new-tab navigations consistently with other PDF
-    // navigations, as done in TabsUpdateFunction::UpdateURL().
-    navigate_params.is_renderer_initiated = true;
-    navigate_params.initiator_origin = extension->origin();
-    navigate_params.source_site_instance = content::SiteInstance::CreateForURL(
-        function.browser_context(), navigate_params.initiator_origin->GetURL());
-  }
+  MaybeSetPdfNavigateParams(function, navigate_params);
 
   base::WeakPtr<content::NavigationHandle> handle = Navigate(&navigate_params);
   if (handle && params.bookmark_id) {
@@ -235,4 +228,19 @@
   return new_contents;
 }
 
+// static
+bool OpenTabHelper::MaybeSetPdfNavigateParams(const ExtensionFunction& function,
+                                              NavigateParams& navigate_params) {
+  auto* const extension = function.extension();
+  if (!extension || extension->id() != extension_misc::kPdfExtensionId) {
+    return false;
+  }
+
+  navigate_params.is_renderer_initiated = true;
+  navigate_params.initiator_origin = extension->origin();
+  navigate_params.source_site_instance = content::SiteInstance::CreateForURL(
+      function.browser_context(), navigate_params.initiator_origin->GetURL());
+  return true;
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/open_tab_helper.h b/chrome/browser/extensions/open_tab_helper.h
index 3a23f797..05130f8 100644
--- a/chrome/browser/extensions/open_tab_helper.h
+++ b/chrome/browser/extensions/open_tab_helper.h
@@ -14,6 +14,7 @@
 class BrowserWindowInterface;
 class ExtensionFunction;
 class GURL;
+struct NavigateParams;
 
 namespace content {
 class WebContents;
@@ -53,6 +54,12 @@
       BrowserWindowInterface& browser,
       const ExtensionFunction& function,
       const Params& params);
+
+  // If `function` is for the PDF Viewer, then mark the PDF-initiated navigation
+  // as renderer-initiated in `navigate_params` and return true. Otherwise
+  // return false and `navigate_params` remains the same.
+  static bool MaybeSetPdfNavigateParams(const ExtensionFunction& function,
+                                        NavigateParams& navigate_params);
 };
 
 }  // namespace extensions
Loading diff…

Original Bug Report

reported by [email protected]

PDF bookmarks bypass SameSite Strict cookies.

UserAgent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36

Steps to reproduce the problem:

  1. On the target set a cookie using document.cookie = “A=A;Secure;SameSite=Strict”;
  2. Create a PDF with a URL bookmark or use https://github.com/chromium/chromium/blob/main/chrome/test/data/pdf/test-bookmarks-with-zoom.pdf
  3. Click the bookmark on the PDF and notice the cookies gets sent. With the following headers: sec-fetch-site “none” sec-fetch-mode “navigate” sec-fetch-dest “document”

I think because extension APIs are used such as chrome.tabs.create, Restrictions that are normally put on navigation’s get bypassed excluding the schemes since that gets checked well not sure if it gets checked for submitForm but thats POST only.

What is the expected behavior? For it to be like chrome.tabs.update and keep the initiator.

What went wrong? PDF viewer bypassing SameSite Strict cookies and Fetch metadata defenses.

Did this work before? N/A

Chrome version: 96.0.4664.45 Channel: stable OS Version: 10.0

View on issue tracker