High chrome Authorization Error 📄 Reporter bug report 🔧 Commit mapped

Overview

High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactIncorrect authorization in FileSystem
DescriptionIncorrect authorization in FileSystem
ComponentFileSystem
Sub-componentFSA
Bug ClassAuthorization Error
Tracker553114097
Fix commitbc5a321c6196 (chromium/src) +181/-0
CISA KEVNot listed
CreditedGoogle
Disclosed2026-10-01

Files Changed

  • chrome/browser/file_system_access/chrome_file_system_access_permission_context_unittest.cc
  • chrome/browser/file_system_access/chrome_file_system_access_permission_context.cc
From bc5a321c6196db0a2de36f1fe3e4fab977b10007 Mon Sep 17 00:00:00 2001
From: Ming-Ying Chung <mych@chromium.org>
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 <fergal@chromium.org>
Reviewed-by: Rahul Singh <rahsin@microsoft.com>
Commit-Queue: Ming-Ying Chung <mych@chromium.org>
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) {
Loading diff…

Regression Test / PoC

shipped with the fix
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) {
Loading diff…

Original Bug Report

reported by vm...@google.com

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

  1. On a Windows machine with WSL installed, navigate to an HTTPS page that invokes window.showDirectoryPicker({ mode: 'readwrite' }).
  2. In the Windows folder picker dialog, select \\wsl.localhost\<Distro>\home\<User> via the “Linux” navigation node.
  3. Observe that Chrome does not display the restricted directory error and instead prompts the user to grant edit permissions.
  4. The webpage calls dirHandle.getFileHandle('.bashrc', { create: true }) and writes a shell command via createWritable(), e.g., appending cmd.exe /c calc.exe.
  5. The next time the user launches a WSL terminal session (such as through Windows Terminal or VS Code), Bash sources .bashrc and executes the command on the host Windows system via WSL’s default interop.

Suggested Fix

  1. Update MaybeIsLocalUNCPath in chrome_file_system_access_permission_context.cc to recognize wsl.localhost (as well as any wsl$ aliases) as a local UNC path.
  2. 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.

View on issue tracker