CVE-2026-113064
Overview
Files Changed
third_party/blink/renderer/platform/runtime_enabled_features.json5
Patch
From fc387e823651866444f3ad366b9552caf3e65b9d Mon Sep 17 00:00:00 2001
From: Nan Lin <linnan@chromium.org>
Date: Thu, 17 Sep 2026 10:19:20 -0700
Subject: [PATCH] Default enable AIPageContentTrackedElementsPassword
This default enables password redaction via compositor in page context
extraction.
Bug: b:439921639
Fixed: 553146807
Change-Id: Ie14cd3c06e038c847e7d7219e26dff254f213b09
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8420124
Reviewed-by: David Bokan <bokan@chromium.org>
Commit-Queue: Nan Lin <linnan@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1699930}
---
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index a58175f..f7d74a8 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -418,7 +418,7 @@
// tracked using the Element::SetTrackedElementSubRect() method.
{
name: "AIPageContentTrackedElementsPassword",
- status: "test"
+ status: "stable"
},
// Clamp AIPageContent visible bounding boxes to the local-root viewport
// after visual-viewport mapping to normalize viewport-relative geometry.
Original Bug Report
Glic screenshot redaction TOCTOU leaks unredacted sensitive field pixels
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: PageContextFetcher captures viewport screenshots and calculates Annotated Page Content (APC) sensitive-field redaction bounding boxes through two unsynchronized asynchronous pipelines. Because the merge logic applies only a resolution scale factor without verifying layout or scroll state between the surface snapshot and the Blink layout walk, page motion can displace or collapse redaction rectangles. This can potentially leak unredacted sensitive pixels (such as revealed plaintext passwords) in screenshots uploaded to the AI backend.
Affected files:
components/page_content_annotations/content/page_context_fetcher.ccthird_party/blink/renderer/modules/content_extraction/ai_page_content_agent.cccomponents/optimization_guide/content/browser/page_content_proto_util.cccomponents/page_content_annotations/content/page_context_fetcher.h
Estimated timestamp from git blame: 2025-12-19
Summary
PageContextFetcher is responsible for collecting page context—including viewport screenshots and Annotated Page Content (APC)—for Glic and Glic Actor flows. To protect user privacy, it draws redaction boxes over sensitive fields (e.g., password fields in cleartext/revealed states) before the screenshot is encoded and sent to the model backend. However, the surface bitmap capture and the APC layout walk operate via two separate asynchronous pipelines that lack synchronization, introducing a potential time-of-check to time-of-use (TOCTOU) race condition.
Root Cause
In components/page_content_annotations/content/page_context_fetcher.cc:
-
Pipeline 1 (Compositor Surface Capture - Time T1):
PageContextFetcher::FetchStartcallsGetTabScreenshot(page_context_fetcher.cc:418), which callsview->CopyFromSurface(...)(page_context_fetcher.cc:718-724). This snapshots the compositor surface as rendered at time T1 intoscreenshot_bitmap_(page_context_fetcher.cc:759-779). -
Pipeline 2 (Renderer Layout Walk - Time T2): Concurrently,
FetchStartrequests APC viaoptimization_guide::GetAIPageContent(...)(page_context_fetcher.cc:473-476). In the default configuration:kGlicScreenshotPasswordRedactionis enabled by default (page_context_fetcher.cc:1185-1186).kAIPageContentTrackedElementsPasswordis disabled by default (runtime_enabled_features.json5:397-400).- Thus,
include_passwords_for_redactionis set totrue(page_context_fetcher.cc:456-458).
When the renderer receives this IPC,
AIPageContentAgentrunsUpdateLifecycle(document)at time T2 (third_party/blink/renderer/modules/content_extraction/ai_page_content_agent.cc:2233) and calculates bounding boxes viaComputeVisibleBoundingBox(ai_page_content_agent.cc:273-303, 2971-2985). These boxes reflect the visual viewport coordinates at time T2. -
Unsynchronized Merge and Drawing:
RedactAndEncodeScreenshotIfNeeded(page_context_fetcher.cc:824-866) merges the T2 bounding boxes onto the T1 bitmap using only a resolution scaling factor (ScaleToEnclosingRect, lines 848-863). There is no comparison of frame tokens, scroll offsets, or layout timestamps. If an element is scrolled out of view at T2,ComputeVisibleBoundingBoxclips it to an empty rect(0, 0, 0, 0), which is pushed tovisible_bounding_boxes_for_redaction_without an emptiness check (ai_page_content_agent.cc:2983-2984), resulting in a zero-area draw.
RedactScreenshotOnWorkerThread (page_context_fetcher.cc:326-359) then paints solid rectangles at the T2 positions onto the T1 bitmap. If the element’s position changed between T1 and T2, the redaction box is drawn in the wrong location (or not drawn at all), leaving the original sensitive pixels visible in the screenshot.
Potential Trigger Steps
(Note: These are suggested theoretical steps derived from static code tracing, as automated dynamic verification was not executed.)
- A web page renders a sensitive field in cleartext (for example, an
<input type="password">whose type was changed to"text"via JavaScript, which matchesHasBeenPasswordField()inai_page_content_agent.cc:1624-1652). - The page runs a continuous animation loop (e.g., via
requestAnimationFrame, CSS transforms, orwindow.scrollTo) that oscillates the element between Position A and Position B (or scrolls it out of view). - The page delays main-thread IPC processing (e.g., via heavy DOM or short tasks) to ensure a latency delta between the Viz surface snapshot (T1) and the Blink layout walk (T2).
- When Glic or Glic Actor initiates a context fetch on the tab, the bitmap is captured at T1 (element at Position A) while APC evaluates geometry at T2 (element at Position B or clipped to empty).
RedactScreenshotOnWorkerThreadapplies the redaction box to Position B, leaving Position A unredacted in the resulting encoded screenshot sent to the backend.
Impact
Defeats the password/sensitive-field redaction mechanism in the default browser configuration without requiring a compromised renderer. Sensitive cleartext pixels can be exposed in screenshots sent to the AI backend.
Suggested Fix
- Atomic Redaction Geometry: Promote
blink::features::kAIPageContentTrackedElementsPasswordto stable so that password coordinates are tracked atomically with the compositor frame via Viz (TrackedElementRects), rather than relying on an asynchronous layout extraction. - Layout/Scroll Validation: Validate that the frame token, layout generation token, and scroll offsets match between the surface snapshot and the APC extraction before applying redactions. If a mismatch is detected, re-capture or fail closed (e.g., suppress the screenshot or redact conservatively).
- Filter Empty Bounding Boxes: In
CollectGeometryForRedactedNodes(ai_page_content_agent.cc:2971-2985), ensure empty/zero-area bounding boxes are not added, and ensurePageContextFetcherhandles clipped/off-screen elements safely.
Evaluated with Chrome root at commit: c6718ebbf2c677c6f63691e28c7801c563f6b19c
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.