Medium chrome Logic Error 🔧 Commit mapped

Overview

Medium
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactMissing authorization in FileSystem
DescriptionMissing authorization in FileSystem
ComponentFileSystem
Bug ClassLogic Error
Tracker502411391
Fix commit386998126bfe (chromium/src) +317/-350
CISA KEVNot listed
CreditedGoogle
Disclosed2026-09-01

Background

File System Access API
the web platform interface (showOpenFilePicker / showDirectoryPicker) that lets an origin prompt the user to grant read/write access to local files and directories.
`FileSystemAccessManagerImpl`
the browser-process class in content/browser/file_system_access/ that services File System Access mojo calls and drives the native chooser dialog.
`WebContents::GetVisibility()`
a browser-side query returning whether a tab is VISIBLE, OCCLUDED, or HIDDEN to the user.
`kOperationAborted`
the FileSystemAccessStatus value returned to the renderer when a request is refused before any picker is shown.

Root Cause Analysis

The vulnerable path is ShowFilePickerOnUIThread in FileSystemAccessManagerImpl, which gates the native file/directory chooser only on web_contents being non-null and outermost_rfh->IsActive() being true, but never checked whether the tab was actually visible to the user. Because a frame can remain “active” (its RenderFrameHost is a current, non-BFCache primary frame) while its WebContents is HIDDEN — for example a background tab or an occluded window — an origin could invoke showOpenFilePicker/showDirectoryPicker and surface the chooser while the user’s attention was on a different, foreground surface. This violates the invariant that a security-sensitive, user-consent prompt must originate from and be attributable to the visible page that requested it.

The fix adds a web_contents->GetVisibility() == Visibility::HIDDEN check (guarded by the kFileSystemAccessCheckHidden feature flag) to the same guard clause, so a hidden WebContents now short-circuits to kOperationAborted before the dialog is ever created. This works because visibility is evaluated in the browser process at the moment of the request, closing the window in which a non-foreground origin could raise the picker.

Key insight
The single mistake was treating frame “active” state as a sufficient proxy for “the user is looking at this page,” when an active frame can belong to a hidden tab; the fix adds an explicit visibility check so the consent-bearing chooser is only shown for a VISIBLE (non-hidden) WebContents.

Attack Path

  1. Prime a background origin A malicious or compromised origin runs in a tab or window that is not the foreground surface, e.g. a background tab, an occluded window, or a just-backgrounded page whose RenderFrameHost is still IsActive().
  2. Trigger the picker while hidden Script calls showOpenFilePicker or showDirectoryPicker, reaching ShowFilePickerOnUIThread even though WebContents::GetVisibility() is HIDDEN.
  3. Bypass the stale guard The pre-fix guard passes because web_contents is non-null and outermost_rfh->IsActive() is true, so the native chooser is created despite the tab being hidden.
  4. Exploit user misattribution The chooser appears without a clearly visible originating page, increasing the chance the user grants file or directory access to an origin they did not knowingly interact with.

Impact Assessment

An attacker gains the ability to raise a local file/directory access prompt from a non-visible page, undermining the user’s ability to attribute the consent request to a specific, foreground origin and increasing the likelihood of an unintended grant of read/write access to local files. This occurs in the browser process on behalf of a web origin using the File System Access API. Preconditions are that the origin can execute script in a live, still-IsActive() frame whose WebContents is HIDDEN, which requires the user to load attacker-controlled content but not to keep it in the foreground.

Changed Functions

FunctionChangeNotes
TestWebViewWebContentsDelegate
content/browser/file_system_access/file_system_access_manager_impl_unittest.cc
modified
if
content/browser/file_system_access/file_system_access_manager_impl_unittest.cc
modified

Files Changed

  • content/browser/file_system_access/features.cc
  • content/browser/file_system_access/features.h
  • content/browser/file_system_access/file_system_access_manager_impl.cc
  • content/browser/file_system_access/file_system_access_manager_impl_unittest.cc

