[BUG] Trust store uses literal path-string matching without normalization — same directory re-prompts trust across path-separator/case variants and version upgrades

Open 💬 0 comments Opened Jul 1, 2026 by CNWTF

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

Environment:

  • Claude Code version: 2.1.197 (also reproduced with historical entries from 2.1.139, 2.1.173)
  • OS: Windows 11 Pro (10.0.26200)
  • Shell: PowerShell 5.1

Summary:
The project trust store in ~/.claude.json (projects map) appears to key on the literal working-directory path string, without normalizing path separators (/ vs \) or drive-letter/segment casing. As a result, the exact same physical directory can accumulate multiple independent entries with inconsistent hasTrustDialogAccepted values, causing the trust dialog to reappear — and .claude/settings.local.json permission rules to be silently ignored — even though the user already accepted trust for that directory under a different path notation.

Suggested fix:
Normalize the working-directory path (case-fold + separator-normalize on Windows, resolve symlinks/junctions where applicable) before using it as the lookup/storage key in the projects trust map, and perform a one-time migration to merge/dedupe existing variant entries for the same physical directory.

What Should Happen?

Expected behavior:
Trust state should be keyed on a canonicalized path (case-folded on Windows, separators normalized, ideally resolved via something like fs.realpathSync/path.resolve) so the same physical directory is recognized as already-trusted regardless of how the cwd string was produced.

Error Messages/Logs

**Evidence (same physical directory: `C:\Users\shine\mba\claude mba`):**

| Key as stored in `~/.claude.json` | `hasTrustDialogAccepted` | `lastVersionBase` |
|---|---|---|
| `C:\Users\shine\mba\claude mba` (backslash) | `true` | (none recorded) |
| `C:\Users\shine\MBA\claude mba` (backslash, different segment case) | `true` | (none recorded) |
| `C:/Users/shine/mba/claude mba` (forward slash) | `false` | `2.1.197` |
| `C:/users/shine/mba/claude mba` (forward slash, lowercase segment) | `false` | `2.1.139` |
| `C:/Users/shine/MBA/claude mba` (forward slash, different segment case) | `false` | `2.1.197` |

Windows filesystem paths are case-insensitive and separator-agnostic — all five keys above resolve to the same physical folder — but the trust store treats them as five distinct, independently-tracked projects.

Steps to Reproduce

Steps to reproduce:

  1. Launch claude in a directory using backslash-style path resolution (e.g., via cmd.exe or certain PowerShell contexts) and accept the trust dialog.
  2. Later, launch claude in the same directory but via a code path that resolves/passes the cwd using forward slashes (observed to happen after upgrading to a newer version, and also when launching via an SSH session using a Unix-style shell where paths are typed in lowercase, e.g. /c/users/...).
  3. Claude Code treats step 2 as an entirely new, untrusted project — the trust dialog reappears, and all permissions.allow entries in .claude/settings.local.json are ignored until re-accepted.

Claude Model

Sonnet (default)

Is this a regression?

Yes, this worked in a previous version

Last Working Version

_No response_

Claude Code Version

v2.1.197

Platform

Other

Operating System

Windows

Terminal/Shell

Windows Terminal

Additional Information

_No response_

View original on GitHub ↗