CVE-2025-8581
Overview
Background
- `ExtensionTabUtil::OpenTab()`
- the helper backing
chrome.tabs.create()that buildsNavigateParamsand starts a navigation into a newly created tab. - `TabsUpdateFunction::UpdateURL()`
- the helper backing
chrome.tabs.update()that navigates the current tab, and which already set renderer-initiated navigation parameters. - PDF Viewer extension
- a built-in Chrome extension (id
extension_misc::kPdfExtensionId) that renders PDFs and useschrome.tabs.create()/chrome.tabs.update()to open links from within a document. - `NavigateParams` (`is_renderer_initiated`, `initiator_origin`, `source_site_instance`)
- fields that record who initiated a navigation, used by browser-side security checks that depend on the initiator’s origin.
Root Cause Analysis
When the PDF Viewer opened a link in a new tab via chrome.tabs.create(), control reached ExtensionTabUtil::OpenTab(), which built a NavigateParams without marking the navigation as renderer-initiated and without attaching the PDF extension’s initiator_origin and source_site_instance. This is inconsistent with same-tab link navigations, which flow through TabsUpdateFunction::UpdateURL() where those parameters are already set. The violated invariant is that a navigation triggered by content inside the PDF Viewer should be attributed to the PDF extension’s origin consistently regardless of whether it targets the current tab or a new tab; treating the new-tab case as effectively browser-initiated with no initiator misrepresents its provenance to downstream navigation/security logic.
The fix copies the UpdateURL() behavior into OpenTab() for the PDF extension only: it sets navigate_params.is_renderer_initiated = true, navigate_params.initiator_origin = extension->origin(), and creates a matching source_site_instance. The change also hoists function->extension() into a local extension and reuses it, keeping the incognito split-mode branch and the new PDF branch reading the same value.
OpenTab() set the same renderer-initiated parameters as UpdateURL() for the PDF extension, giving both paths consistent, correctly attributed navigation provenance.Attack Path
- Trigger a PDF Viewer new-tab navigation
A link inside a rendered PDF (or the viewer UI) causes the PDF Viewer extension to call
chrome.tabs.create()for the target URL, reachingExtensionTabUtil::OpenTab(). - Navigation built without initiator attribution
Pre-patch,
OpenTab()produced aNavigateParamslackingis_renderer_initiated,initiator_origin, andsource_site_instance, so the resulting navigation was not attributed to the PDF extension’s origin. - Inconsistent security handling Because initiator-dependent navigation checks saw no (or a wrong) initiator, the new-tab navigation was handled differently from the equivalent same-tab navigation, an inappropriate implementation the advisory flags in Extensions.
- Downstream misattribution
Any concrete abuse (e.g. origin/URL spoofing or bypass of an initiator-based restriction) that follows from the missing attribution is
(inferred), as the patch demonstrates only the parameter inconsistency, not a specific downstream sink.
Impact Assessment
chrome.tabs.create()). The advisory rates this an inappropriate implementation (logic error) in Extensions with no stated in-the-wild exploitation; any spoofing or restriction-bypass consequence is (inferred).Changed Functions
| Function | Change | Notes |
|---|---|---|
ifchrome/browser/extensions/extension_tab_util.cc |
modified |
Files Changed
chrome/browser/extensions/extension_tab_util.cc
Audit Directions
- Divergent navigation entry pointsCompare
chrome.tabs.create()/OpenTab()andchrome.tabs.update()/UpdateURL()(and other navigation helpers) for asymmetric setting ofis_renderer_initiated,initiator_origin, andsource_site_instance. - Missing initiator origin on privileged-origin navigationsLook for navigations started on behalf of built-in extensions or WebUI that omit the initiator’s origin/site instance, weakening initiator-dependent checks.
- Special-cased single-caller fixesWhere a fix is applied to only one caller (here the PDF extension) for compatibility, audit the other callers of the same helper for the same unattributed-navigation gap.
Patch
From d2d70e969646e9ba1c5f4a0ad586fe327eefc7b6 Mon Sep 17 00:00:00 2001
From: Lei Zhang <thestig@chromium.org>
Date: Mon, 09 Jun 2025 18:05:21 -0700
Subject: [PATCH] [PDF] Perform navigations from the PDF Viewer more consistently
The PDF Viewer uses chrome.tabs.update() and chrome.tabs.create() to
navigate to links in the current tab and in a new tab, respectively. To
make their behavior more consistent, copy navigation params from
TabsUpdateFunction::UpdateURL() to ExtensionTabUtil::OpenTab().
It may be beneficial for ExtensionTabUtil::OpenTab() to use the PDF
Viewer behavior for all chrome.tabs.create() calls. But for now, only
apply it to the PDF Viewer to avoid potential compatibility issues.
Bug: 416942878
Change-Id: I797b9efa38872fa9269ba01cde752e0796dd2ef8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6629248
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Nasko Oskov <nasko@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1471532}
---
diff --git a/chrome/browser/extensions/extension_tab_util.cc b/chrome/browser/extensions/extension_tab_util.cc
index 9829dce..ae5337d 100644
--- a/chrome/browser/extensions/extension_tab_util.cc
+++ b/chrome/browser/extensions/extension_tab_util.cc
@@ -314,11 +314,11 @@
// -title
// -favIconUrl
+ auto* const extension = function->extension();
GURL url(chrome::kChromeUINewTabURL);
if (params.url) {
- ASSIGN_OR_RETURN(url,
- PrepareURLForNavigation(*params.url, function->extension(),
- function->browser_context()));
+ ASSIGN_OR_RETURN(url, PrepareURLForNavigation(*params.url, extension,
+ function->browser_context()));
}
// Default to foreground for the new tab. The presence of 'active' property
@@ -336,8 +336,7 @@
// We can't load extension URLs into incognito windows unless the extension
// uses split mode. Special case to fall back to a tabbed window.
if (url.SchemeIs(kExtensionScheme) &&
- (!function->extension() ||
- !IncognitoInfo::IsSplitMode(function->extension())) &&
+ (extension || !IncognitoInfo::IsSplitMode(extension)) &&
browser->profile()->IsOffTheRecord()) {
Profile* original_profile = browser->profile()->GetOriginalProfile();
@@ -380,6 +379,17 @@
// likely a re-write of how this navigation is called to be compatible with
// the navigation capturing behavior.
navigate_params.pwa_navigation_capturing_force_off = true;
+
+ // Treat PDF open-in-new-window navigations consistently with other PDF
+ // navigations, as done in TabsUpdateFunction::UpdateURL().
+ if (extension && extension->id() == extension_misc::kPdfExtensionId) {
+ 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());
+ }
+
base::WeakPtr<content::NavigationHandle> handle = Navigate(&navigate_params);
if (handle && params.bookmark_id) {
ChromeNavigationUIData* ui_data =
Original Bug Report
SameSite Strict cookies are included when middle clicking a link to another site in a PDF document
Report description
SameSite Strict cookies are included when middle clicking a link to another site in a PDF document
Bug location
Where do you want to report your vulnerability?
Chrome VRP – Report security issues affecting the Chrome browser. See program rules
The problem
Please describe the technical details of the vulnerability
Steps to reproduce:
- Navigate to a page that has set a cookie with SameSite=Strict
- Create a PDF document with a link to that page
- Open that PDF in Chrome, and open the link in a new tab with a middle mouse click
- The SameSite cookie is included with the request for that tab, even if the PDF was served from a different site.
The above steps detail the basic idea, however for ease of reproduction I have also created a Flask application to demonstrate the behaviour at the following GitHub repository: https://github.com/gnea-sec/samesite-demo
- Add an entry to your hosts file, such as
notlocalhost, that also points to127.0.0.1. - Launch the server, and navigate to http://localhost:8181/setcookie
- This sets a cookie with SameSite=Strict
- Verify that the cookie is set at http://localhost:8181/showcookie
- Navigate to http://notlocalhost:8181/pdflink
- Note that this is on a separate domain
notlocalhost, and following links from this site should not include the SameSite cookie.
- Note that this is on a separate domain
- Middle mouse click on the link to open it in a new tab. Note that the tab indicates that the SameSite cookie was received.
- Opening the link by left clicking, or right clicking and selecting “Open link in new tab” does not include the cookie.
- The origin of the link can be further obfuscated, such as by loading it in an iframe, as demonstrated in the mentioned application at http://notlocalhost:8181/frame
The attached video samesite-example.mp4 shows this server being used to demonstrate the issue. It shows a regular HTML link that does not include the SameSite cookie when followed from another site, and then shows the PDF document being served from another site. When the PDF link is followed with a left click, or right click and open in new tab, it does not include the SameSite cookie. However, when the link in a PDF document is middle clicked, it does include the SameSite cookie.
Impact analysis – Please briefly explain who can exploit the vulnerability, and what they gain when doing so
SameSite Strict cookies should not be included when following links from another site. If a website has functionality that can perform a sensitive action with a GET request, and it is relying on a SameSite cookie to prevent unauthorized access, then this can be used in social engineering attacks against users of that site. Any malicious actor would be able to target users of websites that are vulnerable in this way, and use this issue to exploit CSRF vulnerabilities.
This issue can be exploited to circumvent SameSite cookie protections. Following a link from another site should not include SameSite cookies. While a secure web application should not be significantly impacted by this issue, it has the potential to exacerbate certain misconfigurations. For instance, if a GET request is able to perform a sensitive action (it would not be unheard of for an endpoint intended to receive POST requests to also accept GET), then a malicious site could display a PDF loaded in an iframe, and use social engineering techniques to convince users to middle click on the link. A targeted phishing campaign does not need to fool everyone, it just needs to fool one person.
The cause
What version of Chrome have you found the security issue in?
Version 136.0.7103.93 (Official Build) (64-bit)
Is the security issue related to a crash?
No, it is not related to a crash.
Choose the type of vulnerability
Cross-site request forgery (CSRF)
How would you like to be publicly acknowledged for your report?
Vincent Dragnea