CVE-2026-106325
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifcontent/browser/web_contents/web_contents_impl.cc |
modified |
Files Changed
content/browser/web_contents/web_contents_impl.cc
Patch
From 3e7fc7921e3e0a3bf5d9a8d845f4bda5392ac0b0 Mon Sep 17 00:00:00 2001
From: Avi Drissman <avi@chromium.org>
Date: Fri, 04 Sep 2026 02:34:43 -0700
Subject: [PATCH] Don't resolve drags from inactive pages
It's possible that a page navigated after the drag started. In that
case, break the drag id lookup in order to cause the drop to fail.
Canceling the drag when the source navigates would be even better, but
that is OS-dependent and non-trivial, so we'll bump that to be a
feature request (https://crbug.com/556278698).
Fixed: 556211265
Bug: 556278698
Change-Id: Ia93513fad2f5d74666daaac58517db2c6a6a6964
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8344248
Auto-Submit: Avi Drissman <avi@chromium.org>
Reviewed-by: Arthur Sonzogni <arthursonzogni@chromium.org>
Commit-Queue: Arthur Sonzogni <arthursonzogni@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1692298}
---
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 20f1cd0..fdc17b7 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -862,7 +862,7 @@
}
RenderFrameHost* rfh = RenderFrameHost::FromFrameToken(source_rfh_token);
- if (!rfh) {
+ if (!rfh || !rfh->IsActive()) {
return nullptr;
}
Original Bug Report
Glic context leak: BFCached drag source bypasses DragSourceDocumentTracker
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: When web content is dragged and dropped into the Glic panel, Chrome resolves the drag ID back to the source tab and extracts its current page context. If the source page navigates mid-drag into the Back/Forward Cache, DragSourceDocumentTracker persists and WebContents::FromDragId succeeds without checking the frame’s lifecycle state. This allows Glic to capture and upload the post-navigation page’s sensitive context misattributed to the pre-navigation URL.
Affected files:
content/browser/web_contents/web_contents_impl.ccchrome/browser/glic/host/glic_drag_and_drop_util.cccontent/browser/web_contents/drag_source_document_tracker.hcontent/browser/web_contents/drag_source_document_tracker.cc
Estimated timestamp from git blame: 2026-05-29
Summary
When a web drag is dropped into the Glic panel, Chrome resolves the internal drag ID back to the initiating tab to fetch its page context. If the initiating web page navigates mid-drag into the Back/Forward Cache (BFCache), DragSourceDocumentTracker and WebContents::FromDragId fail to invalidate the drag. As a result, Chrome extracts and ships the post-navigation page’s annotated text and title to the Glic service, attributed under the pre-navigation page’s URL.
Root Cause Analysis
-
Drag Tracking Registration (
content/browser/web_contents/web_contents_impl.cc:7995-8023): When a drag begins,WebContentsImpl::OnStartDragginggenerates aDragId, associates it with the document viaDragSourceDocumentTracker::GetOrCreateForCurrentDocument(source_frame)->AddDragId(drag_id), and maps the ID to the frame’sGlobalRenderFrameHostTokeninDragSourceMap. -
BFCache Persistence (
content/public/browser/document_user_data.h:40-45):DragSourceDocumentTrackersubclassesDocumentUserData. When a document transitions into the Back/Forward Cache upon navigation, itsDocumentUserDatainstances are intentionally preserved. Consequently,~DragSourceDocumentTrackerdoes not run, and theDragSourceMapentry is not removed. -
Missing Lifecycle State Validation in
WebContents::FromDragId(content/browser/web_contents/web_contents_impl.cc:856-874):WebContents* WebContents::FromDragId(BrowserContext* browser_context, const DragId& drag_id) { auto* map = DragSourceMap::GetOrCreate(browser_context); GlobalRenderFrameHostToken source_rfh_token = map->GetDragSource(drag_id); ... RenderFrameHost* rfh = RenderFrameHost::FromFrameToken(source_rfh_token); if (!rfh) return nullptr; auto* tracker = DragSourceDocumentTracker::GetForCurrentDocument(rfh); if (!tracker || !tracker->has_drag_id(drag_id)) return nullptr; return WebContents::FromRenderFrameHost(rfh); }RenderFrameHost::FromFrameTokenretrieves the BFCachedRenderFrameHostImplfromGetTokenFrameMap().FromDragIdverifies the tracker and returns the tab’sWebContentswithout checking whetherrfhis active (rfh->IsActive()). -
Context Extraction on the Wrong Document (
chrome/browser/glic/host/glic_drag_and_drop_util.cc:303-341): InStartDragAndDropInvoke,source_wc->GetPrimaryMainFrame()is called on the resolvedWebContents. Because the tab navigated, this returns the new primary document (e.g., a victim page), not the original initiating document.FetchPageContextis then invoked on the active tab, capturing the post-navigation page’s annotated content and bundling it with the pre-navigation URL inBuildDragDropAdditionalContext(...:75-77).
Potential Reproduction Steps
(Note: These are suggested theoretical steps based on static code analysis; our automated tooling does not currently possess live execution capabilities.)
- Enable the Glic UI panel alongside the main browser window (feature
features::kGlicWebDragAndDropFileUploadis enabled by default). - Load an attacker page
https://attacker.example/that renders a draggable element and is eligible for BFCache (nounloadlistener, cacheable headers). - In the page’s
dragstartevent listener, initiate a navigation vialocation.href = 'https://victim.example/account'orhistory.back(). - Drag the element toward the Glic panel. The OS drag loop pumps nested application tasks, allowing the navigation to commit while the drag gesture is in flight.
- Drop the element onto the Glic panel.
- Observe that
HandleOnPerformingDrop->StartDragAndDropInvokesucceeds, and Glic receives the annotated page context ofhttps://victim.example/accountattributed tohttps://attacker.example/.
Impact
An attacker-controlled web page can induce Chrome to capture the full semantic text and metadata of a cross-origin, authenticated page that the user never intended to share with Glic, misattributed under the attacker’s URL. The destination sink is the trusted Glic service/backend under the user’s account.
Suggested Fix
- In
WebContents::FromDragId(content/browser/web_contents/web_contents_impl.cc:864-874), enforce that the resolvedRenderFrameHostis currently active before returning:if (!rfh || !rfh->IsActive()) { return nullptr; } - In
chrome/browser/glic/host/glic_drag_and_drop_util.cc, verify thatsource_wc->GetPrimaryMainFrame()matches the initiatingRenderFrameHostor itsWeakDocumentPtrbefore invokingFetchPageContext.
Evaluated with Chrome root at commit: 53c437ac4ea52cc89d0265eb9e6d68666fdb303e
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.