Bundled Claude Code binary at a version-numbered path re-triggers macOS TCC permission prompts on every desktop app update

Status Open
Reported on v2.1.247
Maintainer reply None cached
Activity 0 comments · opened Aug 30, 2026

Summary

The Claude Code binary bundled inside the Claude desktop app lives at a version-numbered path:

~/Library/Application Support/Claude/claude-code/<version>/claude.app/Contents/MacOS/claude

macOS TCC keys privacy grants to the executable path. Because the version is in the path, every desktop app update produces a binary at a path with zero grants, and the user gets a fresh burst of permission dialogs — one per file provider (Dropbox, iCloud, Google Drive, each mounted volume), plus Downloads/Desktop/Documents, Calendar, and each Apple Events target.

Impact

For a user with several cloud providers mounted this is 6-10 modal dialogs after every update. They appear at the first file access, which for anyone running Claude Code on a schedule means a stack of dialogs waiting at the start of the day. Clicking Allow does not help the next update.

It also silently accumulates dead TCC rows — one block per version, permanently. On this machine ~55 rows across four abandoned version paths had built up before being pruned by hand.

Why the obvious workarounds don't work

  • Granting Full Disk Access to /Applications/Claude.app does not cover it. The bundled binary is attributed as its own client, not as the parent app. Verified: the app had FDA and the prompts still fired.
  • Pinning a stable path with a hardlink works for the standalone CLI install (~/.local/bin/claude), but is not possible here — the desktop app owns that directory and recreates it on update.
  • Auto-approving via a launchd job cannot work, since writing TCC.db itself requires Full Disk Access, which launchd-spawned shells do not have.

Suggested fix

The binary is already Developer ID signed with a stable identity (com.anthropic.claude-code, Team Q6L2SF6YDW), so grants would carry across updates for free if the executable lived at a version-independent path, e.g.:

~/Library/Application Support/Claude/claude-code/current/claude.app/...

with the version directory referenced internally rather than in the executable path. This is how normal auto-updating apps avoid re-prompting.

Environment

  • macOS 26.x (Darwin 25.6.0), Apple Silicon
  • Claude desktop app with bundled Claude Code 2.1.247
  • Also reproduced on the standalone CLI install before it was pinned to a fixed path

Note

The same class of bug affects the standalone installer: ~/.local/bin/claude symlinks directly into ~/.local/share/claude/versions/<version>, so it re-prompts on every update too. A hardlink to a fixed path fixes that one locally, but only if the versioned name is then removed — while both names exist on the same inode, the kernel can still attribute the process to the versioned path.

View original on GitHub ↗