CVE-2026-79206
Overview
Background
- File System Access API
- a web platform API that, after a user picks a file or directory, grants the page read/write handles to that location on disk.
- Blocklist in `ChromeFileSystemAccessPermissionContext`
- a static table of sensitive paths (
BlockPathentries) that the permission context refuses to expose, soIsOpenAbort-style checks deny handles to those paths, their parents, and their children. - `base::DIR_CACHE`
- the platform path key for the user cache directory (
~/.cacheon Linux/ChromeOS), which can hold app state whose contents or presence are security- or privacy-sensitive. - `BlockType::kBlockAllChildren`
- a block mode that denies the directory itself, its parent, and everything beneath it.
Root Cause Analysis
The File System Access blocklist added base::DIR_CACHE (via BlockPath::CreateRelative) only inside the BUILDFLAG(IS_ANDROID) section, so on Linux and ChromeOS ~/.cache was not on the blocklist and web content that obtained a directory handle covering it could read (and write) user cache contents. The invariant that platform cache directories are off-limits to arbitrary web content held on Android, macOS, and Windows but not on Linux/ChromeOS, leaving a gap in the sensitive-path policy.
The fix moves the DIR_CACHE BlockPath::CreateRelative(..., BlockType::kBlockAllChildren) entry out of the Android-only block and into the shared Linux/ChromeOS/Android section (the non-IS_ANDROID #endif-guarded region alongside the ~/.dbus block), so ~/.cache and everything under it are now denied on those platforms too. The accompanying unit test change generalizes the cache-directory assertion from Android-only to IS_LINUX || IS_CHROMEOS || IS_ANDROID, confirming IsOpenAbort now aborts opens of the cache dir, its parent, and paths inside it. Note the patch is purely a blocklist scope change; the diff itself does not contain any out-of-bounds memory operation.
~/.cache (base::DIR_CACHE) blocklist entry to Android only, leaving Linux/ChromeOS unprotected; the fix relocates that entry into the shared platform section so cache access is blocked there as well.Attack Path
- Lure a directory grant
A malicious or misleading page uses the File System Access API to prompt the user to select a directory that resolves to or contains
~/.cacheon Linux/ChromeOS. - Escape the blocklist gap
Because
base::DIR_CACHEwas only blocked underBUILDFLAG(IS_ANDROID), the permission context did not abort the open on Linux/ChromeOS, so the handle to the cache directory is granted. - Read cache contents
With the granted handle the page enumerates and reads files under
~/.cache, exposing cached application data whose contents or mere presence are sensitive. (inferred — the diff shows only the blocklist gap, not the specific data read) - Persist or tamper
Because the entry is
kBlockAllChildrencovering write access too, an unblocked handle could also let the page write into cache subdirectories. (inferred)
Impact Assessment
~/.cache directory on Linux/ChromeOS via the File System Access API, disclosing sensitive cached data. The precondition is that the user grants a directory handle covering the cache path; the API’s own picker/permission UI is the gate. The advisory labels this an out-of-bounds read in FileSystem, but the patch demonstrates only a missing sensitive-path blocklist entry; any characterization beyond a blocklist-scope gap is per the advisory, not shown by the diff, and no exploited-in-the-wild status is stated.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
Audit Directions
- Per-platform blocklist scopingAudit sensitive-path blocklists for entries fenced behind a single
BUILDFLAGthat should apply on more platforms, especially where the underlying path key (e.g.base::DIR_CACHE, config/state dirs) exists across OSes. - Cross-platform parity of sensitive dirsCompare the File System Access blocklist across mac/win/linux/chromeos/android and reconcile which
base::DIR_*keys are protected on each. - Directory-handle exposure of app stateLook for other user-writable directories (config, temp, profile subdirs) reachable via directory handles that reveal or let web content mutate application state.
Patch
From f57f211284300f47f7834a902d89e8ff493424e3 Mon Sep 17 00:00:00 2001
From: Etienne Bergeron <etienneb@google.com>
Date: Wed, 22 Jul 2026 07:47:33 -0700
Subject: [PATCH] Block base::DIR_CACHE in File System Access API on Linux/ChromeOS
Add base::DIR_CACHE (~/.cache) to the File System Access blocklist
on Linux and ChromeOS platforms in addition to Android, preventing web
content from gaining write access to user cache directories.
Also add unit tests in fontconfig_util_unittest and
chrome_file_system_access_permission_context_unittest.
Bug: 513361380
Change-Id: I085954d4cc09a126e916e2fe0053fe5c1f0fd1aa
Fixed: 513361380
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8126779
Commit-Queue: Etienne Bergeron <etienneb@chromium.org>
Reviewed-by: Antonio Sartori <antoniosartori@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1666284}
---
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 aa7ec45..d16db9f9 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
@@ -478,11 +478,13 @@
// a website can do with access to that directory and its contents.
BlockPath::CreateRelative(base::DIR_HOME, FILE_PATH_LITERAL(".dbus"),
BlockType::kBlockAllChildren),
+ // And block all of ~/.cache, matching the similar restrictions on mac
+ // and windows.
+ BlockPath::CreateRelative(base::DIR_CACHE, BlockType::kBlockAllChildren),
#endif
#if BUILDFLAG(IS_ANDROID)
BlockPath::CreateRelative(base::DIR_ANDROID_APP_DATA,
BlockType::kBlockAllChildren),
- BlockPath::CreateRelative(base::DIR_CACHE, BlockType::kBlockAllChildren),
#endif
// TODO(crbug.com/40095723): Refine this list, for example add
// XDG_CONFIG_HOME when it is not set ~/.config?
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 93dd451..50d7a6d9 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
@@ -684,20 +684,22 @@
EXPECT_TRUE(IsOpenAbort(app_data_dir.AppendASCII("foo"), HandleType::kFile));
EXPECT_TRUE(
IsOpenAbort(app_data_dir.AppendASCII("foo"), HandleType::kDirectory));
+#endif // BUILDFLAG(IS_ANDROID)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
base::FilePath cache_dir = temp_dir_.GetPath().AppendASCII("cache");
base::ScopedPathOverride cache_override(base::DIR_CACHE, cache_dir, true,
true);
ResetBlockPath();
- // The android cache directory, its parent and paths inside should not be
+ // The cache directory, its parent and paths inside should not be
// allowed.
EXPECT_TRUE(IsOpenAbort(cache_dir, HandleType::kDirectory));
EXPECT_TRUE(IsOpenAbort(temp_dir_.GetPath(), HandleType::kDirectory));
EXPECT_TRUE(IsOpenAbort(cache_dir.AppendASCII("foo"), HandleType::kFile));
EXPECT_TRUE(
IsOpenAbort(cache_dir.AppendASCII("foo"), HandleType::kDirectory));
-
-#endif // BUILDFLAG(IS_ANDROID)
+#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) ||
+ // BUILDFLAG(IS_ANDROID)
}
// TODO(crbug.com/432011571): Flaky test.
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 93dd451..50d7a6d9 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
@@ -684,20 +684,22 @@
EXPECT_TRUE(IsOpenAbort(app_data_dir.AppendASCII("foo"), HandleType::kFile));
EXPECT_TRUE(
IsOpenAbort(app_data_dir.AppendASCII("foo"), HandleType::kDirectory));
+#endif // BUILDFLAG(IS_ANDROID)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
base::FilePath cache_dir = temp_dir_.GetPath().AppendASCII("cache");
base::ScopedPathOverride cache_override(base::DIR_CACHE, cache_dir, true,
true);
ResetBlockPath();
- // The android cache directory, its parent and paths inside should not be
+ // The cache directory, its parent and paths inside should not be
// allowed.
EXPECT_TRUE(IsOpenAbort(cache_dir, HandleType::kDirectory));
EXPECT_TRUE(IsOpenAbort(temp_dir_.GetPath(), HandleType::kDirectory));
EXPECT_TRUE(IsOpenAbort(cache_dir.AppendASCII("foo"), HandleType::kFile));
EXPECT_TRUE(
IsOpenAbort(cache_dir.AppendASCII("foo"), HandleType::kDirectory));
-
-#endif // BUILDFLAG(IS_ANDROID)
+#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) ||
+ // BUILDFLAG(IS_ANDROID)
}
// TODO(crbug.com/432011571): Flaky test.