Low chrome Logic Error 🔧 Commit mapped

Overview

Low
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactIncorrect security UI in File Input
DescriptionIncorrect security UI in File Input
ComponentFile Input
Bug ClassLogic Error
Tracker454484864
Fix commit9c6ca0273599 (chromium/src) +62/-0
CISA KEVNot listed
CreditedUmar Farooq
Disclosed2026-06-02

Changed Functions

FunctionChangeNotes
if
chrome/browser/file_select_helper.cc
modified
WebContents
chrome/browser/file_select_helper.h
modified
TabInterface
chrome/browser/file_select_helper.h
modified
DialogModel
chrome/browser/file_select_helper.h
modified
ASSERT_TRUE
chrome/browser/ui/views/file_system_access/file_system_access_browsertest.cc
modified
FileSystemAccessBrowserTestForWebUI
chrome/browser/ui/views/file_system_access/file_system_access_browsertest.cc
modified

Files Changed

  • chrome/browser/file_select_helper.cc
  • chrome/browser/file_select_helper.h
  • chrome/browser/ui/views/file_system_access/file_system_access_browsertest.cc
From 9c6ca0273599b9e2713247bb751a1891ad05adf4 Mon Sep 17 00:00:00 2001
From: Alison Gale <agale@chromium.org>
Date: Thu, 23 Apr 2026 16:45:57 -0700
Subject: [PATCH] [SxS] Cancel file picker if active tab changes

This handles the case where a tab gets deactivated while the file picker
is open. One example of this happening is in split view where the user
is mid drag and drop when the file picker is opened.

#top-chrome-bug-fixit

Bug: 454484864,474583539
Change-Id: I91e869ea26b0884c5beb358516c602ec8178d5c9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7154160
Commit-Queue: Alison Gale <agale@chromium.org>
Reviewed-by: Dana Fried <dfried@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1619839}
---

diff --git a/chrome/browser/file_select_helper.cc b/chrome/browser/file_select_helper.cc
index eb9e243..b8a24fda 100644
--- a/chrome/browser/file_select_helper.cc
+++ b/chrome/browser/file_select_helper.cc
@@ -30,6 +30,7 @@
 #include "chrome/grit/generated_resources.h"
 #include "components/enterprise/buildflags/buildflags.h"
 #include "components/enterprise/common/proto/connectors.pb.h"
+#include "components/tabs/public/tab_interface.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/file_select_listener.h"
@@ -557,6 +558,14 @@
   listener_ = std::move(listener);
   content::WebContentsObserver::Observe(web_contents_);
 
+  tabs::TabInterface* tab_interface =
+      tabs::TabInterface::MaybeGetFromContents(web_contents_);
+  if (tab_interface) {
+    tab_deactivated_subscription_ =
+        tab_interface->RegisterWillDeactivate(base::BindRepeating(
+            &FileSelectHelper::OnTabDeactivated, base::Unretained(this)));
+  }
+
 #if !BUILDFLAG(IS_ANDROID)
   if (PictureInPictureWindowManager::GetInstance()
           ->ShouldFileDialogBlockPictureInPicture(web_contents_)) {
@@ -676,6 +685,8 @@
   scoped_tuck_picture_in_picture_.reset();
 #endif  // !BUILDFLAG(IS_ANDROID)
 
+  tab_deactivated_subscription_ = {};
+
   // If there are temporary files, then this instance needs to stick around
   // until web_contents_ is destroyed, so that this instance can delete the
   // temporary files.
@@ -755,6 +766,10 @@
   CleanUp();
 }
 
+void FileSelectHelper::OnTabDeactivated(tabs::TabInterface* tab) {
+  RunFileChooserEnd();
+}
+
 // static
 bool FileSelectHelper::IsAcceptTypeValid(const std::string& accept_type) {
   // TODO(raymes): This only does some basic checks, extend to test more cases.
diff --git a/chrome/browser/file_select_helper.h b/chrome/browser/file_select_helper.h
index 58b1bfe9..37c575db 100644
--- a/chrome/browser/file_select_helper.h
+++ b/chrome/browser/file_select_helper.h
@@ -8,6 +8,7 @@
 #include <memory>
 #include <vector>
 
+#include "base/callback_list.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/ref_counted.h"
@@ -34,6 +35,10 @@
 class WebContents;
 }
 
