Medium chrome Logic Error 📄 Reporter bug report 🔧 Commit mapped

Overview

Medium
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactMissing authorization in FileSystem
DescriptionMissing authorization in FileSystem
ComponentFileSystem
Bug ClassLogic Error
Tracker501627201
Fix commitba62faa8f0a6 (chromium/src) +133/-8
CISA KEVNot listed
CreditedGoogle
Disclosed2026-09-08

Changed Functions

FunctionChangeNotes
LocalFileSyncContextTest
chrome/browser/sync_file_system/local/local_file_sync_context_unittest.cc
modified
TEST_F
chrome/browser/sync_file_system/local/local_file_sync_service_unittest.cc
modified
if
chrome/browser/sync_file_system/local/sync_file_system_backend.cc
modified
SyncFileSystemBackendTest
chrome/browser/sync_file_system/local/sync_file_system_backend_unittest.cc
modified

Files Changed

  • chrome/browser/sync_file_system/BUILD.gn
  • chrome/browser/sync_file_system/local/local_file_change_tracker_unittest.cc
  • chrome/browser/sync_file_system/local/local_file_sync_context_unittest.cc
  • chrome/browser/sync_file_system/local/local_file_sync_service_unittest.cc
  • chrome/browser/sync_file_system/local/sync_file_system_backend.cc
  • chrome/browser/sync_file_system/local/sync_file_system_backend_unittest.cc
From ba62faa8f0a610f059e0da197180d7dc36066a72 Mon Sep 17 00:00:00 2001
From: Eriko Kurimoto <[email protected]>
Date: Wed, 29 Jul 2026 22:34:39 -0700
Subject: [PATCH] SyncFileSystemBackend: restrict to extension origins

SyncFileSystemBackend registers the process-global "syncfs" external
mount and is added to every FileSystemContext, so any origin could
resolve filesystem:.../external/syncfs/... URLs and perform operations
against it. The only legitimate consumer of this backend is the
chrome.syncFileSystem extension API, which always acts on a
chrome-extension:// origin.

Reject non-extension origins in ResolveURL() and
CreateFileSystemOperation() with FILE_ERROR_SECURITY before any backend
state is touched. Existing CannedSyncableFileSystem-based unit tests are
switched to chrome-extension:// origins to match, and
SyncFileSystemBackendTest is added to cover both the allowed and
rejected origin cases.

Bug: 501627201
Change-Id: Ie25cd6c2477e5129c8a06cb72e912bb716851a61
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8029801
Commit-Queue: Eriko Kurimoto <[email protected]>
Reviewed-by: Ming-Ying Chung <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1670836}
---

diff --git a/chrome/browser/sync_file_system/BUILD.gn b/chrome/browser/sync_file_system/BUILD.gn
index 23e6934..12932c05 100644
--- a/chrome/browser/sync_file_system/BUILD.gn
+++ b/chrome/browser/sync_file_system/BUILD.gn
@@ -220,6 +220,7 @@
     "local/local_file_sync_status_unittest.cc",
     "local/mock_sync_status_observer.cc",
     "local/mock_sync_status_observer.h",
+    "local/sync_file_system_backend_unittest.cc",
     "local/syncable_file_operation_runner_unittest.cc",
     "local/syncable_file_system_unittest.cc",
     "logger_unittest.cc",
diff --git a/chrome/browser/sync_file_system/local/local_file_change_tracker_unittest.cc b/chrome/browser/sync_file_system/local/local_file_change_tracker_unittest.cc
index f5f6f4e3..024508d3 100644
--- a/chrome/browser/sync_file_system/local/local_file_change_tracker_unittest.cc
+++ b/chrome/browser/sync_file_system/local/local_file_change_tracker_unittest.cc
@@ -40,7 +40,7 @@
   LocalFileChangeTrackerTest()
       : task_environment_(content::BrowserTaskEnvironment::IO_MAINLOOP),
         in_memory_env_(leveldb_chrome::NewMemEnv("LocalFileChangeTrackerTest")),
-        file_system_(GURL("http://example.com"),
+        file_system_(GURL("chrome-extension://example"),
                      in_memory_env_.get(),
                      base::SingleThreadTaskRunner::GetCurrentDefault().get(),
                      base::SingleThreadTaskRunner::GetCurrentDefault().get()) {}
diff --git a/chrome/browser/sync_file_system/local/local_file_sync_context_unittest.cc b/chrome/browser/sync_file_system/local/local_file_sync_context_unittest.cc
index c1388928..2335e601 100644
--- a/chrome/browser/sync_file_system/local/local_file_sync_context_unittest.cc
+++ b/chrome/browser/sync_file_system/local/local_file_sync_context_unittest.cc
@@ -57,8 +57,8 @@
 namespace sync_file_system {
 
 namespace {
-const char kOrigin1[] = "http://example.com";
-const char kOrigin2[] = "http://chromium.org";
+const char kOrigin1[] = "chrome-extension://example";
+const char kOrigin2[] = "chrome-extension://anotherexample";
 }  // namespace
 
 class LocalFileSyncContextTest : public testing::Test {
diff --git a/chrome/browser/sync_file_system/local/local_file_sync_service_unittest.cc b/chrome/browser/sync_file_system/local/local_file_sync_service_unittest.cc
index f0275949..7fdf68c 100644
--- a/chrome/browser/sync_file_system/local/local_file_sync_service_unittest.cc
+++ b/chrome/browser/sync_file_system/local/local_file_sync_service_unittest.cc
@@ -54,7 +54,7 @@
 
 namespace {
 
-const char kOrigin[] = "http://example.com";
+const char kOrigin[] = "chrome-extension://example";
 
 void DidPrepareForProcessRemoteChange(const base::Location& where,
                                       base::OnceClosure oncompleted,
@@ -314,7 +314,7 @@
 #endif
 
 TEST_F(LocalFileSyncServiceTest, MAYBE_LocalChangeObserverMultipleContexts) {
-  const char kOrigin2[] = "http://foo";
+  const char kOrigin2[] = "chrome-extension://foo";
   CannedSyncableFileSystem file_system2(
       GURL(kOrigin2), in_memory_env_.get(), content::GetIOThreadTaskRunner({}),
       base::ThreadPool::CreateSingleThreadTaskRunner({base::MayBlock()}));
diff --git a/chrome/browser/sync_file_system/local/sync_file_system_backend.cc b/chrome/browser/sync_file_system/local/sync_file_system_backend.cc
index 170e03f..8a4d9c1 100644
--- a/chrome/browser/sync_file_system/local/sync_file_system_backend.cc
+++ b/chrome/browser/sync_file_system/local/sync_file_system_backend.cc
@@ -21,11 +21,13 @@
 #include "chrome/browser/sync_file_system/syncable_file_system_util.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
+#include "extensions/common/constants.h"
 #include "storage/browser/file_system/file_stream_reader.h"
 #include "storage/browser/file_system/file_stream_writer.h"
 #include "storage/browser/file_system/file_system_context.h"
 #include "storage/browser/file_system/file_system_operation.h"
 #include "storage/common/file_system/file_system_util.h"
+#include "url/origin.h"
 
 using content::BrowserThread;
 
@@ -33,6 +35,12 @@
 
 namespace {
 
+// The syncable filesystem is only exposed via the chrome.syncFileSystem
+// extension API, so only extension-scheme origins are permitted to use it.
+bool IsSyncFSAllowedOrigin(const url::Origin& origin) {
+  return origin.scheme() == extensions::kExtensionScheme;
+}
+
 bool CalledOnUIThread() {
   // Ensure that these methods are called on the UI thread, except for unittests
   // where a UI thread might not have been created.
@@ -86,6 +94,12 @@
                                        ResolveURLCallback callback) {
   DCHECK(CanHandleType(url.type()));
 
+  if (!IsSyncFSAllowedOrigin(url.origin())) {
+    std::move(callback).Run(GURL(), std::string(),
+                            base::File::FILE_ERROR_SECURITY);
+    return;
+  }
+
   if (skip_initialize_syncfs_service_for_testing_) {
     GetDelegate()->OpenFileSystem(
         url.GetBucket(), url.type(), mode, std::move(callback),
@@ -131,6 +145,11 @@
   DCHECK(context);
   DCHECK(error_code);
 
+  if (!IsSyncFSAllowedOrigin(url.origin())) {
+    *error_code = base::File::FILE_ERROR_SECURITY;
+    return nullptr;
+  }
+
   std::unique_ptr<storage::FileSystemOperationContext> operation_context =
       GetDelegate()->CreateFileSystemOperationContext(url, context, error_code);
   if (!operation_context)
diff --git a/chrome/browser/sync_file_system/local/sync_file_system_backend_unittest.cc b/chrome/browser/sync_file_system/local/sync_file_system_backend_unittest.cc
new file mode 100644
index 0000000..44a867cc
--- /dev/null
+++ b/chrome/browser/sync_file_system/local/sync_file_system_backend_unittest.cc
@@ -0,0 +1,105 @@
+// Copyright 2026 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/sync_file_system/local/sync_file_system_backend.h"
+
+#include <memory>
+
+#include "base/files/file.h"
+#include "base/task/single_thread_task_runner.h"
+#include "chrome/browser/sync_file_system/local/canned_syncable_file_system.h"
+#include "chrome/browser/sync_file_system/syncable_file_system_util.h"
+#include "content/public/test/browser_task_environment.h"
+#include "storage/browser/file_system/file_system_context.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/leveldatabase/leveldb_chrome.h"
+#include "url/gurl.h"
+
+namespace sync_file_system {
+
+class SyncFileSystemBackendTest : public testing::Test {
+ public:
+  SyncFileSystemBackendTest()
+      : in_memory_env_(leveldb_chrome::NewMemEnv("SyncFileSystemBackendTest")) {
+  }
+
+  SyncFileSystemBackendTest(const SyncFileSystemBackendTest&) = delete;
+  SyncFileSystemBackendTest& operator=(const SyncFileSystemBackendTest&) =
+      delete;
+
+ protected:
+  std::unique_ptr<CannedSyncableFileSystem> CreateFileSystem(
+      const GURL& origin) {
+    auto file_system = std::make_unique<CannedSyncableFileSystem>(
+        origin, in_memory_env_.get(),
+        base::SingleThreadTaskRunner::GetCurrentDefault().get(),
+        base::SingleThreadTaskRunner::GetCurrentDefault().get());
+    file_system->SetUp();
+    return file_system;
+  }
+
+  base::File::Error OpenFileSystemForOrigin(const GURL& origin) {
+    auto file_system = CreateFileSystem(origin);
+    base::File::Error result = file_system->OpenFileSystem();
+    file_system->TearDown();
+    return result;
+  }
+
+  base::File::Error CreateFileSystemOperationForOrigin(const GURL& origin) {
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/chrome/browser/sync_file_system/local/local_file_change_tracker_unittest.cc b/chrome/browser/sync_file_system/local/local_file_change_tracker_unittest.cc
index f5f6f4e3..024508d3 100644
--- a/chrome/browser/sync_file_system/local/local_file_change_tracker_unittest.cc
+++ b/chrome/browser/sync_file_system/local/local_file_change_tracker_unittest.cc
@@ -40,7 +40,7 @@
   LocalFileChangeTrackerTest()
       : task_environment_(content::BrowserTaskEnvironment::IO_MAINLOOP),
         in_memory_env_(leveldb_chrome::NewMemEnv("LocalFileChangeTrackerTest")),
-        file_system_(GURL("http://example.com"),
+        file_system_(GURL("chrome-extension://example"),
                      in_memory_env_.get(),
                      base::SingleThreadTaskRunner::GetCurrentDefault().get(),
                      base::SingleThreadTaskRunner::GetCurrentDefault().get()) {}
diff --git a/chrome/browser/sync_file_system/local/local_file_sync_context_unittest.cc b/chrome/browser/sync_file_system/local/local_file_sync_context_unittest.cc
index c1388928..2335e601 100644
--- a/chrome/browser/sync_file_system/local/local_file_sync_context_unittest.cc
+++ b/chrome/browser/sync_file_system/local/local_file_sync_context_unittest.cc
@@ -57,8 +57,8 @@
 namespace sync_file_system {
 
 namespace {
-const char kOrigin1[] = "http://example.com";
-const char kOrigin2[] = "http://chromium.org";
+const char kOrigin1[] = "chrome-extension://example";
+const char kOrigin2[] = "chrome-extension://anotherexample";
 }  // namespace
 
 class LocalFileSyncContextTest : public testing::Test {
diff --git a/chrome/browser/sync_file_system/local/local_file_sync_service_unittest.cc b/chrome/browser/sync_file_system/local/local_file_sync_service_unittest.cc
index f0275949..7fdf68c 100644
--- a/chrome/browser/sync_file_system/local/local_file_sync_service_unittest.cc
+++ b/chrome/browser/sync_file_system/local/local_file_sync_service_unittest.cc
@@ -54,7 +54,7 @@
 
 namespace {
 
-const char kOrigin[] = "http://example.com";
+const char kOrigin[] = "chrome-extension://example";
 
 void DidPrepareForProcessRemoteChange(const base::Location& where,
                                       base::OnceClosure oncompleted,
@@ -314,7 +314,7 @@
 #endif
 
 TEST_F(LocalFileSyncServiceTest, MAYBE_LocalChangeObserverMultipleContexts) {
-  const char kOrigin2[] = "http://foo";
+  const char kOrigin2[] = "chrome-extension://foo";
   CannedSyncableFileSystem file_system2(
       GURL(kOrigin2), in_memory_env_.get(), content::GetIOThreadTaskRunner({}),
       base::ThreadPool::CreateSingleThreadTaskRunner({base::MayBlock()}));
diff --git a/chrome/browser/sync_file_system/local/sync_file_system_backend_unittest.cc b/chrome/browser/sync_file_system/local/sync_file_system_backend_unittest.cc
new file mode 100644
index 0000000..44a867cc
--- /dev/null
+++ b/chrome/browser/sync_file_system/local/sync_file_system_backend_unittest.cc
@@ -0,0 +1,105 @@
+// Copyright 2026 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/sync_file_system/local/sync_file_system_backend.h"
+
+#include <memory>
+
+#include "base/files/file.h"
+#include "base/task/single_thread_task_runner.h"
+#include "chrome/browser/sync_file_system/local/canned_syncable_file_system.h"
+#include "chrome/browser/sync_file_system/syncable_file_system_util.h"
+#include "content/public/test/browser_task_environment.h"
+#include "storage/browser/file_system/file_system_context.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/leveldatabase/leveldb_chrome.h"
+#include "url/gurl.h"
+
+namespace sync_file_system {
+
+class SyncFileSystemBackendTest : public testing::Test {
+ public:
+  SyncFileSystemBackendTest()
+      : in_memory_env_(leveldb_chrome::NewMemEnv("SyncFileSystemBackendTest")) {
+  }
+
+  SyncFileSystemBackendTest(const SyncFileSystemBackendTest&) = delete;
+  SyncFileSystemBackendTest& operator=(const SyncFileSystemBackendTest&) =
+      delete;
+
+ protected:
+  std::unique_ptr<CannedSyncableFileSystem> CreateFileSystem(
+      const GURL& origin) {
+    auto file_system = std::make_unique<CannedSyncableFileSystem>(
+        origin, in_memory_env_.get(),
+        base::SingleThreadTaskRunner::GetCurrentDefault().get(),
+        base::SingleThreadTaskRunner::GetCurrentDefault().get());
+    file_system->SetUp();
+    return file_system;
+  }
+
+  base::File::Error OpenFileSystemForOrigin(const GURL& origin) {
+    auto file_system = CreateFileSystem(origin);
+    base::File::Error result = file_system->OpenFileSystem();
+    file_system->TearDown();
+    return result;
+  }
+
+  base::File::Error CreateFileSystemOperationForOrigin(const GURL& origin) {
+    auto file_system = CreateFileSystem(origin);
+    base::File::Error result = base::File::FILE_OK;
+    file_system->backend()->CreateFileSystemOperation(
+        storage::OperationType::kCreateFile,
+        CreateSyncableFileSystemURL(origin, base::FilePath()),
+        file_system->file_system_context(), &result);
+    file_system->TearDown();
+    return result;
+  }
+
+  void TearDown() override { RevokeSyncableFileSystem(); }
+
+  content::BrowserTaskEnvironment task_environment_;
+  std::unique_ptr<leveldb::Env> in_memory_env_;
+};
+
+struct SchemeTestParam {
+  const char* scheme_name;
+  const char* url_string;
+  base::File::Error expected_error;
+};
+
+class SyncFileSystemBackendSchemeTest
+    : public SyncFileSystemBackendTest,
+      public ::testing::WithParamInterface<SchemeTestParam> {};
+
+TEST_P(SyncFileSystemBackendSchemeTest, OpenFileSystem) {
+  const SchemeTestParam& param = GetParam();
+  EXPECT_EQ(param.expected_error,
+            OpenFileSystemForOrigin(GURL(param.url_string)));
+}
+
+TEST_P(SyncFileSystemBackendSchemeTest, CreateFileSystemOperation) {
+  const SchemeTestParam& param = GetParam();
+  EXPECT_EQ(param.expected_error,
+            CreateFileSystemOperationForOrigin(GURL(param.url_string)));
+}
+
+const SchemeTestParam kSchemeTestParams[] = {
+    {"chrome_extension", "chrome-extension://example/", base::File::FILE_OK},
+    {"http", "http://example.com/", base::File::FILE_ERROR_SECURITY},
+    {"https", "https://example.com/", base::File::FILE_ERROR_SECURITY},
+    {"file", "file:///foo/bar", base::File::FILE_ERROR_SECURITY},
+    {"chrome", "chrome://settings/", base::File::FILE_ERROR_SECURITY},
+    {"ftp", "ftp://example.com/", base::File::FILE_ERROR_SECURITY},
+};
+
+INSTANTIATE_TEST_SUITE_P(
+    SyncFileSystemBackend,
+    SyncFileSystemBackendSchemeTest,
+    ::testing::ValuesIn(kSchemeTestParams),
+    [](const ::testing::TestParamInfo<SchemeTestParam>& info) {
+      return info.param.scheme_name;
+    });
+
+}  // namespace sync_file_system
diff --git a/chrome/browser/sync_file_system/local/syncable_file_operation_runner_unittest.cc b/chrome/browser/sync_file_system/local/syncable_file_operation_runner_unittest.cc
index faed839..2e8fa9a 100644
--- a/chrome/browser/sync_file_system/local/syncable_file_operation_runner_unittest.cc
+++ b/chrome/browser/sync_file_system/local/syncable_file_operation_runner_unittest.cc
@@ -59,7 +59,7 @@
       : task_environment_(content::BrowserTaskEnvironment::IO_MAINLOOP),
         in_memory_env_(
             leveldb_chrome::NewMemEnv("SyncableFileOperationRunnerTest")),
-        file_system_(GURL("http://example.com"),
+        file_system_(GURL("chrome-extension://example"),
                      in_memory_env_.get(),
                      base::SingleThreadTaskRunner::GetCurrentDefault().get(),
                      base::SingleThreadTaskRunner::GetCurrentDefault().get()),
diff --git a/chrome/browser/sync_file_system/local/syncable_file_system_unittest.cc b/chrome/browser/sync_file_system/local/syncable_file_system_unittest.cc
index 9d73af03..b43fd0c 100644
--- a/chrome/browser/sync_file_system/local/syncable_file_system_unittest.cc
+++ b/chrome/browser/sync_file_system/local/syncable_file_system_unittest.cc
@@ -40,7 +40,7 @@
  public:
   SyncableFileSystemTest()
       : in_memory_env_(leveldb_chrome::NewMemEnv("SyncableFileSystemTest")),
-        file_system_(GURL("http://example.com/"),
+        file_system_(GURL("chrome-extension://example/"),
                      in_memory_env_.get(),
                      base::SingleThreadTaskRunner::GetCurrentDefault().get(),
                      base::SingleThreadTaskRunner::GetCurrentDefault().get()) {}
diff --git a/chrome/browser/sync_file_system/sync_file_system_service_unittest.cc b/chrome/browser/sync_file_system/sync_file_system_service_unittest.cc
index 8c4741d..7810f7f4 100644
--- a/chrome/browser/sync_file_system/sync_file_system_service_unittest.cc
+++ b/chrome/browser/sync_file_system/sync_file_system_service_unittest.cc
@@ -52,7 +52,7 @@
 
 namespace {
 
-const char kOrigin[] = "http://example.com";
+const char kOrigin[] = "chrome-extension://example";
 
 template <typename R> struct AssignTrait {
   typedef const R& ArgumentType;
Loading diff…

Original Bug Report

reported by [email protected]

Unauthorized Google Drive API access via SyncFileSystem permission bypass

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 without the Chrome Security team.

Overview: A potential vulnerability exists where standard web origins can resolve the global syncfs mount point due to a permission policy flaw. This allows an attacker to bypass extension checks and trigger authenticated Google Drive API writes via the deprecated SyncFileSystem component. Malicious sites could potentially create directories and sync files to a user’s Google Drive without interaction.

Affected files:

  • chrome/browser/sync_file_system/local/sync_file_system_backend.cc
  • chrome/browser/sync_file_system/sync_file_system_service.cc
  • chrome/browser/sync_file_system/drive_backend/sync_worker.cc
  • chrome/browser/sync_file_system/drive_backend/sync_engine.cc
  • chrome/browser/sync_file_system/drive_backend/register_app_task.cc
  • chrome/browser/sync_file_system/syncable_file_system_util.cc

Estimated timestamp from git blame: 2025-09-24

Technical Details

There is a potential vulnerability in the SyncFileSystem component that allows arbitrary web origins to bypass extension permission checks and trigger authenticated Google Drive API calls. The core issue stems from how the global syncfs mount point is registered and authorized.

During startup, SyncFileSystemBackend registers a process-global mount point named syncfs mapped to storage::kFileSystemTypeSyncable (chrome/browser/sync_file_system/syncable_file_system_util.cc:37). In storage::FileSystemContext::GetPermissionPolicy, kFileSystemTypeSyncable is explicitly associated with storage::FILE_PERMISSION_SANDBOX.

When a standard web renderer requests access to this mount point, the security check is handled by ChildProcessSecurityPolicyImpl::HasPermissionsForFileSystemFile. Because the filesystem type is associated with FILE_PERMISSION_SANDBOX, the policy immediately grants access as long as the renderer’s origin matches the URL’s origin. It does not perform the strict, path-based access controls typically applied to non-sandboxed external filesystems. This effectively allows any web origin to resolve filesystem:<origin>/external/syncfs/x.

Once access is granted, the request is routed to SyncFileSystemService::InitializeForApp. This method initializes the local filesystem context but critically fails to verify whether the requesting origin corresponds to a valid, installed Chrome Extension holding the syncFileSystem permission.

While Chrome attempts to disable this deprecated service by default, this mitigation is bypassed. When Chrome Sync is enabled and the APPS data type is active, SyncFileSystemService::OnStateChanged calls remote_service_->SetSyncEnabled(true). This triggers SyncEngine::SetSyncEnabled, which recreates the SyncWorker, effectively reviving the service.

Following initialization, SyncWorker::RegisterOrigin is called with the attacker’s origin. It schedules a RegisterAppTask, which uses the DriveServiceInterface (and the user’s OAuth tokens) to perform an authenticated Google Drive API request (AddNewDirectory) to create a folder named after the attacker’s host.

Impact

A malicious website could potentially cause the browser to perform unauthorized, OAuth-authenticated writes to a signed-in user’s Google Drive (provided Chrome Sync is enabled) without any user interaction or extension privileges.

Potential Reproduction Steps

(Note: These are suggested steps based on code analysis; a live PoC has not been executed by this agent.)

  1. Sign in to Chrome with a Google account and ensure Chrome Sync is enabled.
  2. Navigate to an attacker-controlled HTTPS page (e.g., https://attacker.com).
  3. The page executes the following JavaScript: webkitResolveLocalFileSystemURL('filesystem:' + location.origin + '/external/syncfs/x', function(entry){}, function(err){});
  4. The browser process should proceed to perform authenticated Drive API calls and create a new directory named attacker.com within the hidden ‘Chrome Syncable FileSystem’ root folder in the user’s Drive.

Suggested Fix

  1. Add explicit permission checks: SyncFileSystemService::InitializeForApp must explicitly verify that the requesting origin_url belongs to a valid, installed Chrome App or Extension that holds the syncFileSystem permission.
  2. Review Permission Policy: Re-evaluate whether kFileSystemTypeSyncable should be granted FILE_PERMISSION_SANDBOX, as this allows standard web origins to bypass external mount point restrictions.
  3. Remove Deprecated Code: Given that the SyncFileSystem API is deprecated, the most robust fix would be to completely remove the chrome/browser/sync_file_system/ component and related Drive backend code if it is no longer required.

Evaluated with Chrome root at commit: 096fc8fdbfacf2546485756d03f160a3d04fcc9b


Results so far have been promising, but there can be wrong deductions. If this proves to be a false positive, please close as WAI; 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
Links in the report