Overview

Medium
Severity
3.1
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactMissing authorization in FileSystem
DescriptionMissing authorization in FileSystem
ComponentFileSystem
Sub-componentFSA
Bug ClassAuthorization Error
Action tierwatch — logic/policy bug — security-relevant, no memory-unsafety
Computed by PatchGap's deterministic exploitability ruler from the fixing commit. patch-now = RCE-class & attacker-reachable in a default config, or exploited in the wild; watch = real security signal below that bar; noise = no security relevance.
Tracker498710886
Fix commite7ab8065a876 (chromium/src) +101/-3
CWECWE-862
CVSS vectorCVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:N/A:N
CISA KEVNot listed
CreditedGoogle
Reported2026-04-01 (per vendor advisory)
Fix landed2026-08-19 (public git)
Disclosed2026-09-01
Patch gap13 days — fix public in source before the advisory

Background

File System Access API
a browser feature that lets web origins persist and later re-open sandboxed file handles through FileSystemAccessManagerImpl.
`StorageKey`
the per-origin (and partition) key that scopes storage in Chromium so that one site cannot reach another site’s data.
Storage bucket
a named quota-managed storage container identified by a bucket ID and owned by exactly one StorageKey, resolved via QuotaManager::GetBucketById().
Transfer token
a mojo capability produced by serializing a FileSystemHandle that a caller can later deserialize to regain access to the referenced file.

Root Cause Analysis

When FileSystemAccessManagerImpl::DeserializeHandle rebuilt a sandboxed FileSystemHandle that referenced a non-default storage bucket, it looked the bucket up by ID through QuotaManager and, in the bucket_callback lambda, applied the returned BucketInfo to the FileSystemURL via url.SetBucket(result->ToBucketLocator()) whenever result.has_value() was true. It never verified that the resolved bucket’s storage_key matched the caller’s StorageKey, so a serialized handle carrying another origin’s bucket ID would be rebound to that foreign bucket. The same missing check existed in storage::FileSystemContext when opening a filesystem from a caller-supplied BucketLocator, whose storage_key field was trusted without cross-checking the authoritative owner from quota management. The invariant violated is that a storage bucket must only ever be accessed by its owning StorageKey.

The fix threads the caller’s expected_storage_key into the callback and drops the token (returns FILE_ERROR_FAILED) unless result->storage_key equals it, closing the authorization gap.

Key insight
The core mistake was authenticating that a bucket exists but not authorizing that it belongs to the requesting StorageKey, treating the bucket ID (and, in FileSystemContext, the BucketLocator::storage_key) as trustworthy. The fix compares the quota-manager’s authoritative result->storage_key against the caller’s key and rejects mismatches.

Attack Path

  1. Obtain a foreign bucket handle A malicious page crafts or replays a serialized sandboxed FileSystemHandle whose embedded bucket ID belongs to a different origin’s StorageKey.
  2. Deserialize under attacker origin The attacker calls DeserializeHandle with its own StorageKey, and the pre-fix bucket_callback resolves the victim bucket by ID and accepts it because it merely exists.
  3. Rebind the URL to the victim bucket url.SetBucket() applies the foreign BucketLocator, producing a live handle pointing into another origin’s sandboxed storage.
  4. Access cross-origin data Through the resolved transfer token the attacker reads or writes files in the victim origin’s bucket, bypassing StorageKey isolation.

Impact Assessment

An attacker-controlled web origin gains read/write access to another origin’s sandboxed File System Access storage, breaking same-origin storage isolation from within the renderer-facing browser-process API. The vulnerability is a missing authorization (medium severity per the metadata) requiring the attacker to supply a serialized handle or BucketLocator referencing the victim’s bucket ID. No memory-safety primitive is involved; the gain is unauthorized cross-StorageKey data access.

Changed Functions

FunctionChangeNotes
TEST_F
storage/browser/file_system/file_system_context_unittest.cc
modified

Files Changed

  • storage/browser/file_system/file_system_context_unittest.cc
  • content/browser/file_system_access/file_system_access_manager_impl_unittest.cc
  • storage/browser/file_system/file_system_context.cc
  • content/browser/file_system_access/file_system_access_manager_impl.cc

