Headless `claude -p` from a non-default-account session uses the machine-default Keychain credential (silent cross-account billing)

Open 💬 0 comments Opened Jun 30, 2026 by cb2206

Bug: headless claude -p ignores the session's account and uses the machine-default Keychain credential (silently bills the wrong account)

Environment

  • Claude Code version: 2.1.195
  • OS: macOS (Darwin)
  • Auth: claude.ai first-party OAuth (no ANTHROPIC_API_KEY set)
  • Two accounts on one machine via separate Claude Desktop instances:
  • Default Claude.appAccount P (personal subscription)
  • Second instance: open -n -a "/Applications/Claude.app" --args --user-data-dir="$HOME/.claude-instances/work"Account E (enterprise org)
  • The active Claude Code session runs as a child of the Account E Desktop instance.

Summary

From a Claude Code session authenticated as Account E, spawning a fresh headless
claude -p … (e.g. via the Bash tool or any shell) authenticates as Account P
the machine-default OAuth token in the macOS Keychain — not Account E. The mismatch is
silent, and claude auth status reports Account E, masking it. Usage, billing, and
rate limits are charged to the wrong account.

Steps to reproduce

  1. Log the default Claude.app / default claude CLI into Account P (writes the

OAuth token to Keychain service Claude Code-credentials).

  1. Launch a second instance into a separate data dir, logged into Account E:

open -n -a "/Applications/Claude.app" --args --user-data-dir="$HOME/.claude-instances/work"

  1. Start a Claude Code session inside the Account E instance.
  2. From that session run a headless command, e.g. claude -p "say hi" --output-format json.
  3. Observe which account is billed / rate-limited.

Expected

The headless claude -p subprocess authenticates as the session's account
(Account E), or fails loudly / warns on credential ambiguity.

Actual

  • The subprocess authenticates as Account P (machine-default Keychain token).
  • claude auth status reports Account E (it reads cached ~/.claude.json

oauthAccount metadata), so it does not reflect the credential actually used for
inference.

  • Account P hit its session/rate limit; Account E's usage meter did not change —

confirming the calls billed Account P.

Diagnosis (observed)

  • Token actually used for inference: macOS Keychain item service: "Claude Code-credentials"

(the machine default = Account P).

  • ~/.claude.json oauthAccount metadata = Account E (written because the Account E

instance shares $HOME); this is what claude auth status displays.

  • The session carries host-auth env signals (CLAUDE_CODE_CHILD_SESSION,

CLAUDE_CODE_SDK_HAS_HOST_AUTH_REFRESH), indicating it received Account E auth
in-memory from the host instance — but a newly spawned top-level claude process does
not inherit that and falls back to the Keychain default.

Impact

  • Silent cross-account billing / rate-limit consumption: a user working in an

enterprise-authenticated session can unknowingly spend a personal account's allotment
(or vice versa). Especially dangerous for headless/automated workflows launched from
within a session.

  • claude auth status is misleading — it shows the metadata account, not the credential

claude -p actually uses.

Suggested fixes

  • Child claude invocations should inherit the parent session's resolved credential

(credential/env handoff), or

  • claude -p should honor an explicit account selection and **warn when the session

account ≠ the credential it will use**, and

  • claude auth status should report the credential actually used for inference (the

Keychain token's account), not just ~/.claude.json metadata.

Workaround

Set an explicit credential for headless runs to bypass the ambiguous Keychain default:
ANTHROPIC_API_KEY=… claude -p …

Possibly related (but distinct) existing issues

  • #70124 — Stored /login credentials silently beat a valid CLAUDE_CODE_OAUTH_TOKEN

(auth-precedence theme).

  • #62338 — Claude Code silently billed API instead of Max subscription, then gave

incorrect auth confirmation (silent mis-billing + misleading auth status).

  • #68501 — Both Claude Desktop + standalone CLI installed → subscription usage silently

billed to Extra Usage (Desktop + CLI billing interaction).

This report differs: it is specifically about a claude -p child subprocess using the
machine-default Keychain credential instead of the account the parent session is
authenticated as, when two Desktop instances run under separate --user-data-dirs — with
claude auth status reporting the wrong (metadata) account and masking it.

View original on GitHub ↗