macOS TCC popup still recurring on v2.1.153 — "2.1.153" would like to access data from other apps

Status Open
Reported on v2.1.153
Maintainer reply None cached
Activity 5 comments · opened May 28, 2026

Description

The macOS TCC permission dialog keeps appearing with the message:

"2.1.153" would like to access data from other apps.

This is still happening on v2.1.153 running macOS Sequoia 15.4 (Darwin 25.2.0, arm64).

Current permissions already granted

  • Privacy & Security > Automation: claude → System Events ✅ (toggled on)
  • Privacy & Security > Files & Folders: claude → Full Disk Access listed

Despite these permissions being granted, the popup keeps appearing.

Root cause

The CLI binary lives at ~/.local/share/claude/versions/2.1.153 and the symlink at ~/.local/bin/claude points to it. Since the binary path changes with every version update, macOS treats each version as a new, unrecognized binary and:

  1. Shows the version number ("2.1.153") instead of a human-readable name like "Claude Code"
  2. Invalidates previously granted TCC permissions

Prior issues (all closed/locked)

  • #27322
  • #36675
  • #36832
  • #41297

Suggested fix

  • Wrap the CLI in a proper .app bundle with CFBundleName / CFBundleDisplayName, or
  • Use a stable binary path that doesn't change per version (let the symlink be the canonical identity), or
  • Code-sign the binary with a consistent team identity so macOS recognizes it across versions

Environment

  • Claude Code: 2.1.153
  • macOS: Sequoia 15.4 (Darwin 25.2.0)
  • Architecture: arm64

View original on GitHub ↗

4 Comments

drmalcs · 3 months ago

