anthropics / anthropics/claude-code
[BUG] Native CLI install: macOS TCC network-volume grant keyed to versioned binary path — every auto-update silently drops SMB file access (EPERM)
- Dominant language
- Python
- Stars
- 145k
- Forks
- 23.1k
- PR merge metrics
- PR metrics pending
Description
## Environment
- Claude Code native CLI install: `~/.local/bin/claude` → `~/.local/share/claude/versions/` (symlink retargeted on each auto-update)
- claude-code 2.1.239, macOS Darwin 25.6.0
- SMB share mounted at `/Volumes/` (mount healthy, SMB 3.0.2)
## Symptom
After an auto-update, every file open on the SMB volume from a Claude Code session fails with `EPERM: Operation not permitted` — Bash children (`cat`, `head`, `touch`) and the native Read tool alike. Directory listing and `stat` still succeed, and the share is fine from other apps. Signature is a classic macOS TCC denial of `kTCCServiceSystemPolicyNetworkVolumes`.
## Root cause
TCC keys the network-volumes grant to the executable path, and the native installer gives every version its own path. From the user TCC.db (`service='kTCCServiceSystemPolicyNetworkVolumes'`):
```
~/.local/share/claude/versions/2.1.207 | allowed | 2026-07-13
~/.local/share/claude/versions/2.1.215 | allowed | 2026-07-21
~/.local/share/claude/versions/2.1.226 | allowed | 2026-08-11
```
Three separate grants, one per version the user happened to re-approve — and none for the currently running 2.1.239, so file opens deny. The grant dates line up with update days: each update invalidates the previous approval and macOS treats the new binary as a brand-new app.
## Why it bites hard
- In headless/agentic use (hooks, subagents, long unattended sessions) the TCC consent prompt is never answered, so the failure is a silent EPERM with no hint of the cause. `ls` succeeding while `cat` fails sends debugging toward SMB/server problems instead of TCC.
- Updates are frequent, so users working off NAS/SMB volumes re-approve permissions every few days or lose access without noticing.
## Repro
1. Native CLI install on macOS; mount any SMB share; grant network-volume access when prompted; confirm reads work.
2. Let claude auto-update to a new version.
3. Same session workflow: `head -c1 /Volumes//` → `Operation not permitted`; `ls -la` on the same file succeeds.
## Suggested fix
Give TCC a stable identity across updates — e.g. sign the versioned binaries with a consistent code-signing identifier (TCC can then key on signature rather than path), or execute via a stable non-versioned binary path. The desktop app avoids this because its bundle path/identifier is stable.
Related but distinct: #75374 (updater deletes the *old* version dir under a running session, breaking TCC attribution for that session). This report is about the *new* version never inheriting the grant, affecting every fresh session after every update.
## Workaround
Access the share's backing host over SSH instead of the local mount, or manually re-approve in System Settings → Privacy & Security → Files & Folders after each update.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start by tracing the native installer’s auto-update path and how ~/.local/bin/claude launches the versioned binary on macOS. Reproduce the SMB read failure across an update and inspect whether the new executable keeps a stable signing identity or path-based TCC attribution. Done means a fresh post-update session can access the mounted volume without manual re-approval.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- macos
- Domain
- cli, operating-systems, security
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100