CVE-2026-106403
Overview
Files Changed
extensions/renderer/resources/automation/automation_node.js
Patch
From 1d5fc1a9a05528f61d2a9bb57d25ee281a7b56b5 Mon Sep 17 00:00:00 2001 From: Hongyu Long <[email protected]> Date: Tue, 01 Sep 2026 14:59:18 -0700 Subject: [PATCH] [Automation] Use CSPRNG for action request ID generation In the Automation API extension runtime, pending action callbacks are registered in a global map to facilitate cross-tree hit test callback resolution. Currently, request IDs are generated using Math.random(), which relies on a non-cryptographic PRNG whose internal state can be reconstructed after observing minimal outputs. This change migrates request ID generation in addActionResultCallback to the Web Cryptography API (crypto.getRandomValues). Pre-allocating a module-scoped Uint32Array buffer avoids garbage collection churn on frequent action paths. The generated values are masked to positive 31-bit integers to preserve compatibility with signed int32_t IPC contracts while ensuring cryptographic unpredictability. Bug: 523601696 Change-Id: I4706529645f2442d3f3ff87b4e8f79e4f4b01519 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8310032 Reviewed-by: Katie D <[email protected]> Commit-Queue: Hongyu Long <[email protected]> Reviewed-by: Chad Duffin <[email protected]> Cr-Commit-Position: refs/heads/main@{#1690170} --- diff --git a/extensions/renderer/resources/automation/automation_node.js b/extensions/renderer/resources/automation/automation_node.js index 583a2d3..c413c26bb 100644 --- a/extensions/renderer/resources/automation/automation_node.js +++ b/extensions/renderer/resources/automation/automation_node.js @@ -9,6 +9,9 @@ const INT32_MAX = 2147483647; +// Reusable buffer for generating cryptographic random action request IDs. +const randomBuffer = new Uint32Array(1); + const natives = requireNative('automationInternal'); const IsInteractPermitted = natives.IsInteractPermitted; @@ -1967,8 +1970,9 @@ let requestID; const map = AutomationRootNodeImpl.actionRequestIDToCallback; do { - requestID = Math.floor(Math.random() * INT32_MAX); - } while (Object.hasOwn(map, requestID)); + crypto.getRandomValues(randomBuffer); + requestID = randomBuffer[0] & INT32_MAX; + } while (requestID === 0 || Object.hasOwn(map, requestID)); map[requestID] = { actionType,
Original Bug Report
Cross-tree callback hijacking in Automation API due to Math.random()
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: The Chrome automation extension uses Math.random() to generate request IDs for accessibility actions. A compromised renderer can observe these IDs via Mojo, predict future IDs, and forge accessibility events to hijack action callbacks intended for other origins or the desktop tree.
Affected files:
extensions/renderer/resources/automation/automation_node.js
Estimated timestamp from git blame: Unknown (Google3 checkout)
Summary
A potential vulnerability in the Chrome automation API allows a compromised renderer to perform cross-tree callback hijacking. The automation extension uses Math.random() to generate requestID values for tracking the results of accessibility actions. These IDs are sent to renderers via Mojo IPC. Because Math.random() is mathematically predictable, a compromised renderer can recover the PRNG state and predict future request IDs. Combined with a globally shared callback map that lacks origin verification, an attacker can intercept and resolve callbacks intended for other accessibility trees (e.g., the desktop tree or other tabs).
Technical Details
- Insecure ID Generation: In
extensions/renderer/resources/automation/automation_node.js, theaddActionResultCallbackfunction generates request IDs usingMath.random():
// Line 1970
requestID = Math.floor(Math.random() * INT32_MAX);
V8’s Math.random() implementation is a non-cryptographic PRNG. Its internal state can be reconstructed after observing a small number of consecutive outputs.
-
Information Leak via Mojo: Request IDs are passed to renderer processes through the
RenderAccessibilityMojo interface (third_party/blink/public/mojom/render_accessibility.mojom), for example, via therequest_idparameter inHitTestor withinAXActionDataforPerformAction. A compromised renderer can observe these values and recover the extension V8 context’s PRNG state. -
Cross-Tree Hijacking: The
actionRequestIDToCallbackmap inautomation_node.js(line 1760) is shared globally across all accessibility tree instances. When a forged accessibility event arrives with a predictedactionRequestID, theonActionResulthandler (line 2002) performs a lookup in this global map using only therequestIDas the key. There is no check to ensure that the event originated from the same tree that initiated the request.
Potential Attack Scenario
(Note: These are suggested steps; our tooling has not executed a live proof of concept.)
- An attacker compromises a renderer process hosting their website.
- The user has an accessibility extension active (e.g., ChromeVox on ChromeOS).
- The extension performs normal actions on the compromised renderer’s accessibility tree, exposing several
request_idvalues via Mojo. - The attacker uses these values to reconstruct the extension’s V8
Math.random()state and predicts the next sequence ofrequestIDs. - The extension performs a sensitive action (e.g., a hit test) on a privileged tree (like the desktop or another tab).
- The attacker forges an
ax.mojom.AXUpdatesAndEventsMojo message containing anax.mojom.AXEventwith the predictedaction_request_idand atargetIDfrom their own controlled tree. - The event is routed through the browser to the extension, which looks up the predicted ID in the global
actionRequestIDToCallbackmap. - The extension invokes the victim callback with the attacker’s spoofed node, allowing the attacker to spoof UI content or intercept screen reader interactions.
Recommendation
Request IDs should be generated using a cryptographically secure PRNG. Replace Math.random() with crypto.getRandomValues() in automation_node.js:
const buf = new Uint32Array(1);
crypto.getRandomValues(buf);
requestID = buf[0] & 0x7FFFFFFF;
Evaluated with Chrome root at commit: 65b3256311f3ab6fb9870eaa522de7e6dd2663bb
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.