This is really two bugs and I see both (mac tahoe 26.5) every time my Claude tries to run a hook which backs up my ~/.claude/ to my Gdrive via a script that uses rclone:

  • pop up shows the Claude version number and not something recognisable (although recognisability could be spoofed so even if it did say "Claude - yessir, defo not some other program" is that actually more secure?
  • asking for permissions to access places that my script doesn't need access to e.g. removable drives

Steps to reproduce:

  1. Install Claude Code on macOS with an external/removable drive mounted.
  2. Configure a PostToolUse hook that runs any shell command (e.g. rclone sync).
  3. Trigger the hook by editing a file.
  4. Observe the TCC prompt — it shows the version number, not "Claude Code", and requests removable volume access.

Expected behaviour: Prompt should read "Claude Code wants access to…" and should only request the permissions actually
needed.

howie · 2 months ago

Still reproducing on v2.1.175 (macOS, Apple Silicon).

The Privacy & Security list now shows multiple orphaned entries named by
version number (e.g. 2.1.173, 2.1.175) alongside claude / Claude,
each needing Full Disk Access re-granted after every update. Granting FDA
to the terminal app (iTerm) does not stop it, since the responsible
process is the per-version claude binary.

The root cause and suggested fixes in the original report still apply.
A stable binary path (or a properly signed .app bundle with a consistent
identity) so macOS can persist the TCC grant across versions would solve this.

+1 / would appreciate this being prioritized.

mrg0114 · 2 months ago

Summary

macOS ties a TCC grant to the resolved path of the requesting executable. Claude Code installs each version under a version-specific directory:

  • CLI: ~/.local/share/claude/versions/<version>/
  • Desktop/Cowork embedded CLI: ~/Library/Application Support/Claude/claude-code/<version>/claude

Because that path changes on every update, macOS treats each new version as a new, unrecognized binary. The consequences:

  1. Previously granted TCC permissions are invalidated on every update, so the user must re-approve repeatedly.
  2. The consent dialog displays the bare version string (e.g., "2.1.153") instead of "Claude Code," so the user cannot tell what is requesting access.
  3. The grant also fails to persist within a version when the binary is reached through a wrapper/intermediary process, so the prompt can recur per session even without an update.

Separately, the embedded CLI inside Claude Desktop is code-signed with a different identity (com.anthropic.claude-code) than the desktop app (com.anthropic.claudefordesktop), so it does not inherit the Full Disk Access grant given to Claude.app — the user must grant access to the embedded binary separately, and that grant is then invalidated on the next Desktop update (per the version-path problem above).

This is especially visible when a skill/agent reads files that live inside another app's sandbox container (e.g., a NotePlan vault under ~/Library/Containers/co.noteplan.NotePlan3/Data/…), which is precisely the access that triggers the macOS "access data from other apps" dialog.

Steps to reproduce

  1. On macOS, grant the Claude Code CLI (or the Claude Desktop embedded CLI) Full Disk Access / approve the TCC prompt once.
  2. Have it read a file inside another app's container, e.g. ~/Library/Containers/co.noteplan.NotePlan3/Data/….
  3. Update Claude Code (or Claude Desktop) to a newer version.
  4. Repeat the same read.
  5. Observe the TCC consent dialog reappear, now naming the new version number, with the prior grant gone.

Expected results

  • The CLI presents a stable identity to macOS across versions (consistent code-signing identity and/or a canonical, version-independent executable path), so a TCC/Full Disk Access grant persists across updates.
  • The consent dialog shows a human-readable name ("Claude Code"), not a version string.
  • The Desktop embedded CLI inherits or shares the Full Disk Access identity of Claude.app, so it does not need to be authorized separately.

Actual results

  • Each update is treated as a new unrecognized binary; prior grants are discarded and the prompt recurs.
  • The dialog shows the bare version number.
  • The embedded CLI does not inherit Claude.app's Full Disk Access grant.

Suggested fixes

  1. Code-sign the CLI binary with a consistent team/identity so macOS recognizes it across versions.
  2. Use a stable, version-independent executable path as the canonical identity (e.g., let a fixed symlink/launcher be the executable macOS attributes, rather than the per-version directory).
  3. Wrap the CLI in a proper .app bundle with CFBundleName / CFBundleDisplayName so the consent dialog shows a readable name.
  4. Have the Claude Desktop/Cowork embedded CLI share or inherit the desktop app's TCC identity so a single Full Disk Access grant covers both.

Related reports

  • Existing GitHub issues (open/duplicated): #63130 (still recurring on v2.1.153), #36832, #27322, #36675, #41297.
  • Corresponding Apple Feedback Assistant report on the OS-side persistence/identification behavior: FB23381293.
yscheef · 1 month ago

Workaround that eliminates the prompts entirely until this is fixed properly.

Key observation: Anthropic signs every build with the same identity (com.anthropic.claude-code, team Q6L2SF6YDW), so the code-signing requirement (csreq) stored in existing TCC rows still matches each new binary. Only the path-keyed lookup fails. That means you can clone your existing grants to the new version path in the user-level TCC.db and macOS accepts them without re-prompting.

Script (needs a shell with Full Disk Access; I run it as a Claude Code SessionStart hook so it fires before anything can prompt):

#!/bin/bash
# claude-tcc-sync: clone TCC grants from previous Claude Code versions to the current one
set -euo pipefail

DB="$HOME/Library/Application Support/com.apple.TCC/TCC.db"
VDIR="$HOME/.local/share/claude/versions"
CUR=$(realpath "$HOME/.local/bin/claude" 2>/dev/null) || exit 0
[[ "$CUR" == "$VDIR"/* && -r "$DB" ]] || exit 0

COLS="service,client,client_type,auth_value,auth_reason,auth_version,csreq,policy_id,indirect_object_identifier_type,indirect_object_identifier,indirect_object_code_identity,flags,last_modified,pid,pid_version,boot_uuid,last_reminded"
SEL=${COLS/client,/"'$CUR' AS client,"}
SEL=${SEL/last_modified,/"MAX(last_modified) AS last_modified,"}

CHANGED=$(sqlite3 "$DB" "
INSERT OR IGNORE INTO access ($COLS)
SELECT $SEL FROM access
WHERE client LIKE '$VDIR/%' AND client != '$CUR'
GROUP BY service, indirect_object_identifier;
SELECT changes();")

# purge grants for uninstalled versions (cleans up the orphaned entries in System Settings too)
while IFS= read -r c; do
  [[ -e "$c" ]] || { sqlite3 "$DB" "DELETE FROM access WHERE client='$c';"; CHANGED=1; }
done < <(sqlite3 "$DB" "SELECT DISTINCT client FROM access WHERE client LIKE '$VDIR/%';")

# flush the user tccd cache so the new rows take effect
[[ "$CHANGED" != "0" ]] && pkill -U "$UID" tccd 2>/dev/null
exit 0

Notes:

  • Copies the newest answer per service (denials included) and per AppleEvents target, so it preserves whatever you actually clicked.
  • Also purges rows for uninstalled versions, which cleans the pile of orphaned "2.1.xxx" entries out of System Settings > Privacy & Security.
  • The column list matches the access table schema on macOS 26.x; adjust via PRAGMA table_info(access) on other versions.
  • Writing to the user TCC.db is unsupported by Apple. Worst case it silently stops working and you see one prompt per update again, i.e. the status quo.

Obviously the real fix belongs in the installer (stable path or proper .app bundle identity, as the OP suggests). Until then this makes updates silent.

Showing cached comments. Read the full discussion on GitHub ↗