Skip to content

auth remove openai-codex can re-seed a new device_code credential from ~/.codex/auth.json #12747

@NewTurn2017

Description

@NewTurn2017

Summary

hermes auth remove openai-codex <target> can leave an extra device_code credential behind when ~/.codex/auth.json exists. The removal path calls load_pool(), and load_pool() auto-imports Codex CLI tokens into the Hermes auth store before the target credential is removed.

This means a command that should only delete one pool entry can also mutate ~/.hermes/auth.json by seeding a new singleton entry from the external Codex CLI state.

Affected files / lines

  • hermes_cli/auth_commands.py:303-315auth_remove_command() resolves the target via load_pool(provider)
  • agent/credential_pool.py:1341-1363load_pool() always runs singleton seeding before removal
  • agent/credential_pool.py:1155-1189_seed_from_singletons() imports ~/.codex/auth.json into providers.openai-codex / credential_pool.openai-codex

Why this is a bug

auth remove is expected to remove exactly the requested credential. Instead, on machines where Codex CLI is logged in, the command can persist a fresh device_code entry that the user did not ask to add.

Two concrete bad outcomes:

  1. Removing a label-targeted manual entry still leaves two credentials in the pool (the surviving manual entry + an imported singleton).
  2. Removing target 2 can act on the wrong logical set of credentials because load_pool() has already injected an extra seeded entry into the pool state.

Minimal reproduction

  1. Create ~/.hermes/auth.json with two manual openai-codex pool entries (work-account, personal-account).
  2. Create ~/.codex/auth.json with a valid Codex access/refresh token pair.
  3. Run hermes auth remove openai-codex personal-account.
  4. Inspect ~/.hermes/auth.json.

Actual behavior

The command prints that it removed personal-account, but the resulting pool still contains:

  • work-account
  • a newly imported device_code entry seeded from ~/.codex/auth.json

I reproduced this locally with a fully isolated temp HERMES_HOME + temp CODEX_HOME; after auth_remove_command(), the pool persisted:

  • work-account (manual:device_code)
  • codex@example.com (device_code)

The selected test chunk also reproduces this on default-branch main:

  • pytest -q tests/hermes_cli/test_auth_commands.py ...
  • failing tests:
    • test_auth_remove_accepts_label_target
    • test_auth_remove_prefers_exact_numeric_label_over_index

Expected behavior

auth remove should only remove the requested credential and should not auto-import external Codex CLI credentials as a side effect.

Suggested investigation direction

Possible fix directions:

  • Make auth_remove_command() operate on the persisted pool entries without triggering singleton seeding/import.
  • Or teach load_pool() / _seed_from_singletons() to skip Codex CLI auto-import for destructive management commands like auth remove.
  • At minimum, prevent openai-codex singleton seeding from mutating the pool during target resolution.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions