Skip to content

fix(claude-auth): refuse stale same-identity credential overwrites - #13568

Open
brennanb2025 wants to merge 1 commit into
mainfrom
brennanb2025/issue-13165-claude-credential-freshness
Open

fix(claude-auth): refuse stale same-identity credential overwrites#13568
brennanb2025 wants to merge 1 commit into
mainfrom
brennanb2025/issue-13165-claude-credential-freshness

Conversation

@brennanb2025

Copy link
Copy Markdown
Contributor

Summary

Screenshots

No visual change

Testing

  • pnpm lint (focused oxlint on changed files)
  • pnpm typecheck (pnpm run typecheck:node)
  • pnpm test (full suite not run)
  • pnpm build
  • Added or updated high-quality tests that would catch regressions, or explained why tests were not needed

Focused validation:

  • pnpm exec vitest run --config config/vitest.config.ts src/main/claude-accounts/credential-freshness.test.ts src/main/claude-accounts/runtime-auth-service.test.ts — pass, 117 tests
  • pnpm run typecheck:node — pass
  • pnpm exec oxlint on touched files — pass
  • pnpm exec oxfmt --check on touched files — pass

AI Review Report

Surface is main-process Claude managed-account runtime auth. Guard is structural (identity + expiresAt) with no token-family heuristics or secret logging. Extra cost is one best-effort read of file/keychain stores immediately before materialize and managed writes; no startup path changes beyond existing constructor sync. Electron UI/renderer untouched.

Security Audit

No new secret surfaces, IPC, or subprocesses. Tests use temp homes and fake keychain adapters only. No real ~/.claude or Keychain access. Fail-open on unreadable runtime files so permission issues still allow atomic rewrite.

Notes

Safe repro (synthetic only):

  1. Temp home with .credentials.json / fake keychain holding same-email creds at expiresAt=9000.
  2. Managed account snapshot for that email at expiresAt=1000.
  3. Select managed account and syncForCurrentSelection().
  4. On main without this fix: shared runtime is overwritten with the expired snapshot. With the fix: runtime stays at 9000 and managed adopts the fresher copy.

Root cause: Unconditional materialization writers (writeRuntimeCredentials, writeActiveClaudeKeychainCredentialsForRuntime, managed keychain/file) could land an older same-identity snapshot over a fresher multi-writer store.

QA gaps: No live multi-process Claude CLI race on real Keychain; no Electron E2E of account switch UI; SSH host path not separately exercised (shares same service code). Cross-process TOCTOU with an external writer between read and write remains possible but window is minimized.

ELI5

Orca sometimes copied an old Claude login over a newer one and kicked you out. It now checks which copy expires later and keeps the fresher one when both belong to the same account.

Shared Claude runtime stores (file + keychain) are multi-writer. Guard
managed materialization with expiresAt monotonicity so an older managed
snapshot cannot clobber a fresher login, and adopt the fresher copy back
into managed storage. Force-write still applies after re-auth.

Closes #13165
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@brennanb2025, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 13 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6366f8fc-aefb-4f47-8527-c1ae01374754

📥 Commits

Reviewing files that changed from the base of the PR and between 6cdd019 and 4b50a2d.

📒 Files selected for processing (4)
  • src/main/claude-accounts/credential-freshness.test.ts
  • src/main/claude-accounts/credential-freshness.ts
  • src/main/claude-accounts/runtime-auth-service.test.ts
  • src/main/claude-accounts/runtime-auth-service.ts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant