TCC permission grants lost on every auto-update: native installer gives each release a new absolute binary path (bare Mach-O, no bundle)

Status Open
Reported on v2.1.218
Maintainer reply None cached
Activity 3 comments · opened Jul 24, 2026

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)

  1. macOS TCC keys a bare Mach-O CLI binary by absolute path (client_type=1).
  2. The native installer writes every release to a new path: ~/.local/share/claude/versions/<version>, then repoints the ~/.local/bin/claude symlink.
  3. Each update is therefore a brand-new TCC client with zero inherited grants → full re-prompt cycle.
  4. 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.

View original on GitHub ↗

3 Comments

jantichy · 1 month ago

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:

"2.1.231" wants access to files in your Documents folder.

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:

  1. Deny. The user does the security-literate thing and refuses. Claude Code then fails on Documents paths, and per #86091 the failures surface as opaque EPERMs rather than "you denied this permission" — so the user has no path back from a decision they made for good reasons.
  2. Allow. The user gets conditioned to approve filesystem prompts from unidentifiable clients, because that is what working with this tool requires. Multiply by the re-prompt cadence documented here (2–100/day in #87144) and you have systematic desensitization to exactly the dialog macOS built to be a deliberate decision point.

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 —

~/.local/share/claude/versions/2.1.231/claude

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.

Pross · 14 days ago

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:

  • 19:12:47: 2.1.287 installed
  • 19:13:23: bg daemon starts a 2.1.287 spare (claude bg-pty-host … --bg-spare)
  • 19:13:40: kTCCServiceSystemPolicyAppDataDetailed for com.google.Chrome from com.anthropic.claude-code (2.1.287), denied
  • 19:13:41: the same process runs osascript against 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.

Pross · 14 days ago

Correction to my comment above: the "control iTerm" prompt came from my own iTerm status hook (iTerm's it2 helper running osascript inside 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.