Audit Directions

  • Visibility vs. activity conflation
    Audit other consent- or dialog-raising browser paths that gate on RenderFrameHost::IsActive() alone and add a WebContents::GetVisibility() check where a prompt must come from the foreground page.
  • Chooser and permission entry points
    Review every caller that reaches a native chooser, permission prompt, or SelectFileDialog from a renderer-initiated request to confirm the requesting surface is currently visible.
  • Feature-flag-gated security fixes
    Track kFileSystemAccessCheckHidden and similar flags to ensure the protective check cannot be disabled to reopen the bypass, and verify parity across platforms including Android/WebView delegates.
From 386998126bfe0cbabf2ea81be1fbd4cd1a34f2c8 Mon Sep 17 00:00:00 2001
From: Joel Hockey <joelhockey@chromium.org>
Date: Wed, 26 Aug 2026 05:48:27 -0700
Subject: [PATCH] Abort file picker if WebContents is hidden

In ShowFilePickerOnUIThread, verify that the WebContents is not hidden
(web_contents->GetVisibility() == Visibility::HIDDEN) before attempting
to show the file picker dialog. If hidden, the request is aborted with
FileSystemAccessStatus::kOperationAborted.

Adds ChooseEntries_HiddenWebContents unit test and additional tests for
WebView which uses a WebContentsDelegate.

Bug: 502411391
Change-Id: I9f103135a69ba132bca7de68d62a1a35e0234102
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8294258
Commit-Queue: Joel Hockey <joelhockey@chromium.org>
Reviewed-by: Fergal Daly <fergal@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1686307}
---

diff --git a/content/browser/file_system_access/features.cc b/content/browser/file_system_access/features.cc
index 1aab61d4..8cd0a59e 100644
--- a/content/browser/file_system_access/features.cc
+++ b/content/browser/file_system_access/features.cc
@@ -27,6 +27,9 @@
 BASE_FEATURE(kFileSystemAccessObserverQuotaLimit,
              base::FEATURE_ENABLED_BY_DEFAULT);
 
+// When enabled, check for hidden WebContents before showing chooser.
+BASE_FEATURE(kFileSystemAccessCheckHidden, base::FEATURE_ENABLED_BY_DEFAULT);
+
 // On Linux, the quota limit is found by:
 // 1. Rounding down the system limit (read from
 //    /proc/sys/fs/inotify/max_user_watches) to the nearest
diff --git a/content/browser/file_system_access/features.h b/content/browser/file_system_access/features.h
index 4bf18e59..aa3bf43 100644
--- a/content/browser/file_system_access/features.h
+++ b/content/browser/file_system_access/features.h
@@ -19,6 +19,7 @@
 CONTENT_EXPORT BASE_DECLARE_FEATURE(
     kFileSystemAccessDirectoryIterationBlocklistCheck);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kFileSystemAccessObserverQuotaLimit);
+CONTENT_EXPORT BASE_DECLARE_FEATURE(kFileSystemAccessCheckHidden);
 CONTENT_EXPORT BASE_DECLARE_FEATURE_PARAM(
     size_t,
     kFileSystemObserverQuotaLimitLinuxBucketSize);
diff --git a/content/browser/file_system_access/file_system_access_manager_impl.cc b/content/browser/file_system_access/file_system_access_manager_impl.cc
index 14e62d7..bd28d6a4 100644
--- a/content/browser/file_system_access/file_system_access_manager_impl.cc
+++ b/content/browser/file_system_access/file_system_access_manager_impl.cc
@@ -190,7 +190,10 @@
   WebContents* web_contents = WebContents::FromRenderFrameHost(rfh);
   RenderFrameHost* outermost_rfh = rfh ? rfh->GetOutermostMainFrame() : nullptr;
 
