TCC permission grants lost on every auto-update: native installer gives each release a new absolute binary path (bare Mach-O, no bundle)
Summary
On macOS, Claude Code installed via the native installer re-prompts for TCC permissions ("would like to access data from other apps" / "wants to access files managed by iCloud Drive") after every auto-update — several times a day for active users. The prompt also shows the raw version number (e.g. "2.1.218") instead of "Claude Code".
Root cause (confirmed against the TCC database on macOS 26.5 / Darwin 25.5.0)
- macOS TCC keys a bare Mach-O CLI binary by absolute path (
client_type=1). - The native installer writes every release to a new path:
~/.local/share/claude/versions/<version>, then repoints the~/.local/bin/claudesymlink. - Each update is therefore a brand-new TCC client with zero inherited grants → full re-prompt cycle.
- The version number appears in the prompt because the installer ships a bare executable with no app bundle / Info.plist, so macOS falls back to the filename for the client display name.
Evidence
- Signature-keyed TCC rows (
client_type=0,com.anthropic.claude-code) were written and survive updates, but macOS never consults them for a non-bundled binary: versions 2.1.216, 2.1.217, and 2.1.218 each still minted a fresh path-keyed client and re-prompted. - Related open issues: #51911, #53703, #60211, #66216, #76615.
Impact
Users granting Full Disk / Files-and-Folders / cross-app access must re-approve multiple prompts per day. Some users disable the auto-updater (DISABLE_AUTOUPDATER=1) solely to stop the prompts, forfeiting security updates.
Requested fix
Install the executing binary at a stable path (e.g. ~/.local/share/claude/current/claude, updated atomically in place or via a stable hard link that TCC resolves consistently), and/or ship a minimal app bundle with an Info.plist + stable code-signing identity so TCC keys grants by signature rather than by per-version path. Either makes grants survive updates and fixes the display name.
Environment
macOS 26.5 (Darwin 25.5.0), Apple Silicon; Claude Code native installer, auto-update enabled; observed across 2.1.216 → 2.1.218.
3 Comments
Confirming on 2.1.231 / macOS 26 (Darwin 25.5.0), native installer.
One angle that I think is under-weighted across this issue and its relatives: the discussion frames the display-name problem mostly as friction — the same dialog over and over. But the more serious cost is what the anonymous dialog teaches users.
The prompt reads, verbatim:
An unrecognizable numeric string asking for Documents access is the exact shape of a prompt users are trained — correctly — to deny. So the outcomes split two ways, and both are bad:
EPERMs rather than "you denied this permission" — so the user has no path back from a decision they made for good reasons.The re-prompt frequency and the missing display name compound each other: high-frequency prompts are precisely the ones users stop reading, and these are the ones carrying no identity to read in the first place.
Worth noting the fix ordering, since the two halves are separable. The signed-bundle fix proposed here resolves both at once and is clearly right. But if that is a larger packaging change, the display name can be fixed independently and cheaply: move the version into the directory rather than the filename —
TCC's filename fallback then yields
"claude"instead of"2.1.231". Grants still don't survive updates, so this is not a substitute for the bundle work — but a user re-approving"claude"is making an informed decision, while a user re-approving"2.1.231"is not. That seems worth decoupling if the bundle change has a longer runway.Same on macOS 27 with the native installer, daily. Files & Folders now lists 14 separate entries for one app: 2.1.257, 2.1.273–2.1.278, 2.1.280–2.1.284, 2.1.286, 2.1.287. The tccd subject is the versioned path (
~/.local/share/claude/versions/<ver>), so every update starts from scratch.Timing on 2026-10-01 shows the update itself triggers it, with no session in use:
claude bg-pty-host … --bg-spare)kTCCServiceSystemPolicyAppDataDetailedforcom.google.Chromefromcom.anthropic.claude-code(2.1.287), deniedosascriptagainst iTerm, which shows an Automation prompt (filed separately as #98783)The same Chrome app-data request fired on 2026-09-28 at 19:03:37 right after 2.1.284 installed.
Correction to my comment above: the "control iTerm" prompt came from my own iTerm status hook (iTerm's
it2helper runningosascriptinside background sessions), not from Claude Code, so I've closed #98783. The rest stands: the Chrome app-data request comes from Claude Code itself, and grants are lost on every update because of the versioned path.