Medium chrome Memory Corruption 📄 Reporter bug report 🔧 Commit mapped

Overview

Medium
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactMemory corruption in OptimizationGuide
DescriptionMemory corruption in OptimizationGuide
ComponentOptimizationGuide
Sub-componentInternals>OptimizationGuide
Bug ClassMemory Corruption
Tracker553146807
Fix commitfc387e823651 (chromium/src) +1/-1
CISA KEVNot listed
CreditedGoogle
Disclosed2026-10-20

Files Changed

  • third_party/blink/renderer/platform/runtime_enabled_features.json5
From fc387e823651866444f3ad366b9552caf3e65b9d Mon Sep 17 00:00:00 2001
From: Nan Lin <[email protected]>
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 <[email protected]>
Commit-Queue: Nan Lin <[email protected]>
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.
Loading diff…

Original Bug Report

reported by [email protected]

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.cc
  • third_party/blink/renderer/modules/content_extraction/ai_page_content_agent.cc
  • components/optimization_guide/content/browser/page_content_proto_util.cc
  • components/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:

  1. Pipeline 1 (Compositor Surface Capture - Time T1): PageContextFetcher::FetchStart calls GetTabScreenshot (page_context_fetcher.cc:418), which calls view->CopyFromSurface(...) (page_context_fetcher.cc:718-724). This snapshots the compositor surface as rendered at time T1 into screenshot_bitmap_ (page_context_fetcher.cc:759-779).

  2. Pipeline 2 (Renderer Layout Walk - Time T2): Concurrently, FetchStart requests APC via optimization_guide::GetAIPageContent(...) (page_context_fetcher.cc:473-476). In the default configuration:

    • kGlicScreenshotPasswordRedaction is enabled by default (page_context_fetcher.cc:1185-1186).
    • kAIPageContentTrackedElementsPassword is disabled by default (runtime_enabled_features.json5:397-400).
    • Thus, include_passwords_for_redaction is set to true (page_context_fetcher.cc:456-458).

    When the renderer receives this IPC, AIPageContentAgent runs UpdateLifecycle(document) at time T2 (third_party/blink/renderer/modules/content_extraction/ai_page_content_agent.cc:2233) and calculates bounding boxes via ComputeVisibleBoundingBox (ai_page_content_agent.cc:273-303, 2971-2985). These boxes reflect the visual viewport coordinates at time T2.

  3. 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, ComputeVisibleBoundingBox clips it to an empty rect (0, 0, 0, 0), which is pushed to visible_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.)

  1. A web page renders a sensitive field in cleartext (for example, an <input type="password"> whose type was changed to "text" via JavaScript, which matches HasBeenPasswordField() in ai_page_content_agent.cc:1624-1652).
  2. The page runs a continuous animation loop (e.g., via requestAnimationFrame, CSS transforms, or window.scrollTo) that oscillates the element between Position A and Position B (or scrolls it out of view).
  3. 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).
  4. 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).
  5. RedactScreenshotOnWorkerThread applies 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

  1. Atomic Redaction Geometry: Promote blink::features::kAIPageContentTrackedElementsPassword to stable so that password coordinates are tracked atomically with the compositor frame via Viz (TrackedElementRects), rather than relying on an asynchronous layout extraction.
  2. 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).
  3. Filter Empty Bounding Boxes: In CollectGeometryForRedactedNodes (ai_page_content_agent.cc:2971-2985), ensure empty/zero-area bounding boxes are not added, and ensure PageContextFetcher handles 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.

View on issue tracker