-  if (!web_contents || !outermost_rfh || !outermost_rfh->IsActive()) {
+  if (!web_contents ||
+      (base::FeatureList::IsEnabled(features::kFileSystemAccessCheckHidden) &&
+       web_contents->GetVisibility() == Visibility::HIDDEN) ||
+      !outermost_rfh || !outermost_rfh->IsActive()) {
     std::move(callback).Run(file_system_access_error::FromStatus(
                                 FileSystemAccessStatus::kOperationAborted),
                             {});
diff --git a/content/browser/file_system_access/file_system_access_manager_impl_unittest.cc b/content/browser/file_system_access/file_system_access_manager_impl_unittest.cc
index 78c13353..bbee1ae 100644
--- a/content/browser/file_system_access/file_system_access_manager_impl_unittest.cc
+++ b/content/browser/file_system_access/file_system_access_manager_impl_unittest.cc
@@ -37,6 +37,9 @@
 #include "content/browser/file_system_access/fixed_file_system_access_permission_grant.h"
 #include "content/browser/file_system_access/mock_file_system_access_permission_context.h"
 #include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/file_select_listener.h"
+#include "content/public/browser/visibility.h"
+#include "content/public/browser/web_contents_delegate.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/test_browser_context.h"
 #include "content/public/test/test_utils.h"
@@ -69,6 +72,10 @@
 #include "ui/shell_dialogs/select_file_dialog.h"
 #include "url/gurl.h"
 
+#if BUILDFLAG(IS_ANDROID)
+#include "third_party/blink/public/mojom/choosers/file_chooser.mojom.h"
+#endif
+
 namespace content {
 
 namespace {
@@ -155,6 +162,34 @@
   bool was_checked_ = false;
 };
 
+#if BUILDFLAG(IS_ANDROID)
+// A WebContentsDelegate that simulates WebView by overriding
+// `UseFileChooserForFileSystemAccess()` and handling `RunFileChooser()`.
+class TestWebViewWebContentsDelegate : public WebContentsDelegate {
+ public:
+  bool UseFileChooserForFileSystemAccess() const override { return true; }
+
+  void RunFileChooser(RenderFrameHost* render_frame_host,
+                      scoped_refptr<FileSelectListener> listener,
+                      const blink::mojom::FileChooserParams& params) override {
+    run_file_chooser_called_ = true;
+    listener->FileSelected(std::move(files_), base::FilePath(), params.mode);
+  }
+
+  void SetFileToSelect(base::FilePath file) {
+    files_.push_back(blink::mojom::FileChooserFileInfo::NewNativeFile(
+        blink::mojom::NativeFileInfo::New(file, std::u16string(),
+                                          std::vector<std::u16string>())));
+  }
+
+  bool run_file_chooser_called() const { return run_file_chooser_called_; }
+
+ private:
+  bool run_file_chooser_called_ = false;
+  std::vector<blink::mojom::FileChooserFileInfoPtr> files_;
+};
+#endif
+
 }  // namespace
 
 using base::test::RunOnceCallback;
@@ -261,11 +296,12 @@
       FileSystemAccessPermissionContext::SensitiveEntryResult result,
       FileSystemAccessPermissionContext::UserAction user_action =
           FileSystemAccessPermissionContext::UserAction::kOpen,
-      testing::ExpectationSet after_expectations = {}) {
+      testing::ExpectationSet after_expectations = {},
+      FileSystemAccessPermissionContext::HandleType handle_type =
+          FileSystemAccessPermissionContext::HandleType::kFile) {
     return EXPECT_CALL(permission_context_,
                        ConfirmSensitiveEntryAccess_(
-                           kTestStorageKey.origin(), path_info,
-                           FileSystemAccessPermissionContext::HandleType::kFile,
+                           kTestStorageKey.origin(), path_info, handle_type,
                            user_action,
                            web_contents_->GetPrimaryMainFrame()->GetGlobalId(),
                            testing::_))
@@ -276,25 +312,71 @@
   void ExpectGetReadPermissionGrant(
       const PathInfo& path_info,
       FileSystemAccessPermissionContext::UserAction user_action =
-          FileSystemAccessPermissionContext::UserAction::kOpen) {
-    EXPECT_CALL(
-        permission_context_,
-        GetReadPermissionGrant(
-            kTestStorageKey.origin(), path_info,
-            FileSystemAccessPermissionContext::HandleType::kFile, user_action))
+          FileSystemAccessPermissionContext::UserAction::kOpen,
+      FileSystemAccessPermissionContext::HandleType handle_type =
+          FileSystemAccessPermissionContext::HandleType::kFile) {
+    EXPECT_CALL(permission_context_,
+                GetReadPermissionGrant(kTestStorageKey.origin(), path_info,
+                                       handle_type, user_action))
         .WillOnce(testing::Return(allow_grant_));
   }
 
   void ExpectGetWritePermissionGrant(
       const PathInfo& path_info,
       FileSystemAccessPermissionContext::UserAction user_action =
-          FileSystemAccessPermissionContext::UserAction::kOpen) {
-    EXPECT_CALL(
-        permission_context_,
-        GetWritePermissionGrant(
-            kTestStorageKey.origin(), path_info,
-            FileSystemAccessPermissionContext::HandleType::kFile, user_action))
-        .WillOnce(testing::Return(allow_grant_));
+          FileSystemAccessPermissionContext::UserAction::kOpen,
+      FileSystemAccessPermissionContext::HandleType handle_type =
+          FileSystemAccessPermissionContext::HandleType::kFile,
+      scoped_refptr<FixedFileSystemAccessPermissionGrant> grant = nullptr) {
+    EXPECT_CALL(permission_context_,
+                GetWritePermissionGrant(kTestStorageKey.origin(), path_info,
+                                        handle_type, user_action))
+        .WillOnce(testing::Return(grant ? grant : allow_grant_));
+  }
+
+  void ExpectShowFilePicker(
+      bool read_permission = true,
+      bool write_permission = false,
+      std::optional<PathInfo> last_picked_directory_to_set = std::nullopt) {
+    if (read_permission) {
+      EXPECT_CALL(permission_context_,
+                  CanObtainReadPermission(kTestStorageKey.origin()))
+          .WillOnce(testing::Return(true));
+    }
+    if (write_permission) {
+      EXPECT_CALL(permission_context_,
+                  CanObtainWritePermission(kTestStorageKey.origin()))
+          .WillOnce(testing::Return(true));
+    }
+    EXPECT_CALL(permission_context_,
+                GetWellKnownDirectoryPath(
+                    blink::mojom::WellKnownDirectory::kDirDocuments,
+                    kTestStorageKey.origin()))
+        .WillOnce(testing::Return(base::FilePath()));
+    EXPECT_CALL(permission_context_,
+                GetLastPickedDirectory(kTestStorageKey.origin(), std::string()))
+        .WillOnce(testing::Return(PathInfo()));
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/content/browser/file_system_access/file_system_access_manager_impl_unittest.cc b/content/browser/file_system_access/file_system_access_manager_impl_unittest.cc
index 78c13353..bbee1ae 100644
--- a/content/browser/file_system_access/file_system_access_manager_impl_unittest.cc
+++ b/content/browser/file_system_access/file_system_access_manager_impl_unittest.cc
@@ -37,6 +37,9 @@
 #include "content/browser/file_system_access/fixed_file_system_access_permission_grant.h"
 #include "content/browser/file_system_access/mock_file_system_access_permission_context.h"
 #include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/file_select_listener.h"
+#include "content/public/browser/visibility.h"
+#include "content/public/browser/web_contents_delegate.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/test_browser_context.h"
 #include "content/public/test/test_utils.h"
@@ -69,6 +72,10 @@
 #include "ui/shell_dialogs/select_file_dialog.h"
 #include "url/gurl.h"
 
+#if BUILDFLAG(IS_ANDROID)
+#include "third_party/blink/public/mojom/choosers/file_chooser.mojom.h"
+#endif
+
 namespace content {
 
 namespace {
@@ -155,6 +162,34 @@
   bool was_checked_ = false;
 };
 
+#if BUILDFLAG(IS_ANDROID)
+// A WebContentsDelegate that simulates WebView by overriding
+// `UseFileChooserForFileSystemAccess()` and handling `RunFileChooser()`.
+class TestWebViewWebContentsDelegate : public WebContentsDelegate {
+ public:
+  bool UseFileChooserForFileSystemAccess() const override { return true; }
+
+  void RunFileChooser(RenderFrameHost* render_frame_host,
+                      scoped_refptr<FileSelectListener> listener,
+                      const blink::mojom::FileChooserParams& params) override {
+    run_file_chooser_called_ = true;
+    listener->FileSelected(std::move(files_), base::FilePath(), params.mode);
+  }
+
+  void SetFileToSelect(base::FilePath file) {
+    files_.push_back(blink::mojom::FileChooserFileInfo::NewNativeFile(
+        blink::mojom::NativeFileInfo::New(file, std::u16string(),
+                                          std::vector<std::u16string>())));
+  }
+
+  bool run_file_chooser_called() const { return run_file_chooser_called_; }
+
+ private:
+  bool run_file_chooser_called_ = false;
+  std::vector<blink::mojom::FileChooserFileInfoPtr> files_;
+};
+#endif
+
 }  // namespace
 
 using base::test::RunOnceCallback;
@@ -261,11 +296,12 @@
       FileSystemAccessPermissionContext::SensitiveEntryResult result,
       FileSystemAccessPermissionContext::UserAction user_action =
           FileSystemAccessPermissionContext::UserAction::kOpen,
-      testing::ExpectationSet after_expectations = {}) {
+      testing::ExpectationSet after_expectations = {},
+      FileSystemAccessPermissionContext::HandleType handle_type =
+          FileSystemAccessPermissionContext::HandleType::kFile) {
     return EXPECT_CALL(permission_context_,
                        ConfirmSensitiveEntryAccess_(
-                           kTestStorageKey.origin(), path_info,
-                           FileSystemAccessPermissionContext::HandleType::kFile,
+                           kTestStorageKey.origin(), path_info, handle_type,
                            user_action,
                            web_contents_->GetPrimaryMainFrame()->GetGlobalId(),
                            testing::_))
@@ -276,25 +312,71 @@
   void ExpectGetReadPermissionGrant(
       const PathInfo& path_info,
       FileSystemAccessPermissionContext::UserAction user_action =
-          FileSystemAccessPermissionContext::UserAction::kOpen) {
-    EXPECT_CALL(
-        permission_context_,
-        GetReadPermissionGrant(
-            kTestStorageKey.origin(), path_info,
-            FileSystemAccessPermissionContext::HandleType::kFile, user_action))
+          FileSystemAccessPermissionContext::UserAction::kOpen,
+      FileSystemAccessPermissionContext::HandleType handle_type =
+          FileSystemAccessPermissionContext::HandleType::kFile) {
+    EXPECT_CALL(permission_context_,
+                GetReadPermissionGrant(kTestStorageKey.origin(), path_info,
+                                       handle_type, user_action))
         .WillOnce(testing::Return(allow_grant_));
   }
 
   void ExpectGetWritePermissionGrant(
       const PathInfo& path_info,
       FileSystemAccessPermissionContext::UserAction user_action =
-          FileSystemAccessPermissionContext::UserAction::kOpen) {
-    EXPECT_CALL(
-        permission_context_,
-        GetWritePermissionGrant(
-            kTestStorageKey.origin(), path_info,
-            FileSystemAccessPermissionContext::HandleType::kFile, user_action))
-        .WillOnce(testing::Return(allow_grant_));
+          FileSystemAccessPermissionContext::UserAction::kOpen,
+      FileSystemAccessPermissionContext::HandleType handle_type =
+          FileSystemAccessPermissionContext::HandleType::kFile,
+      scoped_refptr<FixedFileSystemAccessPermissionGrant> grant = nullptr) {
+    EXPECT_CALL(permission_context_,
+                GetWritePermissionGrant(kTestStorageKey.origin(), path_info,
+                                        handle_type, user_action))
+        .WillOnce(testing::Return(grant ? grant : allow_grant_));
+  }
+
+  void ExpectShowFilePicker(
+      bool read_permission = true,
+      bool write_permission = false,
+      std::optional<PathInfo> last_picked_directory_to_set = std::nullopt) {
+    if (read_permission) {
+      EXPECT_CALL(permission_context_,
+                  CanObtainReadPermission(kTestStorageKey.origin()))
+          .WillOnce(testing::Return(true));
+    }
+    if (write_permission) {
+      EXPECT_CALL(permission_context_,
+                  CanObtainWritePermission(kTestStorageKey.origin()))
+          .WillOnce(testing::Return(true));
+    }
+    EXPECT_CALL(permission_context_,
+                GetWellKnownDirectoryPath(
+                    blink::mojom::WellKnownDirectory::kDirDocuments,
+                    kTestStorageKey.origin()))
+        .WillOnce(testing::Return(base::FilePath()));
+    EXPECT_CALL(permission_context_,
+                GetLastPickedDirectory(kTestStorageKey.origin(), std::string()))
+        .WillOnce(testing::Return(PathInfo()));
+    EXPECT_CALL(permission_context_, GetPickerTitle(testing::_))
+        .WillOnce(testing::Return(std::u16string()));
+    if (last_picked_directory_to_set) {
+      EXPECT_CALL(
+          permission_context_,
+          SetLastPickedDirectory(kTestStorageKey.origin(), std::string(),
+                                 *last_picked_directory_to_set));
+    }
+  }
+
+  void ExpectCheckPathsAgainstEnterprisePolicy(bool allowed = true) {
+    EXPECT_CALL(permission_context_, CheckPathsAgainstEnterprisePolicy(
+                                         testing::_, testing::_, testing::_))
+        .WillOnce(
+            [allowed](std::vector<PathInfo> entries,
+                      content::GlobalRenderFrameHostId frame_id,
+                      MockFileSystemAccessPermissionContext::
+                          EntriesAllowedByEnterprisePolicyCallback callback) {
+              std::move(callback).Run(allowed ? std::move(entries)
+                                              : std::vector<PathInfo>());
+            });
   }
 
   FileSystemAccessTransferTokenImpl* SerializeAndDeserializeToken(
@@ -1640,37 +1722,16 @@
   manager_->BindReceiver(binding_context,
                          manager_remote.BindNewPipeAndPassReceiver());
 
-  EXPECT_CALL(permission_context_,
-              CanObtainReadPermission(kTestStorageKey.origin()))
-      .WillOnce(testing::Return(true));
-
-  EXPECT_CALL(
-      permission_context_,
-      GetWellKnownDirectoryPath(blink::mojom::WellKnownDirectory::kDirDocuments,
-                                kTestStorageKey.origin()))
-      .WillOnce(testing::Return(base::FilePath()));
-  EXPECT_CALL(permission_context_,
-              GetLastPickedDirectory(kTestStorageKey.origin(), std::string()))
-      .WillOnce(testing::Return(PathInfo()));
-  EXPECT_CALL(permission_context_, GetPickerTitle(testing::_))
-      .WillOnce(testing::Return(std::u16string()));
-  EXPECT_CALL(permission_context_,
-              SetLastPickedDirectory(kTestStorageKey.origin(), std::string(),
-                                     PathInfo(test_file_info.path.DirName())));
+  ExpectShowFilePicker(
+      /*read_permission=*/true, /*write_permission=*/false,
+      PathInfo(test_file_info.path.DirName()));
 
   ExpectConfirmSensitiveEntryAccess(
       test_file_info,
       FileSystemAccessPermissionContext::SensitiveEntryResult::kAllowed);
   ExpectGetReadPermissionGrant(test_file_info);
   ExpectGetWritePermissionGrant(test_file_info);
-  EXPECT_CALL(permission_context_, CheckPathsAgainstEnterprisePolicy(
-                                       testing::_, testing::_, testing::_))
-      .WillOnce([](std::vector<PathInfo> entries,
-                   content::GlobalRenderFrameHostId frame_id,
-                   MockFileSystemAccessPermissionContext::
-                       EntriesAllowedByEnterprisePolicyCallback callback) {
-        std::move(callback).Run(std::move(entries));
-      });
+  ExpectCheckPathsAgainstEnterprisePolicy();
 
   auto open_file_picker_options = blink::mojom::OpenFilePickerOptions::New(
       blink::mojom::AcceptsTypesInfo::New(
@@ -1752,23 +1813,9 @@
   manager_->BindReceiver(binding_context,
                          manager_remote.BindNewPipeAndPassReceiver());
 
-  EXPECT_CALL(permission_context_,
-              CanObtainReadPermission(kTestStorageKey.origin()))
-      .WillOnce(testing::Return(true));
-
-  EXPECT_CALL(
-      permission_context_,
-      GetWellKnownDirectoryPath(blink::mojom::WellKnownDirectory::kDirDocuments,
-                                kTestStorageKey.origin()))
-      .WillOnce(testing::Return(base::FilePath()));
-  EXPECT_CALL(permission_context_,
-              GetLastPickedDirectory(kTestStorageKey.origin(), std::string()))
-      .WillOnce(testing::Return(PathInfo()));
-  EXPECT_CALL(permission_context_, GetPickerTitle(testing::_))
-      .WillOnce(testing::Return(std::u16string()));
-  EXPECT_CALL(permission_context_,
-              SetLastPickedDirectory(kTestStorageKey.origin(), std::string(),
-                                     PathInfo(test_file_info1.path.DirName())));
+  ExpectShowFilePicker(
+      /*read_permission=*/true, /*write_permission=*/false,
+      PathInfo(test_file_info1.path.DirName()));
 
   // ConfirmSensitiveEntryAccess should be called for BOTH files.
   testing::Expectation e1 = ExpectConfirmSensitiveEntryAccess(
@@ -1785,14 +1832,7 @@
   ExpectGetReadPermissionGrant(test_file_info2);
   ExpectGetWritePermissionGrant(test_file_info2);
 
-  EXPECT_CALL(permission_context_, CheckPathsAgainstEnterprisePolicy(
-                                       testing::_, testing::_, testing::_))
-      .WillOnce([](std::vector<PathInfo> entries,
-                   content::GlobalRenderFrameHostId frame_id,
-                   MockFileSystemAccessPermissionContext::
-                       EntriesAllowedByEnterprisePolicyCallback callback) {
-        std::move(callback).Run(std::move(entries));
-      });
+  ExpectCheckPathsAgainstEnterprisePolicy();
 
   auto open_file_picker_options = blink::mojom::OpenFilePickerOptions::New(
       blink::mojom::AcceptsTypesInfo::New(
@@ -1840,20 +1880,7 @@
   manager_->BindReceiver(binding_context,
                          manager_remote.BindNewPipeAndPassReceiver());
 
-  EXPECT_CALL(permission_context_,
-              CanObtainReadPermission(kTestStorageKey.origin()))
-      .WillOnce(testing::Return(true));
-
-  EXPECT_CALL(
-      permission_context_,
-      GetWellKnownDirectoryPath(blink::mojom::WellKnownDirectory::kDirDocuments,
-                                kTestStorageKey.origin()))
-      .WillOnce(testing::Return(base::FilePath()));
-  EXPECT_CALL(permission_context_,
-              GetLastPickedDirectory(kTestStorageKey.origin(), std::string()))
-      .WillOnce(testing::Return(PathInfo()));
-  EXPECT_CALL(permission_context_, GetPickerTitle(testing::_))
-      .WillOnce(testing::Return(std::u16string()));
+  ExpectShowFilePicker();
 
   // ConfirmSensitiveEntryAccess is called for BOTH. The first is allowed, the
   // second is aborted.
@@ -1912,20 +1939,7 @@
   manager_->BindReceiver(binding_context,
                          manager_remote.BindNewPipeAndPassReceiver());
 
-  EXPECT_CALL(permission_context_,
-              CanObtainReadPermission(kTestStorageKey.origin()))
-      .WillOnce(testing::Return(true));
-
-  EXPECT_CALL(
-      permission_context_,
-      GetWellKnownDirectoryPath(blink::mojom::WellKnownDirectory::kDirDocuments,
-                                kTestStorageKey.origin()))
-      .WillOnce(testing::Return(base::FilePath()));
-  EXPECT_CALL(permission_context_,
-              GetLastPickedDirectory(kTestStorageKey.origin(), std::string()))
-      .WillOnce(testing::Return(PathInfo()));
-  EXPECT_CALL(permission_context_, GetPickerTitle(testing::_))
-      .WillOnce(testing::Return(std::u16string()));
+  ExpectShowFilePicker();
 
   // ConfirmSensitiveEntryAccess is called for the first file and is aborted.
   // The second file should NOT be checked.
@@ -1985,20 +1999,7 @@
   manager_->BindReceiver(binding_context,
                          manager_remote.BindNewPipeAndPassReceiver());
 
-  EXPECT_CALL(permission_context_,
-              CanObtainReadPermission(kTestStorageKey.origin()))
-      .WillOnce(testing::Return(true));
-
-  EXPECT_CALL(
-      permission_context_,
... (truncated)
Loading diff…

Original Bug Report

The reporter's bug is still restricted on the tracker. Chrome de-restricts security bugs ~30–90 days after the fix ships; a later run will backfill it here.