CVE-2026-79088
Overview
Background
- File System Access (FSA) permission grants
ChromeFileSystemAccessPermissionContextkeeps per-originread_grantsandwrite_grants(PermissionGrantImplobjects keyed by path) inactive_permissions_map_. Each grant has a status ofGRANTED,DENIEDorASK.- `kFileSystemAccessRevokeReadOnRemove`
- a feature under which
handle.remove()(NotifyEntryRemoved) downgrades the origin’s read grant for that path toDENIED, keeps write access, and records the path indowngraded_read_paths. Content later found there may have been written by someone else. - `MaybeRestoreReadPermission`
- restores a downgraded read grant to
GRANTEDwhen the origin itself writes content at a path indowngraded_read_paths, on the reasoning that the origin then authored that content. - `NotifyEntryMoved`
- called when an FSA handle is moved or renamed (
handle.move()). It moves the origin’s grants fromold_pathtonew_paththroughPermissionGrantImpl::UpdateGrantPath.
Root Cause Analysis
ChromeFileSystemAccessPermissionContext::NotifyEntryMoved moved the active read and write grants from old_path to new_path, but left downgraded_read_paths untouched. It then always called MaybeRestoreReadPermission(origin, new_path.path) when kFileSystemAccessRevokeReadOnRemove was enabled. So after handle.remove() downgraded secret.txt, and another party recreated secret.txt, the origin could move the handle to temp.txt (which carries along the DENIED read grant but leaves the stale secret.txt entry behind) and then move it back. The second move found secret.txt in downgraded_read_paths and restored read access to GRANTED on content the origin never wrote. This broke the invariant that a downgraded read grant is restored only after the origin itself writes.
The fix makes downgraded_read_paths follow the move: it erases old_path and inserts new_path. It also skips MaybeRestoreReadPermission whenever the moved entry was itself downgraded (old_path_was_downgraded). Separately, the patch removes a DCHECK in PermissionGrantImpl::UpdateGrantPath that assumed moved grants are always GRANTED, which crashed Debug builds now that DENIED read grants are kept on purpose.
MaybeRestoreReadPermission into re-granting read access. The fix moves the marker with the grant and stops a move from restoring read access to a downgraded entry.Attack Path
- Obtain read+write access
A web origin gets FSA read and write grants for a file or directory through the normal picker and permission flow, with
kFileSystemAccessRevokeReadOnRemoveenabled. - Remove the entry
The origin calls
handle.remove().NotifyEntryRemoveddowngrades the read grant toDENIED, keeps write access, and records the path indowngraded_read_paths. - Wait for foreign content Another program or the user recreates a file at the same path, with content the origin should not be able to read.
- Move away and back
The origin calls
handle.move()to a temporary name and then back to the original name. Before the patch, the secondNotifyEntryMovedfound the stale entry indowngraded_read_pathsand calledMaybeRestoreReadPermission, which set read access back toGRANTED. - Read the recreated file With read access restored, the origin can read content it did not author, which the revoke-on-remove design was meant to prevent.
Impact Assessment
kFileSystemAccessRevokeReadOnRemove feature, prior user-granted read and write access, and a third party recreating the file at the same path. The removed DCHECK affected only Debug builds (a crash), not release behaviour. The advisory states only “Incorrect authorization in FileSystem” and gives no in-the-wild exploitation detail.Changed Functions
| Function | Change | Notes |
|---|---|---|
ifchrome/browser/file_system_access/chrome_file_system_access_permission_context.cc |
modified |
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
- Path-keyed side tables in permission stateLook for other per-origin sets or maps keyed by path (
downgraded_read_paths, blocked-path caches, recently-removed lists) thatNotifyEntryMoved, directory moves (descendant paths) or overwrite-on-move (kFileSystemAccessMoveWithOverwrite) do not update consistently. - Restore or upgrade triggersAudit every caller of
MaybeRestoreReadPermissionand similar re-grant helpers, such asNotifyEntryModified, to confirm each trigger really shows the origin authored the content, rather than merely touched the path. - Move into an existing downgraded pathCheck the opposite case: moving a readable entry onto a path still in
downgraded_read_paths, including case-insensitive path matches, to confirm no other stale-state combination re-grants read.
Patch
From ab88b786ad83b611543df884ef7344d7ff92a906 Mon Sep 17 00:00:00 2001 From: Ming-Ying Chung <[email protected]> Date: Tue, 11 Aug 2026 18:30:26 -0700 Subject: [PATCH] [FSA] Maintain downgraded read permissions across file moves A state tracking flaw in NotifyEntryMoved() leaves stale entries in downgraded_read_paths when file entries are moved. When handle.remove() downgrades a read grant to DENIED, the path is stored in downgraded_read_paths to track potential origin file recreations. However, moving the handle away and back leaves the original path in downgraded_read_paths. Consequently, MaybeRestoreReadPermission() inappropriately restores read access to GRANTED on a file the origin did not author. For example, consider an origin manipulating a target file handle: (1) Initial state: Read status is GRANTED and write status is GRANTED for "secret.txt". (2) handle.remove(): Read status drops to DENIED, write status remains GRANTED, and "secret.txt" is added to downgraded_read_paths. (3) Victim recreates "secret.txt": Read status for origin remains DENIED. (4) handle.move('temp.txt'): Active grants migrate to "temp.txt", but "secret.txt" remains in downgraded_read_paths. (5) handle.move('secret.txt'): Grants migrate back to secret.txt, and MaybeRestoreReadPermission() finds "secret.txt" in downgraded_read_paths, incorrectly restoring read status to GRANTED. Also drop the obsolete DCHECK in PermissionGrantImpl:UpdateGrantPath(): removing it is safe because DENIED read grants now represent a valid runtime state. PermissionGrantImpl::UpdateGrantPath() asserted that active grants being moved held GRANTED status, which caused Debug builds to crash when moving handles with read grants downgraded to DENIED by handle.remove(). Prior to kFileSystemAccessRevokeReadOnRemove, active grants being moved were assumed to be GRANTED. Under kFileSystemAccessRevokeReadOnRemove, revoked grants are retained in read_grants with status DENIED to track state across operations, so removing the DCHECK allows PermissionGrantImpl::UpdateGrantPath() to safely update grant paths without altering permission checks. In summary, this CL updates NotifyEntryMoved() to carry downgraded_read_paths entries alongside active grants, drops the obsolete assertion in PermissionGrantImpl::UpdateGrantPath(), and adds dedicated unit tests to verify state migration and assertion safety in Debug builds. TAG=agy CONV=214d42c9-1a4f-4404-85d5-800d9b0885eb Bug: 496401361 Change-Id: I7844d3e7cfe5ec9363bd16e028665a94fc79e620 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8224042 Reviewed-by: Mingyu Lei <[email protected]> Commit-Queue: Ming-Ying Chung <[email protected]> Cr-Commit-Position: refs/heads/main@{#1677704} --- 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 e0d5734..f2400b7 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 @@ -1223,9 +1223,6 @@ return; } - DCHECK_EQ(old_path_it->second->GetActivePermissionStatus(), - PermissionStatus::GRANTED); - auto* const grant_to_move = old_path_it->second.get(); if (allow_overwrite) { @@ -2665,6 +2662,7 @@ features::kFileSystemAccessMoveWithOverwrite); bool updated = false; + bool old_path_was_downgraded = false; auto it = active_permissions_map_.find(origin); if (it != active_permissions_map_.end()) { // TODO(crbug.com/40245144): Consolidate superfluous child grants. @@ -2672,6 +2670,14 @@ new_path, allow_overwrite); PermissionGrantImpl::UpdateGrantPath(it->second.read_grants, old_path, new_path, allow_overwrite); + if (base::FeatureList::IsEnabled( + blink::features::kFileSystemAccessRevokeReadOnRemove) && + it->second.downgraded_read_paths.erase(old_path.path)) { + // The downgraded read grant moved along with the entry; carry the + // downgraded state to `new_path` so a later write there can restore it. + it->second.downgraded_read_paths.insert(new_path.path); + old_path_was_downgraded = true; + } updated = true; } if (base::FeatureList::IsEnabled( @@ -2702,7 +2708,10 @@ } if (base::FeatureList::IsEnabled( - blink::features::kFileSystemAccessRevokeReadOnRemove)) { + blink::features::kFileSystemAccessRevokeReadOnRemove) && + !old_path_was_downgraded) { + // Only restore if the moved entry was readable at `old_path`; otherwise + // the origin has not authored the content now at `new_path`. MaybeRestoreReadPermission(origin, new_path.path); } } 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 337d442..67f0e25 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 @@ -3795,6 +3795,103 @@ PermissionStatus::ASK); } +// Verifies that moving an entry with a downgraded read grant transfers the +// downgraded state to the destination path, and moving the entry back to its +// original path does not restore the read grant. +TEST_F(ChromeFileSystemAccessPermissionContextTest, + NotifyEntryMoved_DowngradedReadGrantFollowsMove) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature( + blink::features::kFileSystemAccessRevokeReadOnRemove); + permission_context()->SetOriginHasExtendedPermissionForTesting(kTestOrigin); + + const auto file_path_info = + PathInfo(kTestPathInfo.path.AppendASCII("test_file.txt")); + const auto temp_path_info = + PathInfo(kTestPathInfo.path.AppendASCII("temp_file.txt")); + + // Initialize read and write permissions for the target file path. + auto read_grant = permission_context()->GetReadPermissionGrant( + kTestOrigin, file_path_info, HandleType::kFile, UserAction::kSave); + auto write_grant = permission_context()->GetWritePermissionGrant( + kTestOrigin, file_path_info, HandleType::kFile, UserAction::kSave); + EXPECT_EQ(read_grant->GetStatus(), PermissionStatus::GRANTED); + EXPECT_EQ(write_grant->GetStatus(), PermissionStatus::GRANTED); + + // Calling `NotifyEntryRemoved()` downgrades the read grant and records the + // path in `downgraded_read_paths`. + permission_context()->NotifyEntryRemoved(kTestOrigin, file_path_info); + EXPECT_EQ(read_grant->GetStatus(), PermissionStatus::DENIED); + EXPECT_EQ(write_grant->GetStatus(), PermissionStatus::GRANTED); + EXPECT_TRUE(permission_context()->IsPathInDowngradedReadPathsForTesting( + kTestOrigin, file_path_info.path)); + + // Calling `NotifyEntryMoved()` transfers the downgraded read state to the + // destination path. + permission_context()->NotifyEntryMoved(kTestOrigin, file_path_info, + temp_path_info); + EXPECT_EQ(read_grant->GetPath(), temp_path_info.path); + EXPECT_EQ(read_grant->GetStatus(), PermissionStatus::DENIED); + EXPECT_FALSE(permission_context()->IsPathInDowngradedReadPathsForTesting( + kTestOrigin, file_path_info.path)); + EXPECT_TRUE(permission_context()->IsPathInDowngradedReadPathsForTesting( + kTestOrigin, temp_path_info.path)); + + // Moving the entry back to its original path retains the `DENIED` read grant + // because the origin has not authored new content at the destination. + permission_context()->NotifyEntryMoved(kTestOrigin, temp_path_info, + file_path_info); + EXPECT_EQ(read_grant->GetPath(), file_path_info.path); + EXPECT_EQ(read_grant->GetStatus(), PermissionStatus::DENIED); + EXPECT_EQ(write_grant->GetStatus(), PermissionStatus::GRANTED); + EXPECT_TRUE(permission_context()->IsPathInDowngradedReadPathsForTesting( + kTestOrigin, file_path_info.path)); + EXPECT_FALSE(permission_context()->IsPathInDowngradedReadPathsForTesting( + kTestOrigin, temp_path_info.path)); + + // Calling `NotifyEntryModified()` at the original path restores the read + // grant. + permission_context()->NotifyEntryModified(kTestOrigin, file_path_info); + EXPECT_EQ(read_grant->GetStatus(), PermissionStatus::GRANTED); + EXPECT_FALSE(permission_context()->IsPathInDowngradedReadPathsForTesting( + kTestOrigin, file_path_info.path)); +} + +// Verifies that moving a handle with a downgraded read grant successfully +// updates the grant path without triggering assertion failures. +TEST_F(ChromeFileSystemAccessPermissionContextTest, + NotifyEntryMoved_DowngradedReadGrantMigratesWithoutAssertionFailure) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature( + blink::features::kFileSystemAccessRevokeReadOnRemove); + permission_context()->SetOriginHasExtendedPermissionForTesting(kTestOrigin); + + const auto file_path_info = + PathInfo(kTestPathInfo.path.AppendASCII("test_file.txt")); + const auto temp_path_info = + PathInfo(kTestPathInfo.path.AppendASCII("temp_file.txt")); + + // Initialize read and write grants. + auto read_grant = permission_context()->GetReadPermissionGrant( + kTestOrigin, file_path_info, HandleType::kFile, UserAction::kSave); + auto write_grant = permission_context()->GetWritePermissionGrant( + kTestOrigin, file_path_info, HandleType::kFile, UserAction::kSave); + EXPECT_EQ(read_grant->GetStatus(), PermissionStatus::GRANTED); + EXPECT_EQ(write_grant->GetStatus(), PermissionStatus::GRANTED); + + // Downgrade the read grant to `DENIED` via `NotifyEntryRemoved()`. + permission_context()->NotifyEntryRemoved(kTestOrigin, file_path_info); + EXPECT_EQ(read_grant->GetStatus(), PermissionStatus::DENIED); + + // Moving the handle invokes `PermissionGrantImpl::UpdateGrantPath()`. + // This operation must successfully update the grant path for a `DENIED` + // grant without triggering assertion failures in debug builds. + permission_context()->NotifyEntryMoved(kTestOrigin, file_path_info, + temp_path_info); + EXPECT_EQ(read_grant->GetPath(), temp_path_info.path); + EXPECT_EQ(read_grant->GetStatus(), PermissionStatus::DENIED); +} + // Tests that calling NotifyEntryRemoved with a directory path also revokes // read permission grants for descendants whose stored path differs only in // case from the removed directory. Native file pickers on case-insensitive
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 337d442..67f0e25 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
@@ -3795,6 +3795,103 @@
PermissionStatus::ASK);
}
+// Verifies that moving an entry with a downgraded read grant transfers the
+// downgraded state to the destination path, and moving the entry back to its
+// original path does not restore the read grant.
+TEST_F(ChromeFileSystemAccessPermissionContextTest,
+ NotifyEntryMoved_DowngradedReadGrantFollowsMove) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(
+ blink::features::kFileSystemAccessRevokeReadOnRemove);
+ permission_context()->SetOriginHasExtendedPermissionForTesting(kTestOrigin);
+
+ const auto file_path_info =
+ PathInfo(kTestPathInfo.path.AppendASCII("test_file.txt"));
+ const auto temp_path_info =
+ PathInfo(kTestPathInfo.path.AppendASCII("temp_file.txt"));
+
+ // Initialize read and write permissions for the target file path.
+ auto read_grant = permission_context()->GetReadPermissionGrant(
+ kTestOrigin, file_path_info, HandleType::kFile, UserAction::kSave);
+ auto write_grant = permission_context()->GetWritePermissionGrant(
+ kTestOrigin, file_path_info, HandleType::kFile, UserAction::kSave);
+ EXPECT_EQ(read_grant->GetStatus(), PermissionStatus::GRANTED);
+ EXPECT_EQ(write_grant->GetStatus(), PermissionStatus::GRANTED);
+
+ // Calling `NotifyEntryRemoved()` downgrades the read grant and records the
+ // path in `downgraded_read_paths`.
+ permission_context()->NotifyEntryRemoved(kTestOrigin, file_path_info);
+ EXPECT_EQ(read_grant->GetStatus(), PermissionStatus::DENIED);
+ EXPECT_EQ(write_grant->GetStatus(), PermissionStatus::GRANTED);
+ EXPECT_TRUE(permission_context()->IsPathInDowngradedReadPathsForTesting(
+ kTestOrigin, file_path_info.path));
+
+ // Calling `NotifyEntryMoved()` transfers the downgraded read state to the
+ // destination path.
+ permission_context()->NotifyEntryMoved(kTestOrigin, file_path_info,
+ temp_path_info);
+ EXPECT_EQ(read_grant->GetPath(), temp_path_info.path);
+ EXPECT_EQ(read_grant->GetStatus(), PermissionStatus::DENIED);
+ EXPECT_FALSE(permission_context()->IsPathInDowngradedReadPathsForTesting(
+ kTestOrigin, file_path_info.path));
+ EXPECT_TRUE(permission_context()->IsPathInDowngradedReadPathsForTesting(
+ kTestOrigin, temp_path_info.path));
+
+ // Moving the entry back to its original path retains the `DENIED` read grant
+ // because the origin has not authored new content at the destination.
+ permission_context()->NotifyEntryMoved(kTestOrigin, temp_path_info,
+ file_path_info);
+ EXPECT_EQ(read_grant->GetPath(), file_path_info.path);
+ EXPECT_EQ(read_grant->GetStatus(), PermissionStatus::DENIED);
+ EXPECT_EQ(write_grant->GetStatus(), PermissionStatus::GRANTED);
+ EXPECT_TRUE(permission_context()->IsPathInDowngradedReadPathsForTesting(
+ kTestOrigin, file_path_info.path));
+ EXPECT_FALSE(permission_context()->IsPathInDowngradedReadPathsForTesting(
+ kTestOrigin, temp_path_info.path));
+
+ // Calling `NotifyEntryModified()` at the original path restores the read
+ // grant.
+ permission_context()->NotifyEntryModified(kTestOrigin, file_path_info);
+ EXPECT_EQ(read_grant->GetStatus(), PermissionStatus::GRANTED);
+ EXPECT_FALSE(permission_context()->IsPathInDowngradedReadPathsForTesting(
+ kTestOrigin, file_path_info.path));
+}
+
+// Verifies that moving a handle with a downgraded read grant successfully
+// updates the grant path without triggering assertion failures.
+TEST_F(ChromeFileSystemAccessPermissionContextTest,
+ NotifyEntryMoved_DowngradedReadGrantMigratesWithoutAssertionFailure) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(
+ blink::features::kFileSystemAccessRevokeReadOnRemove);
+ permission_context()->SetOriginHasExtendedPermissionForTesting(kTestOrigin);
+
+ const auto file_path_info =
+ PathInfo(kTestPathInfo.path.AppendASCII("test_file.txt"));
+ const auto temp_path_info =
+ PathInfo(kTestPathInfo.path.AppendASCII("temp_file.txt"));
+
+ // Initialize read and write grants.
+ auto read_grant = permission_context()->GetReadPermissionGrant(
+ kTestOrigin, file_path_info, HandleType::kFile, UserAction::kSave);
+ auto write_grant = permission_context()->GetWritePermissionGrant(
+ kTestOrigin, file_path_info, HandleType::kFile, UserAction::kSave);
+ EXPECT_EQ(read_grant->GetStatus(), PermissionStatus::GRANTED);
+ EXPECT_EQ(write_grant->GetStatus(), PermissionStatus::GRANTED);
+
+ // Downgrade the read grant to `DENIED` via `NotifyEntryRemoved()`.
+ permission_context()->NotifyEntryRemoved(kTestOrigin, file_path_info);
+ EXPECT_EQ(read_grant->GetStatus(), PermissionStatus::DENIED);
+
+ // Moving the handle invokes `PermissionGrantImpl::UpdateGrantPath()`.
+ // This operation must successfully update the grant path for a `DENIED`
+ // grant without triggering assertion failures in debug builds.
+ permission_context()->NotifyEntryMoved(kTestOrigin, file_path_info,
+ temp_path_info);
+ EXPECT_EQ(read_grant->GetPath(), temp_path_info.path);
+ EXPECT_EQ(read_grant->GetStatus(), PermissionStatus::DENIED);
+}
+
// Tests that calling NotifyEntryRemoved with a directory path also revokes
// read permission grants for descendants whose stored path differs only in
// case from the removed directory. Native file pickers on case-insensitive
Original Bug Report
Read grant restoration bypass via rename round-trip in File System Access API
Project Fortify, an experimental security project, has identified the following potential security issue.
Overview: A logic error in ChromeFileSystemAccessPermissionContext fails to clear downgraded_read_paths when a file is renamed. An attacker who previously deleted a file can exploit this stale state by renaming a newly created file at the same path away and back again. This inadvertently triggers MaybeRestoreReadPermission, restoring the attacker’s revoked read access to the user’s new file.
Affected files:
chrome/browser/file_system_access/chrome_file_system_access_permission_context.cccontent/browser/file_system_access/file_system_access_handle_base.cccontent/browser/file_system_access/file_system_access_file_handle_impl.cc
Estimated timestamp from git blame: 2026-01-25
Overview
The kFileSystemAccessRevokeReadOnRemove feature protects user privacy by revoking an origin’s read access (downgrading to DENIED) when the origin deletes a file via handle.remove(). However, the path is stored in downgraded_read_paths to allow restoration if the file is immediately recreated.
A logic flaw exists in how renames (move()) interact with this state. ChromeFileSystemAccessPermissionContext::NotifyEntryMoved updates the paths for permission grants but fails to clear the original path from the downgraded_read_paths set. An attacker can exploit this stale state using a “round-trip” rename to bypass the revocation and read a newly created file at the original path.
Note: The following are potential steps to trigger the vulnerability, as our setup does not currently have the ability to run code to produce a fully working PoC.
Potential Attacker Steps
- Initial Setup & Removal: An attacker origin obtains read/write access to a user-selected file (e.g.,
secret.txt). The attacker callshandle.remove().- Result: The file is deleted.
NotifyEntryRemoveddowngrades the read grant toDENIED(write staysGRANTED) and addssecret.txttodowngraded_read_paths.
- Result: The file is deleted.
- User Recreates File: The user independently creates or saves a new file at the exact same path (
secret.txt). The origin’s handle now points to this new file, but cannot read it due to theDENIEDread grant. - First Rename (Move Away): Using a transient user activation (e.g., a single click), the attacker calls
handle.move('temp.txt').- Result: The file is renamed.
NotifyEntryMovedmigrates theDENIEDread grant andGRANTEDwrite grant totemp.txt. - Bug:
NotifyEntryMovedfails to removesecret.txtfromdowngraded_read_paths. - Note: In debug builds, this step crashes due to
DCHECK_EQ(old_path_it->second->GetActivePermissionStatus(), PermissionStatus::GRANTED);insideUpdateGrantPath. In release builds, theDCHECKcompiles out, and theDENIEDgrant is successfully migrated.
- Result: The file is renamed.
- Second Rename (Move Back): Still within the same transient user activation window, the attacker calls
handle.move('secret.txt').- Result: The file is renamed back.
NotifyEntryMovedmigrates the grants back tosecret.txt. At the end of the function, it callsMaybeRestoreReadPermission(origin, 'secret.txt').
- Result: The file is renamed back.
- Bypass Achieved:
MaybeRestoreReadPermissionchecks ifsecret.txtis indowngraded_read_paths. Because it was left stale in step 3, it is found. The function restores the read grant toGRANTED. The attacker can now read the new user-created file.
Suggested Fix
- In
ChromeFileSystemAccessPermissionContext::NotifyEntryMoved, explicitly check and managedowngraded_read_paths. Ifold_path.pathexists in the set, it should either be removed or migrated tonew_path.path, depending on the intended product behavior for tracking restored files across moves. - Re-evaluate the
DCHECK_EQinPermissionGrantImpl::UpdateGrantPath(line 1077). IfDENIEDgrants are legitimately expected to be moved (or if they shouldn’t be), the logic handlingDENIEDgrants during moves should be made robust in production builds, rather than implicitly relying on theDCHECKcompiling out.
Evaluated with Chrome root at commit: 0eb4855bda702feaaa8b899336664f97e3df88b8
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. Please feel free to reach out to me if you have concerns or feedback.