CVE-2026-103626
Overview
Files Changed
chrome/browser/file_system_access/chrome_file_system_access_permission_context_unittest.ccchrome/browser/file_system_access/chrome_file_system_access_permission_context.cc
Patch
From bc5a321c6196db0a2de36f1fe3e4fab977b10007 Mon Sep 17 00:00:00 2001 From: Ming-Ying Chung <[email protected]> Date: Thu, 03 Sep 2026 21:58:57 -0700 Subject: [PATCH] [FSA] Block WSL UNC paths in sensitive directory checks WSL exposes Linux distribution filesystems to the Windows host through the `\\wsl.localhost` and `\\wsl$` UNC namespaces. Because `wsl.localhost` contains only valid DNS characters and does not match "localhost", it bypassed the local UNC heuristic in `MaybeIsLocalUNCPath()`. `ShouldBlockAccessToPath()` relies on `MaybeIsLocalUNCPath()` returning true to block access. When it returned false, execution fell through to evaluate candidate paths against standard blocklist rules. Because those rules resolve to DOS drive letters such as `C:\Users\<user>`, `base::FilePath::IsParent()` returned false against the UNC root, causing `ShouldBlockAccessToPath()` to reach its default return of false and permit access. This permitted websites to pick or write files inside the Linux distribution, including user dotfiles such as `~/.bashrc`. Because WSL enables Windows interop by default, code planted in `~/.bashrc` executes Windows binaries on the host desktop upon terminal launch, escaping the browser sandbox. This CL updates `MaybeIsLocalUNCPath()` to explicitly recognize `wsl.localhost` as a local UNC host on Windows, causing `ShouldBlockAccessToPath()` to abort sensitive checks immediately. Bug: 553114097 Change-Id: I3faa0ed39721c0736c3ebabf018c8f9889dde4a3 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8341352 Reviewed-by: Fergal Daly <[email protected]> Reviewed-by: Rahul Singh <[email protected]> Commit-Queue: Ming-Ying Chung <[email protected]> Cr-Commit-Position: refs/heads/main@{#1692183} --- diff --git a/chrome/browser/file_system_access/chrome_file_system_access_permission_context.cc b/chrome/browser/file_system_access/chrome_file_system_access_permission_context.cc index c9a965a..46cc285 100644 --- a/chrome/browser/file_system_access/chrome_file_system_access_permission_context.cc +++ b/chrome/browser/file_system_access/chrome_file_system_access_permission_context.cc @@ -279,6 +279,8 @@ return false; } +// Returns true if the path is a Universal Naming Convention (UNC) path pointing +// to a local system path, device namespace, or WSL loopback redirector. bool MaybeIsLocalUNCPath(const base::FilePath& path) { if (!path.IsNetwork()) { return false; @@ -293,6 +295,10 @@ if (components.size() >= 2 && (base::FilePath::CompareEqualIgnoreCase(components[1], FILE_PATH_LITERAL("localhost")) || + base::FilePath::CompareEqualIgnoreCase( + components[1], FILE_PATH_LITERAL("wsl.localhost")) || + base::FilePath::CompareEqualIgnoreCase( + components[1], FILE_PATH_LITERAL("wsl.localhost.")) || components[1] == FILE_PATH_LITERAL("127.0.0.1") || components[1] == FILE_PATH_LITERAL(".") || components[1] == FILE_PATH_LITERAL("?") || diff --git a/chrome/browser/file_system_access/chrome_file_system_access_permission_context_unittest.cc b/chrome/browser/file_system_access/chrome_file_system_access_permission_context_unittest.cc index 1f6c5d6..7c067cec 100644 --- a/chrome/browser/file_system_access/chrome_file_system_access_permission_context_unittest.cc +++ b/chrome/browser/file_system_access/chrome_file_system_access_permission_context_unittest.cc @@ -1111,6 +1111,181 @@ SensitiveDirectoryResult::kAbort); } +// Verifies that Windows Subsystem for Linux (WSL) Universal Naming Convention +// (UNC) paths are rejected by sensitive entry access checks. +// +// WSL exposes Linux distribution filesystems through the \\wsl.localhost and +// legacy \\wsl$ UNC namespaces. Because these paths alias local system files +// and shell configuration dotfiles without using DOS drive letters, they must +// Verifies that Windows Subsystem for Linux (WSL) Universal Naming Convention +// (UNC) distribution root paths are rejected by sensitive entry access checks. +TEST_F(ChromeFileSystemAccessPermissionContextNoSymbolicLinkCheckTest, + ConfirmSensitiveEntryAccess_WSL_DistroRoot) { + // Distribution root paths should be blocked. + EXPECT_EQ(ConfirmSensitiveEntryAccessSync( + permission_context(), + PathInfo(FILE_PATH_LITERAL("\\\\wsl.localhost\\Ubuntu")), + HandleType::kDirectory, UserAction::kOpen), + SensitiveDirectoryResult::kAbort); + EXPECT_EQ(ConfirmSensitiveEntryAccessSync( + permission_context(), + PathInfo(FILE_PATH_LITERAL("\\\\wsl.localhost\\Ubuntu\\")), + HandleType::kDirectory, UserAction::kOpen), + SensitiveDirectoryResult::kAbort); +} + +// Verifies that WSL system configuration directories and files are blocked. +TEST_F(ChromeFileSystemAccessPermissionContextNoSymbolicLinkCheckTest, + ConfirmSensitiveEntryAccess_WSL_SystemPaths) { + // Distribution system configuration directories should be blocked. + EXPECT_EQ(ConfirmSensitiveEntryAccessSync( + permission_context(), + PathInfo(FILE_PATH_LITERAL("\\\\wsl.localhost\\Ubuntu\\etc")), + HandleType::kDirectory, UserAction::kOpen), + SensitiveDirectoryResult::kAbort); + EXPECT_EQ( + ConfirmSensitiveEntryAccessSync( + permission_context(), + PathInfo(FILE_PATH_LITERAL("\\\\wsl.localhost\\Ubuntu\\etc\\shadow")), + HandleType::kFile, UserAction::kOpen), + SensitiveDirectoryResult::kAbort); + EXPECT_EQ(ConfirmSensitiveEntryAccessSync( + permission_context(), + PathInfo(FILE_PATH_LITERAL("\\\\wsl.localhost\\Ubuntu\\root")), + HandleType::kDirectory, UserAction::kOpen), + SensitiveDirectoryResult::kAbort); +} + +// Verifies that WSL user home directories, .ssh, and shell init dotfiles +// (.bashrc) are blocked across picker open, save, and non-prompted resolution +// (kNone). +TEST_F(ChromeFileSystemAccessPermissionContextNoSymbolicLinkCheckTest, + ConfirmSensitiveEntryAccess_WSL_UserPaths) { + // User home directories and shell configuration files should be blocked. + EXPECT_EQ( + ConfirmSensitiveEntryAccessSync( + permission_context(), + PathInfo(FILE_PATH_LITERAL("\\\\wsl.localhost\\Ubuntu\\home\\user")), + HandleType::kDirectory, UserAction::kOpen), + SensitiveDirectoryResult::kAbort); + EXPECT_EQ(ConfirmSensitiveEntryAccessSync( + permission_context(), + PathInfo(FILE_PATH_LITERAL( + "\\\\wsl.localhost\\Ubuntu\\home\\user\\.ssh")), + HandleType::kDirectory, UserAction::kOpen), + SensitiveDirectoryResult::kAbort); + EXPECT_EQ(ConfirmSensitiveEntryAccessSync( + permission_context(), + PathInfo(FILE_PATH_LITERAL( + "\\\\wsl.localhost\\Ubuntu\\home\\user\\.ssh")), + HandleType::kDirectory, UserAction::kNone), + SensitiveDirectoryResult::kAbort); + EXPECT_EQ(ConfirmSensitiveEntryAccessSync( + permission_context(), + PathInfo(FILE_PATH_LITERAL( + "\\\\wsl.localhost\\Ubuntu\\home\\user\\.bashrc")), + HandleType::kFile, UserAction::kSave), + SensitiveDirectoryResult::kAbort); + EXPECT_EQ(ConfirmSensitiveEntryAccessSync( + permission_context(), + PathInfo(FILE_PATH_LITERAL( + "\\\\wsl.localhost\\Ubuntu\\home\\user\\.bashrc")), + HandleType::kFile, UserAction::kOpen), + SensitiveDirectoryResult::kAbort); + EXPECT_EQ(ConfirmSensitiveEntryAccessSync( + permission_context(), + PathInfo(FILE_PATH_LITERAL( + "\\\\wsl.localhost\\Ubuntu\\home\\user\\.bashrc")), + HandleType::kFile, UserAction::kNone), + SensitiveDirectoryResult::kAbort); +} + +// Verifies that WSL UNC paths with case variations, trailing dot FQDN syntax, +// and forward slash separators are blocked. +TEST_F(ChromeFileSystemAccessPermissionContextNoSymbolicLinkCheckTest, + ConfirmSensitiveEntryAccess_WSL_PathVariations) { + // Case variations should be blocked. + EXPECT_EQ( + ConfirmSensitiveEntryAccessSync( + permission_context(), + PathInfo(FILE_PATH_LITERAL("\\\\WSL.LOCALHOST\\Ubuntu\\home\\user")), + HandleType::kDirectory, UserAction::kOpen), + SensitiveDirectoryResult::kAbort); + EXPECT_EQ(ConfirmSensitiveEntryAccessSync( + permission_context(), + PathInfo(FILE_PATH_LITERAL("\\\\Wsl.LocalHost\\Ubuntu\\etc")), + HandleType::kDirectory, UserAction::kOpen), + SensitiveDirectoryResult::kAbort); + EXPECT_EQ(ConfirmSensitiveEntryAccessSync( + permission_context(), + PathInfo(FILE_PATH_LITERAL( + "\\\\WSL.LOCALHOST\\UBUNTU\\home\\user\\.bashrc")), + HandleType::kFile, UserAction::kSave), + SensitiveDirectoryResult::kAbort); + EXPECT_EQ(ConfirmSensitiveEntryAccessSync( + permission_context(), + PathInfo(FILE_PATH_LITERAL( + "\\\\WSL.LOCALHOST\\UBUNTU\\home\\user\\.bashrc")), + HandleType::kFile, UserAction::kNone), + SensitiveDirectoryResult::kAbort); + + // Fully qualified domain name syntax with trailing dot should be blocked. + EXPECT_EQ( + ConfirmSensitiveEntryAccessSync( + permission_context(), + PathInfo(FILE_PATH_LITERAL("\\\\wsl.localhost.\\Ubuntu\\home\\user")), + HandleType::kDirectory, UserAction::kOpen), + SensitiveDirectoryResult::kAbort); + + // Forward slash path separators should be blocked. + EXPECT_EQ(ConfirmSensitiveEntryAccessSync( + permission_context(), + PathInfo(FILE_PATH_LITERAL("//wsl.localhost/Ubuntu/home/user")), + HandleType::kDirectory, UserAction::kOpen), + SensitiveDirectoryResult::kAbort); +} + +// Verifies that legacy \\wsl$ redirector paths are rejected. +TEST_F(ChromeFileSystemAccessPermissionContextNoSymbolicLinkCheckTest, + ConfirmSensitiveEntryAccess_WSL_LegacyRedirector) { + EXPECT_EQ( + ConfirmSensitiveEntryAccessSync( + permission_context(), PathInfo(FILE_PATH_LITERAL("\\\\wsl$\\Ubuntu")), + HandleType::kDirectory, UserAction::kOpen), + SensitiveDirectoryResult::kAbort); + EXPECT_EQ(ConfirmSensitiveEntryAccessSync( + permission_context(), + PathInfo(FILE_PATH_LITERAL("\\\\wsl$\\Ubuntu\\home\\user")), + HandleType::kDirectory, UserAction::kOpen), + SensitiveDirectoryResult::kAbort); + EXPECT_EQ( + ConfirmSensitiveEntryAccessSync( + permission_context(), + PathInfo(FILE_PATH_LITERAL("\\\\WSL$\\Ubuntu\\home\\user\\.ssh")), + HandleType::kDirectory, UserAction::kOpen), + SensitiveDirectoryResult::kAbort); +} + +// Verifies that legitimate remote UNC shares remain allowed. +TEST_F(ChromeFileSystemAccessPermissionContextNoSymbolicLinkCheckTest, + ConfirmSensitiveEntryAccess_RemoteUNC_Allowed) { + EXPECT_EQ(ConfirmSensitiveEntryAccessSync( + permission_context(), + PathInfo(FILE_PATH_LITERAL("\\\\server\\share\\foo\\bar")), + HandleType::kDirectory, UserAction::kOpen), + SensitiveDirectoryResult::kAllowed); + EXPECT_EQ(ConfirmSensitiveEntryAccessSync( + permission_context(), + PathInfo(FILE_PATH_LITERAL("\\\\remote-nas\\projects\\my-app")), + HandleType::kDirectory, UserAction::kOpen), + SensitiveDirectoryResult::kAllowed); + EXPECT_EQ(ConfirmSensitiveEntryAccessSync( + permission_context(), + PathInfo(FILE_PATH_LITERAL("\\\\corp.domain.com\\dfs\\team")), + HandleType::kDirectory, UserAction::kOpen), + SensitiveDirectoryResult::kAllowed); +} + // Testing that the */.git/hooks are all blocked. TEST_F(ChromeFileSystemAccessPermissionContextTest, ConfirmSensitiveEntryAccess_SuffixWriteBlock) {
Regression Test / PoC
diff --git a/chrome/browser/file_system_access/chrome_file_system_access_permission_context_unittest.cc b/chrome/browser/file_system_access/chrome_file_system_access_permission_context_unittest.cc
index 1f6c5d6..7c067cec 100644
--- a/chrome/browser/file_system_access/chrome_file_system_access_permission_context_unittest.cc
+++ b/chrome/browser/file_system_access/chrome_file_system_access_permission_context_unittest.cc
@@ -1111,6 +1111,181 @@
SensitiveDirectoryResult::kAbort);
}
+// Verifies that Windows Subsystem for Linux (WSL) Universal Naming Convention
+// (UNC) paths are rejected by sensitive entry access checks.
+//
+// WSL exposes Linux distribution filesystems through the \\wsl.localhost and
+// legacy \\wsl$ UNC namespaces. Because these paths alias local system files
+// and shell configuration dotfiles without using DOS drive letters, they must
+// Verifies that Windows Subsystem for Linux (WSL) Universal Naming Convention
+// (UNC) distribution root paths are rejected by sensitive entry access checks.
+TEST_F(ChromeFileSystemAccessPermissionContextNoSymbolicLinkCheckTest,
+ ConfirmSensitiveEntryAccess_WSL_DistroRoot) {
+ // Distribution root paths should be blocked.
+ EXPECT_EQ(ConfirmSensitiveEntryAccessSync(
+ permission_context(),
+ PathInfo(FILE_PATH_LITERAL("\\\\wsl.localhost\\Ubuntu")),
+ HandleType::kDirectory, UserAction::kOpen),
+ SensitiveDirectoryResult::kAbort);
+ EXPECT_EQ(ConfirmSensitiveEntryAccessSync(
+ permission_context(),
+ PathInfo(FILE_PATH_LITERAL("\\\\wsl.localhost\\Ubuntu\\")),
+ HandleType::kDirectory, UserAction::kOpen),
+ SensitiveDirectoryResult::kAbort);
+}
+
+// Verifies that WSL system configuration directories and files are blocked.
+TEST_F(ChromeFileSystemAccessPermissionContextNoSymbolicLinkCheckTest,
+ ConfirmSensitiveEntryAccess_WSL_SystemPaths) {
+ // Distribution system configuration directories should be blocked.
+ EXPECT_EQ(ConfirmSensitiveEntryAccessSync(
+ permission_context(),
+ PathInfo(FILE_PATH_LITERAL("\\\\wsl.localhost\\Ubuntu\\etc")),
+ HandleType::kDirectory, UserAction::kOpen),
+ SensitiveDirectoryResult::kAbort);
+ EXPECT_EQ(
+ ConfirmSensitiveEntryAccessSync(
+ permission_context(),
+ PathInfo(FILE_PATH_LITERAL("\\\\wsl.localhost\\Ubuntu\\etc\\shadow")),
+ HandleType::kFile, UserAction::kOpen),
+ SensitiveDirectoryResult::kAbort);
+ EXPECT_EQ(ConfirmSensitiveEntryAccessSync(
+ permission_context(),
+ PathInfo(FILE_PATH_LITERAL("\\\\wsl.localhost\\Ubuntu\\root")),
+ HandleType::kDirectory, UserAction::kOpen),
+ SensitiveDirectoryResult::kAbort);
+}
+
+// Verifies that WSL user home directories, .ssh, and shell init dotfiles
+// (.bashrc) are blocked across picker open, save, and non-prompted resolution
+// (kNone).
+TEST_F(ChromeFileSystemAccessPermissionContextNoSymbolicLinkCheckTest,
+ ConfirmSensitiveEntryAccess_WSL_UserPaths) {
+ // User home directories and shell configuration files should be blocked.
+ EXPECT_EQ(
+ ConfirmSensitiveEntryAccessSync(
+ permission_context(),
+ PathInfo(FILE_PATH_LITERAL("\\\\wsl.localhost\\Ubuntu\\home\\user")),
+ HandleType::kDirectory, UserAction::kOpen),
+ SensitiveDirectoryResult::kAbort);
+ EXPECT_EQ(ConfirmSensitiveEntryAccessSync(
+ permission_context(),
+ PathInfo(FILE_PATH_LITERAL(
+ "\\\\wsl.localhost\\Ubuntu\\home\\user\\.ssh")),
+ HandleType::kDirectory, UserAction::kOpen),
+ SensitiveDirectoryResult::kAbort);
+ EXPECT_EQ(ConfirmSensitiveEntryAccessSync(
+ permission_context(),
+ PathInfo(FILE_PATH_LITERAL(
+ "\\\\wsl.localhost\\Ubuntu\\home\\user\\.ssh")),
+ HandleType::kDirectory, UserAction::kNone),
+ SensitiveDirectoryResult::kAbort);
+ EXPECT_EQ(ConfirmSensitiveEntryAccessSync(
+ permission_context(),
+ PathInfo(FILE_PATH_LITERAL(
+ "\\\\wsl.localhost\\Ubuntu\\home\\user\\.bashrc")),
+ HandleType::kFile, UserAction::kSave),
+ SensitiveDirectoryResult::kAbort);
+ EXPECT_EQ(ConfirmSensitiveEntryAccessSync(
+ permission_context(),
+ PathInfo(FILE_PATH_LITERAL(
+ "\\\\wsl.localhost\\Ubuntu\\home\\user\\.bashrc")),
+ HandleType::kFile, UserAction::kOpen),
+ SensitiveDirectoryResult::kAbort);
+ EXPECT_EQ(ConfirmSensitiveEntryAccessSync(
+ permission_context(),
+ PathInfo(FILE_PATH_LITERAL(
+ "\\\\wsl.localhost\\Ubuntu\\home\\user\\.bashrc")),
+ HandleType::kFile, UserAction::kNone),
+ SensitiveDirectoryResult::kAbort);
+}
+
+// Verifies that WSL UNC paths with case variations, trailing dot FQDN syntax,
+// and forward slash separators are blocked.
+TEST_F(ChromeFileSystemAccessPermissionContextNoSymbolicLinkCheckTest,
+ ConfirmSensitiveEntryAccess_WSL_PathVariations) {
+ // Case variations should be blocked.
+ EXPECT_EQ(
+ ConfirmSensitiveEntryAccessSync(
+ permission_context(),
+ PathInfo(FILE_PATH_LITERAL("\\\\WSL.LOCALHOST\\Ubuntu\\home\\user")),
+ HandleType::kDirectory, UserAction::kOpen),
+ SensitiveDirectoryResult::kAbort);
+ EXPECT_EQ(ConfirmSensitiveEntryAccessSync(
+ permission_context(),
+ PathInfo(FILE_PATH_LITERAL("\\\\Wsl.LocalHost\\Ubuntu\\etc")),
+ HandleType::kDirectory, UserAction::kOpen),
+ SensitiveDirectoryResult::kAbort);
+ EXPECT_EQ(ConfirmSensitiveEntryAccessSync(
+ permission_context(),
+ PathInfo(FILE_PATH_LITERAL(
+ "\\\\WSL.LOCALHOST\\UBUNTU\\home\\user\\.bashrc")),
+ HandleType::kFile, UserAction::kSave),
+ SensitiveDirectoryResult::kAbort);
+ EXPECT_EQ(ConfirmSensitiveEntryAccessSync(
+ permission_context(),
+ PathInfo(FILE_PATH_LITERAL(
+ "\\\\WSL.LOCALHOST\\UBUNTU\\home\\user\\.bashrc")),
+ HandleType::kFile, UserAction::kNone),
+ SensitiveDirectoryResult::kAbort);
+
+ // Fully qualified domain name syntax with trailing dot should be blocked.
+ EXPECT_EQ(
+ ConfirmSensitiveEntryAccessSync(
+ permission_context(),
+ PathInfo(FILE_PATH_LITERAL("\\\\wsl.localhost.\\Ubuntu\\home\\user")),
+ HandleType::kDirectory, UserAction::kOpen),
+ SensitiveDirectoryResult::kAbort);
+
+ // Forward slash path separators should be blocked.
+ EXPECT_EQ(ConfirmSensitiveEntryAccessSync(
+ permission_context(),
+ PathInfo(FILE_PATH_LITERAL("//wsl.localhost/Ubuntu/home/user")),
+ HandleType::kDirectory, UserAction::kOpen),
+ SensitiveDirectoryResult::kAbort);
+}
+
+// Verifies that legacy \\wsl$ redirector paths are rejected.
+TEST_F(ChromeFileSystemAccessPermissionContextNoSymbolicLinkCheckTest,
+ ConfirmSensitiveEntryAccess_WSL_LegacyRedirector) {
+ EXPECT_EQ(
+ ConfirmSensitiveEntryAccessSync(
+ permission_context(), PathInfo(FILE_PATH_LITERAL("\\\\wsl$\\Ubuntu")),
+ HandleType::kDirectory, UserAction::kOpen),
+ SensitiveDirectoryResult::kAbort);
+ EXPECT_EQ(ConfirmSensitiveEntryAccessSync(
+ permission_context(),
+ PathInfo(FILE_PATH_LITERAL("\\\\wsl$\\Ubuntu\\home\\user")),
+ HandleType::kDirectory, UserAction::kOpen),
+ SensitiveDirectoryResult::kAbort);
+ EXPECT_EQ(
+ ConfirmSensitiveEntryAccessSync(
+ permission_context(),
+ PathInfo(FILE_PATH_LITERAL("\\\\WSL$\\Ubuntu\\home\\user\\.ssh")),
+ HandleType::kDirectory, UserAction::kOpen),
+ SensitiveDirectoryResult::kAbort);
+}
+
+// Verifies that legitimate remote UNC shares remain allowed.
+TEST_F(ChromeFileSystemAccessPermissionContextNoSymbolicLinkCheckTest,
+ ConfirmSensitiveEntryAccess_RemoteUNC_Allowed) {
+ EXPECT_EQ(ConfirmSensitiveEntryAccessSync(
+ permission_context(),
+ PathInfo(FILE_PATH_LITERAL("\\\\server\\share\\foo\\bar")),
+ HandleType::kDirectory, UserAction::kOpen),
+ SensitiveDirectoryResult::kAllowed);
+ EXPECT_EQ(ConfirmSensitiveEntryAccessSync(
+ permission_context(),
+ PathInfo(FILE_PATH_LITERAL("\\\\remote-nas\\projects\\my-app")),
+ HandleType::kDirectory, UserAction::kOpen),
+ SensitiveDirectoryResult::kAllowed);
+ EXPECT_EQ(ConfirmSensitiveEntryAccessSync(
+ permission_context(),
+ PathInfo(FILE_PATH_LITERAL("\\\\corp.domain.com\\dfs\\team")),
+ HandleType::kDirectory, UserAction::kOpen),
+ SensitiveDirectoryResult::kAllowed);
+}
+
// Testing that the */.git/hooks are all blocked.
TEST_F(ChromeFileSystemAccessPermissionContextTest,
ConfirmSensitiveEntryAccess_SuffixWriteBlock) {
Original Bug Report
FSA blocklist bypass via WSL UNC path allows code execution via shell dotfiles
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: On Windows, the File System Access API’s sensitive directory blocklist fails to detect and restrict access to the Windows Subsystem for Linux (WSL) UNC namespace (\\wsl.localhost\). Web applications can obtain directory handles over a user’s WSL Linux home directory without triggering blocklist protections. An attacker can potentially leverage write access to plant shell initialization dotfiles (e.g., .bashrc), leading to persistent code execution within WSL and escalation to the Windows host via default interop.
Affected files:
chrome/browser/file_system_access/chrome_file_system_access_permission_context.cc
Estimated timestamp from git blame: 2023-02-06
Summary
On Windows, ChromeFileSystemAccessPermissionContext::ShouldBlockAccessToPath enforces a sensitive-directory blocklist to prevent web applications from obtaining read/write access to sensitive operating system paths, even with user consent. However, the blocklist does not cover paths under the WSL redirector UNC namespace (\\wsl.localhost\), allowing web content to acquire directory grants for the Linux home directory and plant shell configuration files.
Root Cause
In chrome/browser/file_system_access/chrome_file_system_access_permission_context.cc, local UNC paths are checked exclusively through MaybeIsLocalUNCPath:
// chrome/browser/file_system_access/chrome_file_system_access_permission_context.cc:292-300
if (components.size() >= 2 &&
(base::FilePath::CompareEqualIgnoreCase(components[1],
FILE_PATH_LITERAL("localhost")) ||
components[1] == FILE_PATH_LITERAL("127.0.0.1") ||
components[1] == FILE_PATH_LITERAL(".") ||
components[1] == FILE_PATH_LITERAL("?") ||
ContainsInvalidDNSCharacter(components[1]))) {
return true;
}
For modern WSL paths (e.g., \\wsl.localhost\Ubuntu\home\user), components[1] is wsl.localhost. This does not match localhost or 127.0.0.1, and contains only valid DNS characters ([A-Za-z0-9.-_]), so MaybeIsLocalUNCPath returns false.
Once past this check, ShouldBlockAccessToPath tests the path against kBlockPaths. On Windows, all standard block rules (such as base::DIR_HOME, ~/.ssh, ~/.gnupg, base::DIR_WINDOWS, DIR_PROGRAM_FILES) resolve to drive-letter paths (e.g., C:\...). In base::FilePath::IsParent, a C:-rooted path never matches a \\-rooted UNC path, causing ShouldBlockAccessToPath to return false for any path under \\wsl.localhost\.
Furthermore, FileSystemAccessManagerImpl::IsSafePathComponent explicitly allows leading-dot filenames (such as .bashrc), and .bashrc is not classified as dangerous under download_file_types.asciipb or IsSafePathComponent’s dangerous extension rules.
Note: These findings are based on static code auditing; our tooling agent does not currently have the environment capabilities to execute a live proof-of-concept run.
Potential Reproduction Steps
- On a Windows machine with WSL installed, navigate to an HTTPS page that invokes
window.showDirectoryPicker({ mode: 'readwrite' }). - In the Windows folder picker dialog, select
\\wsl.localhost\<Distro>\home\<User>via the “Linux” navigation node. - Observe that Chrome does not display the restricted directory error and instead prompts the user to grant edit permissions.
- The webpage calls
dirHandle.getFileHandle('.bashrc', { create: true })and writes a shell command viacreateWritable(), e.g., appendingcmd.exe /c calc.exe. - The next time the user launches a WSL terminal session (such as through Windows Terminal or VS Code), Bash sources
.bashrcand executes the command on the host Windows system via WSL’s default interop.
Suggested Fix
- Update
MaybeIsLocalUNCPathinchrome_file_system_access_permission_context.ccto recognizewsl.localhost(as well as anywsl$aliases) as a local UNC path. - Alternatively, add explicit blocklist rules covering the WSL filesystem hierarchy (such as
\\wsl.localhost\<distro>\home\<user>,.ssh,/etc, and/root).
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.