+namespace tabs {
+class TabInterface;
+}
+
 namespace ui {
 class DialogModel;
 struct SelectedFileInfo;
@@ -143,6 +148,8 @@
   void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
   void WebContentsDestroyed() override;
 
+  void OnTabDeactivated(tabs::TabInterface* tab);
+
   void EnumerateDirectoryImpl(
       content::WebContents* tab,
       scoped_refptr<content::FileSelectListener> listener,
@@ -320,6 +327,8 @@
   // Set to false in unit tests since there is no WebContents.
   bool abort_on_missing_web_contents_in_tests_ = true;
 
+  base::CallbackListSubscription tab_deactivated_subscription_;
+
 #if !BUILDFLAG(IS_ANDROID)
   // When not null, this prevents picture-in-picture windows from opening.
   std::unique_ptr<ScopedDisallowPictureInPicture>
diff --git a/chrome/browser/ui/views/file_system_access/file_system_access_browsertest.cc b/chrome/browser/ui/views/file_system_access/file_system_access_browsertest.cc
index 98be5531..2594a266 100644
--- a/chrome/browser/ui/views/file_system_access/file_system_access_browsertest.cc
+++ b/chrome/browser/ui/views/file_system_access/file_system_access_browsertest.cc
@@ -26,6 +26,8 @@
 #include "chrome/browser/ui/actions/chrome_action_id.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_actions.h"
+#include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/tabs/split_tab_metrics.h"
 #include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/views/file_system_access/file_system_access_test_utils.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
@@ -1356,6 +1358,42 @@
   ASSERT_EQ("AbortError", content::EvalJs(first_tab, "window.p"));
 }
 
+// Test that creating a split view while the dialog is showing closes the
+// dialog. https://crbug.com/474583539 https://crbug.com/454484864
+IN_PROC_BROWSER_TEST_P(FileSystemAccessBrowserTest,
+                       ShowOpenFileThenHideDueToSplitView) {
+  ASSERT_TRUE(ui_test_utils::NavigateToURL(
+      browser(), embedded_test_server()->GetURL("/title1.html")));
+  content::WebContents* first_tab =
+      browser()->tab_strip_model()->GetActiveWebContents();
+
+  // Open the dialog and wait until it's created.
+  content::SelectFileDialogRecorder recorder;
+  ui::SelectFileDialog::SetFactory(
+      std::make_unique<content::ObservableSelectFileDialogFactory>(
+          recorder.GetWeakPtr()));
+  ASSERT_EQ(42,
+            content::EvalJs(
+                first_tab,
+                "window.p = self.showOpenFilePicker().catch(e => e.name); 42"));
+  ASSERT_TRUE(base::test::RunUntil([&recorder]() {
+    return recorder.state != content::SelectFileDialogRecorder::kNotCreated;
+  }));
+
+  // Create a split view.
+  const int active_index = browser()->tab_strip_model()->active_index();
+  chrome::NewSplitTab(browser(),
+                      split_tabs::SplitTabCreatedSource::kToolbarButton);
+  EXPECT_TRUE(content::WaitForLoadStop(
+      browser()->tab_strip_model()->GetWebContentsAt(active_index + 1)));
+
+  // The first tab should not be the active tab anymore.
+  ASSERT_NE(first_tab, browser()->tab_strip_model()->GetActiveWebContents());
+
+  // Check that the dialog was closed.
+  ASSERT_EQ("AbortError", content::EvalJs(first_tab, "window.p"));
+}
+
 class FileSystemAccessBrowserTestForWebUI
     : public InProcessBrowserTest,
       public ::testing::WithParamInterface<bool> {
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/chrome/browser/ui/views/file_system_access/file_system_access_browsertest.cc b/chrome/browser/ui/views/file_system_access/file_system_access_browsertest.cc
index 98be5531..2594a266 100644
--- a/chrome/browser/ui/views/file_system_access/file_system_access_browsertest.cc
+++ b/chrome/browser/ui/views/file_system_access/file_system_access_browsertest.cc
@@ -26,6 +26,8 @@
 #include "chrome/browser/ui/actions/chrome_action_id.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_actions.h"
+#include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/tabs/split_tab_metrics.h"
 #include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/views/file_system_access/file_system_access_test_utils.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
@@ -1356,6 +1358,42 @@
   ASSERT_EQ("AbortError", content::EvalJs(first_tab, "window.p"));
 }
 
+// Test that creating a split view while the dialog is showing closes the
+// dialog. https://crbug.com/474583539 https://crbug.com/454484864
+IN_PROC_BROWSER_TEST_P(FileSystemAccessBrowserTest,
+                       ShowOpenFileThenHideDueToSplitView) {
+  ASSERT_TRUE(ui_test_utils::NavigateToURL(
+      browser(), embedded_test_server()->GetURL("/title1.html")));
+  content::WebContents* first_tab =
+      browser()->tab_strip_model()->GetActiveWebContents();
+
+  // Open the dialog and wait until it's created.
+  content::SelectFileDialogRecorder recorder;
+  ui::SelectFileDialog::SetFactory(
+      std::make_unique<content::ObservableSelectFileDialogFactory>(
+          recorder.GetWeakPtr()));
+  ASSERT_EQ(42,
+            content::EvalJs(
+                first_tab,
+                "window.p = self.showOpenFilePicker().catch(e => e.name); 42"));
+  ASSERT_TRUE(base::test::RunUntil([&recorder]() {
+    return recorder.state != content::SelectFileDialogRecorder::kNotCreated;
+  }));
+
+  // Create a split view.
+  const int active_index = browser()->tab_strip_model()->active_index();
+  chrome::NewSplitTab(browser(),
+                      split_tabs::SplitTabCreatedSource::kToolbarButton);
+  EXPECT_TRUE(content::WaitForLoadStop(
+      browser()->tab_strip_model()->GetWebContentsAt(active_index + 1)));
+
+  // The first tab should not be the active tab anymore.
+  ASSERT_NE(first_tab, browser()->tab_strip_model()->GetActiveWebContents());
+
+  // Check that the dialog was closed.
+  ASSERT_EQ("AbortError", content::EvalJs(first_tab, "window.p"));
+}
+
 class FileSystemAccessBrowserTestForWebUI
     : public InProcessBrowserTest,
       public ::testing::WithParamInterface<bool> {
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.