Auto-updater leaves orphan TCC entries for every previous CLI version on macOS
Bug report — paste into https://github.com/anthropics/claude-code/issues
Title: Auto-updater leaves orphan TCC entries for every previous CLI version on macOS
---
Summary
The Claude Code CLI bundled with the Claude Desktop app (macOS) installs each new version into a versioned subdirectory:
~/Library/Application Support/Claude/claude-code/<VERSION>/claude.app
When a new version is staged, the user is re-prompted for the privacy permissions that the prior version had already been granted (Accessibility, AppleEvents/Automation, Files & Folders, Removable Volumes, etc.). Each grant becomes a new path-based row in macOS's TCC database. The updater never tells macOS to revoke the prior version's rows, so they accumulate as orphans whose binary no longer exists on disk.
After ~13 CLI version updates on my system, ~70 orphan rows had piled up across multiple Privacy & Security panels, plus one in the system-level TCC.db. The Privacy & Security panels (Files & Folders, Automation, Local Network, etc.) showed dozens of blank-icon "claude" / "claude.app" entries.
The homebrew install path (/opt/homebrew/lib/node_modules/@anthropic-ai/claude-code/bin/claude.exe) does not exhibit this — its path is stable across updates and TCC reuses the row.
Reproduction
- Use Claude Desktop and let the embedded CLI auto-update through ~5+ versions.
- Open System Settings → Privacy & Security → Files & Folders (or Automation, Local Network, Full Disk Access).
- Observe multiple blank-icon "claude" / "claude.app" entries, each corresponding to an old version's install path.
Verify in the TCC database:
sqlite3 -header -column ~/Library/Application\ Support/com.apple.TCC/TCC.db "
SELECT service, client, client_type
FROM access
WHERE client LIKE '/Users/%/Library/Application Support/Claude/claude-code/%/claude'
AND client_type = 1;
"
(Requires Full Disk Access on the running shell.)
Expected behavior
When the auto-updater stages a new version and removes the previous one, it should:
Option A — Call tccutil for each TCC service the old version had records in:
tccutil reset SystemPolicyDocumentsFolder /Users/.../claude-code/<OLDVER>/claude
tccutil reset SystemPolicyDesktopFolder /Users/.../claude-code/<OLDVER>/claude
…
(Though note: tccutil reset resets by bundle ID, not arbitrary path, so this may require direct DB manipulation by an entitled helper.)
Option B — Install at a stable, versioned-via-symlink path:
~/Library/Application Support/Claude/claude-code/current/claude.app ← symlink to versioned dir
…and request TCC permissions only via the current path. New versions update the symlink target; TCC keys reuse.
Workaround (mitigation, not a fix)
I've automated cleanup on my machine via a launchd agent that runs monthly. It:
- Enumerates path-based TCC rows under
~/Library/Application Support/Claude/claude-code/*/claude - Tests whether each path still exists on disk
- DELETEs rows for missing paths
This requires the running script to have Full Disk Access. It does not clean the system-level TCC.db (would need root).
The script and launchd plist are local — happy to share if useful.
Environment
- macOS: <fill in:
sw_vers -productVersionand build> - Claude Desktop version: <Settings → About>
- Embedded CLI version: <
~/Library/Application Support/Claude/claude-code/<current>/claude --version> - Homebrew npm-installed CLI version (if applicable): <
claude --version>
Severity
Cosmetic / quality of life, not a security issue per se — the orphan rows are inert because their code-signing anchors are broken. But the Privacy & Security panels become very hard to audit when filled with phantom rows, and most users have no straightforward way to clean them (the macOS UI offers no per-row delete on Automation/Files & Folders/Local Network).
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