[BUG] Claude.app deletes & recreates keychain item on workspace open, dropping apple-tool: from partition list and causing recurring macOS prompts

Open 💬 1 comment Opened May 25, 2026 by Corrugator

Summary

When Claude.app opens a workspace, it triggers a write to the
Claude Code-credentials keychain item via a SecItemDelete +
SecItemAdd
sequence rather than SecItemUpdate. The freshly added
item ships with a minimal partition list that no longer contains
apple-tool:, so any subsequent /usr/bin/security call against the
item — by system services, the desktop app's own components, or
third‑party tools — triggers a macOS "security wants to access" dialog.

Clicking "Always Allow" only adds the calling binary to the *application
list, not apple-tool: to the partition list*, so the prompt returns
the next time a different binary makes a /usr/bin/security call. The
only permanent recovery is the user manually re‑running
security set-generic-password-partition-list -S apple-tool:,apple:,…
which itself gets undone the next time Claude.app opens a workspace.

Same root cause as #22144 (closed as not planned). Filing again as a bug
report because I now have a deterministic reproducer with raw log
timestamps showing the partition‑list mutation in real time.

Reproducer (verified twice in 13 min on my machine)

I wrote a passive watcher that polls the keychain item's partition_id
description and mdat every 30 s via security dump-keychain — metadata
only, no ACL decrypt, so the watcher itself never triggers a prompt.
I then opened a new workspace in Claude.app while watching.

Event 1 (11:56 CEST, ~10 s after opening a workspace):

11:56:25  PARTITION LIST CHANGED
          was: cdhash:44a5a8…, apple-tool:
          now: cdhash:44a5a8…
          !! apple-tool: was REMOVED — /usr/bin/security calls will prompt now
11:56:35  keychain item rewritten (mdat changed)
          was: 20260525015645Z
          now: 20260525095609Z

Event 2 (12:08 CEST, ~5 s after opening another workspace) — shows
the underlying delete+add pattern across two consecutive polls:

12:08:57  PARTITION LIST CHANGED   was: cdhash:44a5a8…   now: <missing>
12:09:45  PARTITION LIST CHANGED   was: <missing>        now: cdhash:44a5a8…

The item was completely absent from the keychain for ~48 s between
those two polls, confirming the rewrite goes through SecItemDelete
then SecItemAdd rather than SecItemUpdate. Each event correlated
with active processes:

  • /Applications/Claude.app/Contents/MacOS/Claude (the desktop app)
  • …/claude-code/2.1.149/claude.app/Contents/MacOS/claude (the bundled

CLI that Claude.app shells out to for code workspaces)

Downstream symptom: wake‑from‑sleep prompts

The partition list reset persists across sleep/wake cycles. My watcher
captured 3 sleep/wake cycles (gaps of +152 s, +230 s, +514 s) over 2 h
following a single workspace‑open rewrite. Partition list stayed
cdhash:… (no apple-tool:) the entire time — no further keychain
mutations
. On the last wake, the user got a "security wants to access"
prompt despite not having touched Claude.app since the morning. The
wake itself doesn't mutate the keychain; some background service simply
made a /usr/bin/security call against the already‑broken partition
list.

This is why end users perceive the issue as "random prompts after
opening the Mac" rather than "after I opened a workspace": the cause is
many hours before the symptom. They never make the connection — they
blame the third‑party tool that happened to call security at wake
time.

Why this matters

I'm shipping a Stream Deck plugin ("Usage Monitor for Claude Code",
currently in Elgato marketplace review) that reads the rate‑limit
headers from /v1/messages to surface session and weekly usage on a
physical button. Real end users will hit this every time they open a
workspace in Claude.app:

  • They click Always Allow + type their login password
  • A few hours later, on next wake or next workspace switch, the same

prompt returns

  • They reasonably blame the third‑party plugin

I've already mitigated my read path: my plugin uses a bundled,
ad‑hoc‑signed Swift helper that talks to Security.framework directly,
so the helper's CDHash survives in the partition list and its own
polling is silent. But anything else on the user's system that uses
/usr/bin/security against this item (system services on wake, the
Claude.app's own components on some code paths, other third‑party tools
they install) still prompts — because the partition list has been left
in a broken state.

Asked‑for fix, in decreasing order of "would unblock us"

  1. Use SecItemUpdate instead of SecItemDelete + SecItemAdd for

the keychain write path. This is the proper API for rotating the
stored data while preserving the existing ACL and partition list.
Existing third‑party trust and apple-tool: survive across token
rotations and workspace opens. Smallest possible patch, fixes the
issue completely.

  1. If a fresh add is unavoidable, include apple-tool: (and ideally

merge in the previous partition list values, if any can be read
before the delete) when constructing the new item with
kSecAttrAccessControl. This silences /usr/bin/security for every
existing third‑party integration with zero API additions.

  1. Either of the options from #22144 (cache file at

~/.claude/usage-cache.json, or a claude auth token export
command) as a long‑term cleaner API surface — but (1) is so much
smaller that it should land first regardless.

Happy to provide more diagnostics, the raw watcher script, or test
patches against the macOS keychain layer.

Environment

  • macOS Tahoe (Darwin 26.5.0)
  • Claude Code CLI 2.1.149
  • Claude.app 1.8555.2
  • Watcher script + complete raw log available on request.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