Path-pattern scanner false-positives on macOS usernames containing `.`, and "always allow" option fails to persist a rule (Bash and Write only; Edit unaffected)

Status Open
Reported on v2.1.123
Maintainer reply None cached
Activity 7 comments · opened Apr 30, 2026

Summary

Three related issues in the path-pattern security scanner that produces "suspicious Windows path pattern that requires manual approval":

  1. False positive on macOS usernames containing a period. Any path under /Users/<username-with-period>./... matches because the literal <letter>./ looks like a Windows drive-letter pattern (C:\). macOS allows periods in usernames; on my machine the username is josejimenezjr. (a common abbreviation for "Jr.") so every home-directory path under /Users/josejimenezjr./... triggers the scanner.
  2. "Yes, and always allow" doesn't persist. Selecting option 2 ("always allow access to <folder>/ from this project") does not write a rule to .claude/settings.local.json. Verified by file mtime and rule count remaining unchanged after multiple selections.
  3. Pre-installed allow-rules are bypassed. Manually adding Write(//path/**), Write(/path/**), and Bash(<exact-prefix>:*) rules to .claude/settings.local.json does not suppress the scanner. The scanner runs at a layer above the permission/allow-list system.
  4. Tool coverage: scanner fires on Bash and Write tool calls but not on Edit. Edit-tool calls to the same paths use the standard out-of-cwd permission prompt (different wording: "allow all edits in <folder>/ during this session") and are correctly suppressed by auto mode for in-project files.

Environment

  • Claude Code: 2.1.123 (latest published on npm at time of report)
  • macOS, username josejimenezjr. (legal trailing period in macOS username)
  • Auto mode (bypassPermissions) active

Reproduction

  1. macOS account with a period in the username (e.g. josejimenezjr.).
  2. In Claude Code with auto mode on, run a Bash command that writes to a home-directory path:

``
echo test > /Users/josejimenezjr./test.txt
``

  1. Observe prompt:

> Claude requested permissions to write to /Users/josejimenezjr./test.txt, which contains a suspicious Windows path pattern that requires manual approval.

  1. Pick option 2 ("Yes, and always allow access to josejimenezjr./ from this project").
  2. Run the same command again. Expected: silent. Actual: prompts again.
  3. Inspect <project>/.claude/settings.local.json: file mtime unchanged, no new rule added.
  4. Pre-install the following rules manually in .claude/settings.local.json:

``json
"Write(//Users/josejimenezjr./**)",
"Write(/Users/josejimenezjr./**)",
"Bash(echo SCANNER_PROBE:*)"
`
Run a matching
echo SCANNER_PROBE_BASH > /Users/josejimenezjr./scanner_probe.txt`. Actual: still prompts.

  1. Use the Edit tool against an existing in-project file under home dir (e.g. <project>/.claude/settings.local.json). Actual: silent (auto mode handles it correctly). Edit on an existing file outside the project working directory under home dir prompts with the standard "Yes, allow all edits during this session" prompt, not the scanner warning.

Workaround

None known. Option 2 fails silently. Manual allow-rules are not respected by this scanner. Affected users on macOS with periods in their username must manually approve every Bash and Write call to home-directory paths.

Related

  • #41763 (bypassPermissions silently downgrades to acceptEdits after approving suspicious-path prompt) - same scanner family.

View original on GitHub ↗

7 Comments

josejimenezjr0 · 4 months ago

Worth calling out plainly: auto mode (bypassPermissions) does not suppress this scanner either. The Environment block in the issue shows the repro is under auto mode, but the scanner fires regardless of permission mode (auto, default, plan). This is consistent with the architectural finding in summary point #3 - the scanner appears to run above the permission resolution layer entirely, so neither auto mode nor manual allow-rules can override it.

github-actions[bot] · 4 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/37192
  2. https://github.com/anthropics/claude-code/issues/35183
  3. https://github.com/anthropics/claude-code/issues/16762

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

josejimenezjr0 · 4 months ago

Update: corrections, expanded scope, and duplicate triage

After running additional tests on a second macOS account (no period in the username) across both 2.1.116 and 2.1.123, the original report needs significant corrections. The bug surface is wider than originally reported, two findings were wrong, and there's confirmed version drift between releases.

Duplicate-candidate triage (responding to bot)

  • #37192 (WSL permission rules ignored): not a duplicate. Different platform (Windows/WSL), different root cause (WSL path translation, \\wsl.localhost\...), different tool surface. Surface theme of "permissions ignored" but unrelated underlying bug.
  • #35183 (backticks inside <<'EOF' heredoc): architectural sibling, not a duplicate. Tested the verbatim repro on 2.1.116 - did not fire, appears silently fixed. Same shape as this bug (a content scanner producing false positives that runs above the permission resolution layer), different specific scanner. Worth referencing because if backticks were patched the same way, it suggests the path scanner can be patched similarly.
  • #16762 (Always Allow not persisted, Windows, March 2024, still open + stale): closest match for finding #2 in this report. Identical symptom, identical prompt wording ("Yes, allow access to [path] from this project"). My macOS reproduction proves this is a cross-platform persistence bug, not Windows-specific. Strong recommendation to link this with #54856 - very likely same root cause, different platform manifestation.

Corrections to the original report

  1. Scope is wider than "usernames containing .". The trigger is any path segment ending in . anywhere under /Users/ or /private/, regardless of username. Common real-world directories that fire: Mr., Jr., Sr., Dr., Co., Inc., Vol.1, Apr., version suffixes, abbreviated folder names. The username case is just one easy repro because josejimenezjr. (period for "Jr.") creates a period-ending segment in every home-directory path.
  1. Tool coverage is Bash only, not "Bash and Write". Verified on 2.1.123:
  • Write tool to /Users/Shared/sibling_verify/Mr./writetest.txt: fires the standard out-of-cwd permission prompt ("Do you want to create writetest.txt? [...] Yes, allow all edits in Mr./ during this session"), not the scanner warning.
  • Edit tool: same standard prompt, no scanner.
  • Read tool: silent, no scanner.
  • Bash tool: scanner fires.

The original report's "Bash and Write" claim was extrapolated from a parallel-tool-call test that was inconclusive (the user rejected before the Write probe completed). On clean re-test, Write does not trigger this scanner.

Version drift (2.1.116 → 2.1.123)

The regex was broadened between these versions. Concrete comparison:

| Test | 2.1.116 | 2.1.123 |
|---|---|---|
| mkdir "/Users/foo/scanner-test/r." (period at end of arg) | fires | fires |
| mkdir "/Users/foo/scanner-test/r./newsub" (period followed by /<chars>") | silent | fires |
| mkdir "/Users/foo/scanner-test/.dotdir" (period at segment start) | silent | silent |
| ls "/Users/foo/scanner-test/r./" (period followed by /") | silent | silent |

The "always allow" persistence failure is unchanged across both versions.

The 2.1.123 broadening means every command operating on a path containing any period-ending segment under /Users/ or /private/ now fires the scanner, as long as there's at least one more path component after that segment. This is the user-facing regression that made the bug noticeable now.

Refined regex hypothesis

For 2.1.123:

/(\/Users\/|\/private\/)[^"]*?[A-Za-z0-9]+\.(?:\/[^"\/]+|\s*"|$)/i

That is: under a literal /Users/ or /private/ prefix, match <word-chars>. followed by either:

  • A close quote (with optional trailing whitespace), OR
  • A slash followed by one or more non-slash, non-quote chars

Case-insensitive. Maintainers should confirm against actual source.

New finding: trivial bypass via runtime path construction

The scanner string-matches the visible Bash command, not the resolved path. Verified silent on 2.1.123:

sub=$(printf 'r%s' '.'); mkdir -p "/Users/Shared/sibling_verify/dyn/$sub"

Created /Users/Shared/sibling_verify/dyn/r./ with no prompt. The actual filesystem operation is identical to a literal mkdir "/Users/Shared/.../r." (which fires), but because the r. is constructed at runtime from printf, the scanner doesn't see it.

This means the scanner is functionally a UX hint, not a security boundary - any motivated user (or AI tool call) can route around it with one line of shell. Worth knowing for fix prioritization.

Bug #2 ("Always allow doesn't persist") - additional finding

The original report covers the disk-persistence failure. Additional behavior verified: session-memory scope is also broken. After clicking option 2 ("Yes, and always allow access to scanner-test/ from this project") on a mkdir scanner-test/q. prompt, subsequent mkdir scanner-test/rs. and mkdir scanner-test/UPPER. commands inside the same folder still prompted with the scanner. Option 2 is effectively a relabeled "option 1 (Yes)" - it neither persists to disk nor caches in session memory.

Bug #3 ("Pre-installed allow-rules ignored") - confirmed on real account

Manually adding the following rules to <project>/.claude/settings.local.json:

"Write(//Users/josejimenezjr./**)",
"Write(/Users/josejimenezjr./**)",
"Bash(echo SCANNER_PROBE:*)"

then running echo SCANNER_PROBE_BASH > /Users/josejimenezjr./scanner_probe.txt - scanner still fires. Confirms scanner runs above the allow-list resolution layer entirely.

nwjdesigns · 4 months ago

Hitting this on macOS — same root cause but with a folder-name pattern rather than username. My organisational top-level folder is ~/Desktop/2026/MR./ (a two-letter initialism with a trailing dot, used across many projects under it), so every Edit/Write tool call against any file under that tree triggers the "suspicious Windows path pattern" prompt. Confirming the OP's findings: auto/bypass mode does not suppress it, and pre-installed allow-rules in .claude/settings.local.json are ignored — the scanner runs above the permission layer.

This looks like a platform-detection oversight rather than an intentional cross-platform check. The patterns the scanner is matching (trailing-dot path segments, drive-letter-style fragments) are only meaningful constraints on Windows — on macOS they're fully legal path components with no special filesystem handling. The fix looks like a one-liner: gate the scanner on process.platform === 'win32' so it only runs on hosts where these patterns are actually constrained. Failing that, a permissions.disablePathHeuristics setting in settings.json would let users opt out per-project on platforms where this is a known false-positive.

Renaming the folder isn't a workable mitigation here — it's a top-level org folder with years of project files under it, including Adobe apps that store linked-asset references. The expectation is that legitimate macOS path conventions don't get blocked by a Windows-targeted heuristic.

josejimenezjr0 · 3 months ago

Bumping this off stale. Still reproduces on 2.1.143 (latest as of today), which is 27 releases past the version this was first reported on. None of the changelog entries between 2.1.124 and 2.1.143 reference the scanner, path heuristics, or the permission-layer code this lives in.

Status snapshot:

  • Filed 2026-04-30 on 2.1.123
  • 2.1.143 released 2026-05-15, still reproduces
  • No maintainer engagement on the thread to date
  • Confirmed by another user in this thread with a completely different folder pattern (~/Desktop/2026/MR./), so the bug is not specific to usernames containing .
  • Pinned to 2.1.116 with DISABLE_UPDATES=1 since the original report to keep the CLI usable, which means missing every fix shipped since 2026-04-20 (memory-leak fixes in 2.1.121, MCP OAuth fixes, session-corruption recovery)

Also routed through /feedback to the internal channel in parallel.

Looking for a triage acknowledgment. The triage notes, refined regex hypothesis, version-drift table, and trivial-bypass proof are all above. The proposed fix from the thread (gate the scanner on process.platform === 'win32', or revert to the pre-2.1.117 narrow regex) is small.

sshahzaiib · 2 months ago

Still reproduces on 2.1.173 (macOS, username shahzaiba.) — same behavior as OP: the scanner fires before permissions.allow is evaluated, so no rule syntax (bare, // absolute, ~/, wildcard) suppresses the prompts. Adding a data point and a working escape hatch for anyone who can't wait for a fix.

Full write-up with copy-pasteable script and migration commands: https://gist.github.com/sshahzaiib/6bb119164b87a8401915b203898f1185

Workaround that actually resolves it: rename the macOS account to drop the trailing dot

bypassPermissions is the only in-product workaround, but it's a blunt instrument. Renaming the account (shahzaiba.shahzaib) eliminates the false-positive entirely — and confirms the root cause is purely the <letter>./ segment matching the Windows drive-letter heuristic.

Rename procedure (summarized; standard macOS account rename):

  1. Back up, then fully log out of the affected account (FileVault auto-login counts as a GUI session — log out properly).
  2. From a second admin account: mv /Users/olduser. /Users/newuser, then dscl . -change /Users/olduser. NFSHomeDirectory ... and dscl . -change /Users/olduser. RecordName olduser. newuser.
  3. Create a compatibility symlink ln -s /Users/newuser /Users/olduser. for any configs still holding the old path. Password, Keychain, FileVault/SecureToken all survive (tied to the account UUID, not the name).

Claude Code state migration — the part that isn't obvious. Session history is keyed by path-encoded directory names, so after the rename all prior sessions disappear from /resume until you migrate:

  • ~/.claude/projects/: rename each -Users-olduser--<project> dir to the new encoding, and rewrite /Users/olduser./Users/newuser inside the session .jsonl files.
  • Rewrite the same paths in ~/.claude/history.jsonl, ~/.claude.json (project keys — watch for a duplicate key if you've already launched once from the new path), ~/.claude/settings.json, and ~/.claude/plugins/*.json.
  • Restart Claude Code afterwards so it doesn't write stale in-memory state back to ~/.claude.json.

Result

After the rename, with defaultMode: "auto" restored and path-scoped rules (Edit(~/Documents/dev/**), Write(~/Documents/dev/**)): zero prompts on Write, Edit, and read-only Bash under the allowed path. The exact same rules that were dead letters before the rename work immediately once the username has no period — there's nothing wrong with the rules themselves, only the scanner layer that pre-empts them.

Obviously an account rename is a drastic "fix" for a path-pattern regex, but until the scanner either anchors the drive-letter check to path starts (^[A-Za-z]:[\\/]) or runs after the allow-list, it's the only way to get the permission system working on these machines.

josejimenezjr0 · 1 month ago

Bump to remove stale. Still an issue