CVE-2026-11168
Overview
Files Changed
extensions/common/api/_api_features.json
Patch
From 7446ed80981ba25be896e4609ddb11226eae19d7 Mon Sep 17 00:00:00 2001 From: Tim Judkins <[email protected]> Date: Thu, 30 Apr 2026 15:55:25 -0700 Subject: [PATCH] [Extensions] Add an allowlist for metricsPrivate.getHistogram This function originally belonged to the autotestPrivate namespace, but was moved to metricsPrivate in order to make it available for some lacros tests[1]. Since the lacros tests are no longer around, the only caller to this function should be the autotest extension, so this CL restricts it with an Allowlist. Eventually we should actually move this function back to the autotestPrivate namespace, but that requires some changes on the ChromeOS side first in the Autotest extension itself. crbug.com/508312478 has been filed to track that. Note: in reality, the autotest extension is loaded with --allowlisted-extension-id, which lets it bypass the feature check, so really this new feature definition is more just to restrict the function under normal conditions. [1] https://chromium-review.googlesource.com/c/chromium/src/+/2108219 Fixed: 502256049 Change-Id: I3d9dbdc869b3fe2118af2a2534c78c24353e086f Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7805284 Reviewed-by: Devlin Cronin <[email protected]> Commit-Queue: Tim <[email protected]> Cr-Commit-Position: refs/heads/main@{#1623545} --- diff --git a/extensions/common/api/_api_features.json b/extensions/common/api/_api_features.json index 86111029..e0abe3d 100644 --- a/extensions/common/api/_api_features.json +++ b/extensions/common/api/_api_features.json @@ -433,6 +433,16 @@ "channel": "stable", "source": "metricsPrivate" }, + "metricsPrivate.getHistogram": { + "allowlist": [ + // The Autotest extension is loaded with --allowlisted-extension-id, so it + // technically bypasses this check, but this entry is included anyway to + // restrict access to this function under normal circumstances. + // TODO(crbug.com/508312478): getHistogram should be moved back to the + // autotestPrivate namespace. + "0D209B5E4401BB8E7873B5AB5B1346A1CB067015" // ChromeOS Autotest extension + ] + }, "metricsPrivate.getIsCrashReportingEnabled": { "allowlist": [ // This function inherits the extension restrictions of metricsPrivate,
Original Bug Report
Info leak of global UMA data via metricsPrivate.getHistogram in chrome-untrusted://
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 without the Chrome Security team.
Overview: The metricsPrivate.getHistogram API is inadvertently exposed to several chrome-untrusted:// contexts due to missing explicit feature restrictions. A compromised renderer can call this API to fetch process-global UMA histogram data, bypassing profile isolation. This allows an attacker to fingerprint user activity across all origins, including Incognito mode.
Affected files:
extensions/common/api/_api_features.jsonextensions/browser/api/metrics_private/metrics_private_api.ccextensions/browser/extension_function_dispatcher.cccontent/browser/metrics/histogram_synchronizer.cc
Estimated timestamp from git blame: 2025-12-01
Summary
An overly broad API grant in extensions/common/api/_api_features.json exposes the metricsPrivate.getHistogram function to several chrome-untrusted:// origins. Because chrome-untrusted:// surfaces handle untrustworthy content and are treated as potentially compromised, exposing an API that retrieves global browser state allows an attacker with renderer code execution to leak sensitive information that crosses Site Isolation and profile boundaries.
Technical Details
In extensions/common/api/_api_features.json, a ComplexFeature entry for metricsPrivate grants the namespace to contexts: ["webui_untrusted"] for a list of chrome-untrusted:// URLs (e.g., media-app, lens-overlay, boca-app).
The developer’s intent was likely to restrict child methods using the "default_parent": true block, which restricts access to privileged_extension. However, default_parent is only processed at compile time by feature_compiler.py for explicitly listed child features. Because metricsPrivate.getHistogram is entirely omitted from the feature JSON files, it bypasses this compile-time logic.
At runtime, when the renderer’s API bindings check if metricsPrivate.getHistogram is available, ExtensionAPI::IsAvailable falls back to querying the parent metricsPrivate namespace. Since metricsPrivate is a ComplexFeature, its availability check returns true if any of its underlying rules match. Thus, the webui_untrusted rule satisfies the check, and the browser’s ExtensionFunctionDispatcher grants permission.
When metricsPrivate.getHistogram is called, MetricsPrivateGetHistogramFunction::Run() performs the following actions:
- Calls
content::FetchHistogramsAsynchronously(), which usesHistogramSynchronizerandHistogramControllerto broadcast a collection request to all live child processes (renderers, GPU, etc.). - The returned data is merged synchronously into the browser process’s global
base::StatisticsRecorder. - The requested histogram’s sum and bucket counts are returned to the caller.
Because histograms in Chromium are process-global, they are not partitioned by profile. The returned data aggregates samples from all regular and Incognito profiles.
Potential Exploitation Steps
(Note: These are suggested steps; our tooling agent does not yet execute code to provide a working PoC.)
- An attacker gains arbitrary code execution in a
chrome-untrusted://renderer (e.g., by exploiting a Blink vulnerability triggered via a malicious file in the Media App). - From the compromised renderer context, the attacker executes JavaScript:
chrome.metricsPrivate.getHistogram('Blink.UseCounter.Features', (res) => { ... });. - The browser process fetches global histogram data and returns it to the attacker.
- By repeatedly polling sensitive histograms (such as network error codes, password manager metrics, or Blink use counters) and observing the deltas between counts, the attacker can precisely track user activity, infer visited cross-origin websites, and monitor Incognito mode behavior.
Suggested Fix
Explicitly define metricsPrivate.getHistogram in extensions/common/api/_api_features.json to restrict its contexts to privileged_extension (and possibly specific WebUIs that genuinely need it). Alternatively, add an explicit validation check in MetricsPrivateGetHistogramFunction::Run to ensure the caller has the necessary permissions or an associated extension ID.
Evaluated with Chrome root at commit: 096fc8fdbfacf2546485756d03f160a3d04fcc9b
Results so far have been promising, but there can be wrong deductions. If this proves to be a false positive, please close as WAI; 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.