Audit Directions

  • Bucket ownership checks
    Everywhere a bucket is resolved by ID via QuotaManager::GetBucketById(), confirm the returned BucketInfo::storage_key is compared against the authenticated caller’s StorageKey before use.
  • Trusting `BucketLocator` fields
    Flag any code path that consumes a caller- or serialization-supplied BucketLocator::storage_key without re-deriving the owner from quota management.
  • Deserialization boundaries
    Review all handle/token deserialization entry points for authorization (not just existence) checks that re-validate the resource belongs to the deserializing origin.
From e7ab8065a8763f03f5b8c92d0daff4225111875f Mon Sep 17 00:00:00 2001
From: Ming-Ying Chung <mych@chromium.org>
Date: Wed, 19 Aug 2026 02:03:46 -0700
Subject: [PATCH] [FSA] Check bucket storage key when deserializing handles

When deserializing a sandboxed FileSystemHandle that references a
non-default storage bucket, verify that the bucket returned by
`QuotaManager::GetBucketById()` belongs to the same StorageKey as the
caller. If it does not, drop the token, matching the existing behavior
for buckets that no longer exist.

Bug: 498710886
Change-Id: Icf29635c1ec30dbc25baa8bb19e68b1b43c21ac7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8255670
Reviewed-by: Fergal Daly <fergal@chromium.org>
Commit-Queue: Ming-Ying Chung <mych@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1682137}
---
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 ad279ee..14e62d7 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
@@ -1250,16 +1250,18 @@
       // Apply bucket information.
       auto bucket_callback = base::BindOnce(
           [](storage::FileSystemURL url,
+             const blink::StorageKey& expected_storage_key,
              base::OnceCallback<void(const storage::FileSystemURL&)> callback,
              storage::QuotaErrorOr<storage::BucketInfo> result) {
-            if (!result.has_value()) {
+            if (!result.has_value() ||
+                result->storage_key != expected_storage_key) {
               // Drop `token`, and directly return.
               return;
             }
             url.SetBucket(result->ToBucketLocator());
             std::move(callback).Run(url);
           },
-          url,
+          url, storage_key,
           base::BindOnce(&FileSystemAccessManagerImpl::
                              DidGetSandboxedBucketForDeserializeHandle,
                          weak_factory_.GetWeakPtr(), data, std::move(token),
diff --git a/storage/browser/file_system/file_system_context.cc b/storage/browser/file_system/file_system_context.cc
index 457049d..76dc4c5 100644
--- a/storage/browser/file_system/file_system_context.cc
+++ b/storage/browser/file_system/file_system_context.cc
@@ -423,7 +423,7 @@
     OpenFileSystemMode mode,
     OpenFileSystemCallback callback,
     QuotaErrorOr<BucketInfo> result) {
-  if (!result.has_value()) {
+  if (!result.has_value() || result->storage_key != storage_key) {
     std::move(callback).Run(FileSystemURL(), std::string(),
                             base::File::FILE_ERROR_FAILED);
     return;
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 00e479c..78c13353 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
@@ -1036,6 +1036,59 @@
   EXPECT_EQ(PermissionStatus::GRANTED, token->GetWriteGrant()->GetStatus());
 }
 
+// Verifies that `DeserializeHandle()` rejects sandboxed file handles associated
+// with a storage bucket owned by a different `blink::StorageKey`.
+//
+// The test serializes a handle pointing to a custom bucket under an alternate
+// storage key, then attempts to deserialize it using the test caller's storage
+// key. The deserialization must drop the transfer token and fail to resolve.
+TEST_F(FileSystemAccessManagerImplTest,
+       DeserializeHandle_SandboxedFile_OtherStorageKeyBucket) {
+  // Create a non-default bucket owned by a different storage key.
+  const blink::StorageKey kOtherStorageKey =
+      blink::StorageKey::CreateFromStringForTesting("https://other.example/");
+  base::test::TestFuture<storage::QuotaErrorOr<storage::BucketInfo>>
+      bucket_future;
+  quota_manager_proxy_->CreateBucketForTesting(
+      kOtherStorageKey, "custom_bucket",
+      base::SequencedTaskRunner::GetCurrentDefault(),
+      bucket_future.GetCallback());
+  ASSERT_OK_AND_ASSIGN(auto other_bucket, bucket_future.Take());
+
+  // Serialize a sandboxed file handle that points at the other key's bucket.
+  // The handle must be constructed with a matching binding context to satisfy
+  // token origin validation during serialization.
+  auto test_file_url = file_system_context_->CreateCrackedFileSystemURL(
+      kOtherStorageKey, storage::kFileSystemTypeTemporary,
+      base::FilePath::FromUTF8Unsafe("test/foo/bar"));
+  test_file_url.SetBucket(other_bucket.ToBucketLocator());
+  const FileSystemAccessManagerImpl::BindingContext other_binding_context = {
+      kOtherStorageKey, GURL("https://other.example/"),
+      GlobalRenderFrameHostId()};
+  FileSystemAccessFileHandleImpl file(manager_.get(), other_binding_context,
+                                      test_file_url, "bar",
+                                      {ask_grant_, ask_grant_});
+  mojo::PendingRemote<blink::mojom::FileSystemAccessTransferToken> token_remote;
+  manager_->CreateTransferToken(file,
+                                token_remote.InitWithNewPipeAndPassReceiver());
+
+  base::test::TestFuture<std::vector<uint8_t>> serialize_future;
+  manager_->SerializeHandle(
+      std::move(token_remote),
+      serialize_future.GetCallback<const std::vector<uint8_t>&>());
+  std::vector<uint8_t> serialized = serialize_future.Take();
+  EXPECT_FALSE(serialized.empty());
+
+  // Deserializing under `kTestStorageKey`, which does not own the bucket, must
+  // drop the transfer token and fail to resolve.
+  manager_->DeserializeHandle(kTestStorageKey, serialized,
+                              token_remote.InitWithNewPipeAndPassReceiver());
+  base::test::TestFuture<FileSystemAccessTransferTokenImpl*> resolve_future;
+  manager_->ResolveTransferToken(std::move(token_remote),
+                                 resolve_future.GetCallback());
+  EXPECT_FALSE(resolve_future.Get());
+}
+
 TEST_F(FileSystemAccessManagerImplTest,
        SerializeHandle_SandboxedDirectory_CustomBucket) {
   auto test_file_url = file_system_context_->CreateCrackedFileSystemURL(
diff --git a/storage/browser/file_system/file_system_context_unittest.cc b/storage/browser/file_system/file_system_context_unittest.cc
index a223db35..39e7402a 100644
--- a/storage/browser/file_system/file_system_context_unittest.cc
+++ b/storage/browser/file_system/file_system_context_unittest.cc
@@ -232,6 +232,49 @@
   ASSERT_EQ(last_resolved_url_.value().bucket(), bucket.ToBucketLocator());
 }
 
+// Verifies that `OpenFileSystem()` rejects attempts to open a filesystem when
+// the requested storage bucket belongs to a different `blink::StorageKey`.
+//
+// The test constructs a spoofed `storage::BucketLocator` pointing to a bucket
+// ID owned by another storage key and invokes `OpenFileSystem()`. The operation
+// must validate the bucket's actual owner from quota management and fail with
+// `base::File::FILE_ERROR_FAILED`.
+TEST_F(FileSystemContextTest, OpenFileSystem_OtherStorageKeyBucket) {
+  scoped_refptr<FileSystemContext> file_system_context =
+      CreateFileSystemContextForTest(/*external_mount_points=*/nullptr);
+  base::RunLoop run_loop;
+  base::File::Error open_error = base::File::FILE_OK;
+  const auto open_callback = base::BindLambdaForTesting(
+      [&](const FileSystemURL& root_url, const std::string& name,
+          base::File::Error error) {
+        open_error = error;
+        run_loop.Quit();
+      });
+  const auto storage_key =
+      blink::StorageKey::CreateFromStringForTesting("http://host/test.crswap");
+  const auto other_storage_key =
+      blink::StorageKey::CreateFromStringForTesting("http://other/test.crswap");
+  base::test::TestFuture<storage::QuotaErrorOr<storage::BucketInfo>>
+      bucket_future;
+  proxy()->CreateBucketForTesting(
+      other_storage_key, "custom_bucket",
+      base::SequencedTaskRunner::GetCurrentDefault(),
+      bucket_future.GetCallback());
+  ASSERT_OK_AND_ASSIGN(auto bucket, bucket_future.Take());
+
+  // Construct a bucket locator spoofing ownership under `storage_key` while
+  // referencing the bucket ID registered to `other_storage_key`.
+  storage::BucketLocator spoofed_bucket = bucket.ToBucketLocator();
+  spoofed_bucket.storage_key = storage_key;
+
+  file_system_context->OpenFileSystem(
+      storage_key, spoofed_bucket, kFileSystemTypeTemporary,
+      OpenFileSystemMode::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
+      std::move(open_callback));
+  run_loop.Run();
+  EXPECT_EQ(base::File::FILE_ERROR_FAILED, open_error);
+}
+
 TEST_F(FileSystemContextTest, CrackFileSystemURL) {
   scoped_refptr<ExternalMountPoints> external_mount_points =
       ExternalMountPoints::CreateRefCounted();
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 00e479c..78c13353 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
@@ -1036,6 +1036,59 @@
   EXPECT_EQ(PermissionStatus::GRANTED, token->GetWriteGrant()->GetStatus());
 }
 
+// Verifies that `DeserializeHandle()` rejects sandboxed file handles associated
+// with a storage bucket owned by a different `blink::StorageKey`.
+//
+// The test serializes a handle pointing to a custom bucket under an alternate
+// storage key, then attempts to deserialize it using the test caller's storage
+// key. The deserialization must drop the transfer token and fail to resolve.
+TEST_F(FileSystemAccessManagerImplTest,
+       DeserializeHandle_SandboxedFile_OtherStorageKeyBucket) {
+  // Create a non-default bucket owned by a different storage key.
+  const blink::StorageKey kOtherStorageKey =
+      blink::StorageKey::CreateFromStringForTesting("https://other.example/");
+  base::test::TestFuture<storage::QuotaErrorOr<storage::BucketInfo>>
+      bucket_future;
+  quota_manager_proxy_->CreateBucketForTesting(
+      kOtherStorageKey, "custom_bucket",
+      base::SequencedTaskRunner::GetCurrentDefault(),
+      bucket_future.GetCallback());
+  ASSERT_OK_AND_ASSIGN(auto other_bucket, bucket_future.Take());
+
+  // Serialize a sandboxed file handle that points at the other key's bucket.
+  // The handle must be constructed with a matching binding context to satisfy
+  // token origin validation during serialization.
+  auto test_file_url = file_system_context_->CreateCrackedFileSystemURL(
+      kOtherStorageKey, storage::kFileSystemTypeTemporary,
+      base::FilePath::FromUTF8Unsafe("test/foo/bar"));
+  test_file_url.SetBucket(other_bucket.ToBucketLocator());
+  const FileSystemAccessManagerImpl::BindingContext other_binding_context = {
+      kOtherStorageKey, GURL("https://other.example/"),
+      GlobalRenderFrameHostId()};
+  FileSystemAccessFileHandleImpl file(manager_.get(), other_binding_context,
+                                      test_file_url, "bar",
+                                      {ask_grant_, ask_grant_});
+  mojo::PendingRemote<blink::mojom::FileSystemAccessTransferToken> token_remote;
+  manager_->CreateTransferToken(file,
+                                token_remote.InitWithNewPipeAndPassReceiver());
+
+  base::test::TestFuture<std::vector<uint8_t>> serialize_future;
+  manager_->SerializeHandle(
+      std::move(token_remote),
+      serialize_future.GetCallback<const std::vector<uint8_t>&>());
+  std::vector<uint8_t> serialized = serialize_future.Take();
+  EXPECT_FALSE(serialized.empty());
+
+  // Deserializing under `kTestStorageKey`, which does not own the bucket, must
+  // drop the transfer token and fail to resolve.
+  manager_->DeserializeHandle(kTestStorageKey, serialized,
+                              token_remote.InitWithNewPipeAndPassReceiver());
+  base::test::TestFuture<FileSystemAccessTransferTokenImpl*> resolve_future;
+  manager_->ResolveTransferToken(std::move(token_remote),
+                                 resolve_future.GetCallback());
+  EXPECT_FALSE(resolve_future.Get());
+}
+
 TEST_F(FileSystemAccessManagerImplTest,
        SerializeHandle_SandboxedDirectory_CustomBucket) {
   auto test_file_url = file_system_context_->CreateCrackedFileSystemURL(
diff --git a/storage/browser/file_system/file_system_context_unittest.cc b/storage/browser/file_system/file_system_context_unittest.cc
index a223db35..39e7402a 100644
--- a/storage/browser/file_system/file_system_context_unittest.cc
+++ b/storage/browser/file_system/file_system_context_unittest.cc
@@ -232,6 +232,49 @@
   ASSERT_EQ(last_resolved_url_.value().bucket(), bucket.ToBucketLocator());
 }
 
+// Verifies that `OpenFileSystem()` rejects attempts to open a filesystem when
+// the requested storage bucket belongs to a different `blink::StorageKey`.
+//
+// The test constructs a spoofed `storage::BucketLocator` pointing to a bucket
+// ID owned by another storage key and invokes `OpenFileSystem()`. The operation
+// must validate the bucket's actual owner from quota management and fail with
+// `base::File::FILE_ERROR_FAILED`.
+TEST_F(FileSystemContextTest, OpenFileSystem_OtherStorageKeyBucket) {
+  scoped_refptr<FileSystemContext> file_system_context =
+      CreateFileSystemContextForTest(/*external_mount_points=*/nullptr);
+  base::RunLoop run_loop;
+  base::File::Error open_error = base::File::FILE_OK;
+  const auto open_callback = base::BindLambdaForTesting(
+      [&](const FileSystemURL& root_url, const std::string& name,
+          base::File::Error error) {
+        open_error = error;
+        run_loop.Quit();
+      });
+  const auto storage_key =
+      blink::StorageKey::CreateFromStringForTesting("http://host/test.crswap");
+  const auto other_storage_key =
+      blink::StorageKey::CreateFromStringForTesting("http://other/test.crswap");
+  base::test::TestFuture<storage::QuotaErrorOr<storage::BucketInfo>>
+      bucket_future;
+  proxy()->CreateBucketForTesting(
+      other_storage_key, "custom_bucket",
+      base::SequencedTaskRunner::GetCurrentDefault(),
+      bucket_future.GetCallback());
+  ASSERT_OK_AND_ASSIGN(auto bucket, bucket_future.Take());
+
+  // Construct a bucket locator spoofing ownership under `storage_key` while
+  // referencing the bucket ID registered to `other_storage_key`.
+  storage::BucketLocator spoofed_bucket = bucket.ToBucketLocator();
+  spoofed_bucket.storage_key = storage_key;
+
+  file_system_context->OpenFileSystem(
+      storage_key, spoofed_bucket, kFileSystemTypeTemporary,
+      OpenFileSystemMode::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
+      std::move(open_callback));
+  run_loop.Run();
+  EXPECT_EQ(base::File::FILE_ERROR_FAILED, open_error);
+}
+
 TEST_F(FileSystemContextTest, CrackFileSystemURL) {
   scoped_refptr<ExternalMountPoints> external_mount_points =
       ExternalMountPoints::CreateRefCounted();
Loading diff…

Original Bug Report

reported by rj...@google.com

Cross-Origin OPFS Access via Missing Bucket Ownership Check in DeserializeHandle

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 security team.

Overview: A compromised renderer can potentially gain cross-origin read/write access to a victim’s non-default OPFS storage buckets. By laundering a stolen FileSystemAccessTransferToken through IndexedDB, an attacker can bypass origin checks because FileSystemAccessManagerImpl::DeserializeHandle fails to verify bucket ownership when deserializing handles.

Affected files:

  • content/browser/file_system_access/file_system_access_manager_impl.cc
  • storage/browser/file_system/obfuscated_file_util.cc
  • storage/browser/quota/quota_manager_impl.cc
  • storage/browser/file_system/file_system_url.h
  • content/browser/indexed_db/instance/bucket_context.cc

Estimated timestamp from git blame: 2023-02-24

Summary

A logic flaw in how the File System Access API deserializes handles from IndexedDB could allow a compromised renderer to gain unauthorized cross-origin access to a victim’s non-default Origin Private File System (OPFS) storage buckets.

When a FileSystemHandle representing a file in a non-default storage bucket is serialized (e.g., when saved to IndexedDB), the browser stores the physical bucket_id but relies on the context (the IndexedDB instance’s Storage Key) to determine ownership during deserialization. If an attacker can force the browser to serialize a victim’s token into the attacker’s IndexedDB, the subsequent deserialization process will combine the attacker’s Storage Key with the victim’s bucket_id without verifying ownership, resulting in a “laundered” handle that bypasses origin checks.

Potential Exploit Steps

Note: These steps represent a theoretical exploit chain based on code analysis; a functional proof-of-concept has not been executed.

  1. Prerequisites: An attacker compromises a renderer process (Origin B). A victim origin (Origin A) obtains a handle to a file in its non-default OPFS bucket and sends it to Origin B via postMessage('*').
  2. Token Interception: The compromised renderer for Origin B receives the FileSystemAccessTransferToken Mojo remote and bypasses normal renderer-side checks that would drop cross-origin tokens.
  3. Storage (Serialization): The compromised renderer initiates a transaction to store this token remote in its own IndexedDB. In the browser process, FileSystemAccessManagerImpl::SerializeHandle handles this by extracting the victim’s bucket_id from the URL and saving it to a protobuf (FileSystemAccessHandleData). The StorageKey is intentionally omitted from the serialized data.
  4. Retrieval (Deserialization): The attacker reads the stored record from IndexedDB. This triggers FileSystemAccessManagerImpl::DeserializeHandle in the browser process.
  5. Missing Ownership Verification: DeserializeHandle is called with the attacker’s StorageKey (Origin B) and the serialized protobuf containing the victim’s bucket_id. It calls QuotaManagerImpl::GetBucketById to resolve the bucket. Crucially, GetBucketById fetches the bucket information but does not verify that the retrieved bucket actually belongs to Origin B’s StorageKey.
  6. Token Laundering: The callback in DeserializeHandle applies the victim’s BucketLocator to a new FileSystemURL that holds the attacker’s StorageKey. It then mints a new FileSystemAccessTransferTokenImpl. Because it uses Origin B’s StorageKey, the new token is bound to Origin B’s origin, effectively laundering it.
  7. Security Bypass and Access: The attacker redeems the laundered token. The browser’s defense-in-depth check (IsValidTransferToken) passes because the token’s origin now matches the attacker’s origin. Subsequent file I/O operations (e.g., getFile()) are routed by ObfuscatedFileUtil using the bucket() field of the URL, granting the attacker read/write access to the victim’s physical OPFS directory on disk.

Suggested Fix

In FileSystemAccessManagerImpl::DeserializeHandle (content/browser/file_system_access/file_system_access_manager_impl.cc), explicitly verify that the BucketInfo retrieved from GetBucketById belongs to the storage_key provided to the deserialization method.

        context_->quota_manager_proxy()->GetBucketById(
            storage::BucketId::FromUnsafeValue(data.sandboxed().bucket_id()),
            base::SequencedTaskRunner::GetCurrentDefault(),
            base::BindOnce(
                [](storage::FileSystemURL url, const blink::StorageKey& expected_storage_key,
                   base::OnceCallback<void(const storage::FileSystemURL&)> callback,
                   storage::QuotaErrorOr<storage::BucketInfo> result) {
                  if (!result.has_value() || result->storage_key != expected_storage_key) {
                    // Drop `token`, and directly return.
                    return;
                  }
                  url.SetBucket(result->ToBucketLocator());
                  std::move(callback).Run(url);
                },
                url, storage_key, std::move(bucket_callback)));

Evaluated with Chrome root at commit: e9e0fcbb690b1a8c1a26c81c2a9ea23d6e178368


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