fix(auth): prevent unauthorized Claude Code credential usage in auxiliary fallback chain#7009
Closed
wanpengxie wants to merge 4 commits into
Closed
Conversation
Gate function for checking whether a user has explicitly selected a provider via hermes model/setup, auth.json active_provider, or env vars. Used in subsequent commits to prevent unauthorized credential auto-discovery. Follows the pattern from PR NousResearch#4210. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…er config
_seed_from_singletons('anthropic') now checks
is_provider_explicitly_configured('anthropic') before reading
~/.claude/.credentials.json. Without this, the auxiliary client
fallback chain silently discovers and uses Claude Code tokens when
the user's primary provider key is invalid — consuming their Claude
Max subscription quota without consent.
Follows the same gating pattern as PR NousResearch#4210 (setup wizard gate)
but applied to the credential pool seeding path.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Previously, removing a claude_code credential from the anthropic pool only printed a note — the next load_pool() re-seeded it from ~/.claude/.credentials.json. Now writes a 'suppressed_sources' flag to auth.json that _seed_from_singletons checks before seeding. Follows the pattern of env: source removal (clears .env var) and device_code removal (clears auth store state). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…configured _resolve_api_key_provider() now checks is_provider_explicitly_configured before calling _try_anthropic(). Previously, any auxiliary fallback (e.g. when kimi-coding key was invalid) would silently discover and use Claude Code OAuth tokens — consuming the user's Claude Max subscription without their knowledge. This is the auxiliary-client counterpart of the setup-wizard gate in PR NousResearch#4210. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Contributor
|
Merged via #7156. Your defense-in-depth credential gate was cherry-picked with authorship preserved (4 commits). The CLAUDE_CODE_OAUTH_TOKEN exclusion was a particularly nice touch. Thanks, @wanpengxie! |
|
pero una pregunta en la terminal si funciona pero por medio de telegram manda el error de api como se soluciona via hermes gateway |
CybercodeXx
pushed a commit
to CybercodeXx/hermes-agent
that referenced
this pull request
Apr 17, 2026
Scenario: user configures kimi-coding with a malformed API key. When the main agent fails and auxiliary fallback runs, the fix must prevent _try_anthropic() from silently reading ~/.claude/.credentials.json. 9 tests covering all three vulnerable paths from PRs NousResearch#7009/NousResearch#7156: A. _seed_from_singletons() — credential pool gate B. _resolve_api_key_provider() — auxiliary client fallback chain C. suppress_credential_source() — re-seed prevention after auth remove Also verifies CLAUDE_CODE_OAUTH_TOKEN (implicit) vs ANTHROPIC_API_KEY (explicit) are distinguished correctly by is_provider_explicitly_configured(). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
_seed_from_singletons("anthropic")behindis_provider_explicitly_configured()— Claude Code credentials are no longer auto-discovered when the user never selected anthropicsuppressed_sourcesmechanism toauth.json—hermes auth removenow prevents re-seeding of removedclaude_codeentries_resolve_api_key_provider()— auxiliary fallback chain skips anthropic when not explicitly configuredProblem
When a user configures a non-anthropic provider (e.g. kimi-coding) with an invalid API key, the auxiliary client fallback chain silently discovers and uses
~/.claude/.credentials.jsonwithout consent. This:user-agent: claude-cli,anthropic-beta: claude-code-20250219)~/.claude/.credentials.json, potentially disrupting Claude Code's own auth (scopes field loss causes Claude Code to report "not logged in" — see PR fix(anthropic): write scopes field to Claude Code credentials on token refresh #4126)hermes auth removewas also ineffective forclaude_codesource — removed entries were immediately re-seeded on the nextload_pool()call.Reproduction scenario
hermes setup, selectkimi-coding, enter a malformed API keyhermes chat— main agent fails on kimi, auxiliary client falls through to_try_anthropic()→ reads~/.claude/.credentials.json→ uses Claude Max OAuth token for compression/summarization~/.claude/.credentials.jsonContext
PR #4210 fixed the same class of bug for the setup wizard gate: "Users got silently routed to someone else's inference without being asked." This PR extends that fix to the remaining unprotected paths:
_seed_from_singletons()inagent/credential_pool.py— credential pool auto-discovery_resolve_api_key_provider()inagent/auxiliary_client.py— auxiliary fallback chainauth_remove_command()inhermes_cli/auth_commands.py— remove re-seed preventionChanges
hermes_cli/auth.pyis_provider_explicitly_configured(),suppress_credential_source(),is_source_suppressed()agent/credential_pool.py_seed_from_singletons("anthropic")behind explicit config check + suppress checkagent/auxiliary_client.py_resolve_api_key_provider()anthropic branchhermes_cli/auth_commands.pyclaude_codesource removaltests/hermes_cli/test_auth_provider_gate.pytests/agent/test_credential_pool.pytests/hermes_cli/test_auth_commands.pytests/agent/test_auxiliary_client.pyTest plan
pytest tests/hermes_cli/test_auth_provider_gate.py— 6/6 passpytest tests/agent/test_credential_pool.py— 28/28 passpytest tests/hermes_cli/test_auth_commands.py— 16/16 passpytest tests/agent/test_auxiliary_client.py— 97/98 pass (1 pre-existing failure unrelated to this PR)🤖 Generated with Claude Code