Skip to content

auth.json writes are racy and a single corrupt read wipes all provider credentials #54

Description

backend/cli/src/auth/index.ts has two problems that combine badly:

  1. set()/remove() are unlocked read-modify-write over auth.json, and Bun.write is not atomic (truncate then write).
  2. all() swallows parse errors and returns {}.

Reproduced:

A) after concurrent sets — providers on disk: [ "provider-a", "provider-b" ]
A) lost: [ "provider-c" ]
B) corrupt auth.json reads as {}
B) after one Auth.set on the corrupt file: { "openai-codex": {...} }   <- anthropic key GONE

Failure scenarios:

  • a Codex token refresh persists rotated tokens at the same moment the user logs into another provider; one credential silently vanishes
  • a torn read during a concurrent write, or a disk-full truncation, makes all() return {}; the next routine token refresh then rewrites auth.json containing only itself, permanently destroying every other provider credential with no warning

This is the persistence layer underneath the codex rotation fix from #20, so the cross-process race that fix targets can still destroy state one level down. The same unlocked pattern exists in backend/cli/src/mcp/auth.ts (mcp-auth.json).

Fixes: write via temp file + rename, take a file lock (the repo already has a Lock util used by BunProc.install), and treat an unparseable auth.json as fatal for writes (back it up and refuse) instead of as {}.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions