Title: Authentication Bypass via Insecure Credential Pool Synchronization during Anthropic Exhaustion
Description:
An authorization bypass vulnerability exists in the CredentialPool of the hermes-agent caused by insecure synchronization with a global credentials file (~/.claude/.credentials.json). When the agent encounters a rate limit (HTTP 429) using Anthropic claude_code credentials, it marks the current entry as exhausted. During the subsequent rotation to select a new token, the pool automatically checks if exhausted tokens have updated credentials in the local .claude config file. Because this applies to any exhausted token from the claude_code source regardless of user boundary, the singleton credentials file will overwrite every distinct pool entry as they each face exhaustion, causing all isolated accounts to merge into a single identity. This breaks multi-account credential pooling and leads to rate limit cascading across all pool credentials, similar to a previous Codex vulnerability (#11364).
The vulnerability lies within agent/credential_pool.py. When multiple Anthropic accounts are configured in auth.json with source: claude_code to distribute loads and circumvent rate limits, the token pool manager attempts to track them securely.
However, if a token encounters an exhaustion error (e.g. HTTP 429), mark_exhausted_and_rotate() marks the current token as exhausted and clears the active selection.
When the system selects the next credential by calling self._available_entries(), the method includes an insecure syncing mechanism for exhausted credentials:
if (self.provider == "anthropic" and entry.source == "claude_code"
and entry.last_status == STATUS_EXHAUSTED):
synced = self._sync_anthropic_entry_from_credentials_file(entry)The method _sync_anthropic_entry_from_credentials_file() blind-reads the global ~/.claude/.credentials.json and overrides the pool entry if the refreshToken differs. Since this happens symmetrically for all entries in the pool as they individually encounter exhaustion, every single distinct account token in the pool will gradually be clobbered by whatever token is currently sitting in ~/.claude/.credentials.json.
- Python 3.10+
- The
poc_anthropic_sync.pyscript downloaded. - Tested locally by mimicking the CLI's handling of
auth.jsonrotation and selection cycles.
-
Download the PoC server script from: https://gist.github.com/YLChen-007/5fcaf1ee5120a6f04c11addb1e3ff4c5
-
Set the script to target a local installation of the hermes-agent framework by ensuring
sys.path.insert(0, "/root/llm-agent-project/hermes-agent")references paths correctly. -
Run the PoC:
python poc_anthropic_sync.py -
The PoC spins up a fake multi-credential
auth.jsoncontainingtoken-acc-1,token-acc-2, andtoken-acc-3, and injects a singleHACKED_SINGLE_ACCESS_TOKENinto the mocked.claude/.credentials.json. -
The PoC runs 10 cycles of
pool.select()followed by an exhaustion eventpool.mark_exhausted_and_rotate(status_code=429)to mimic the rate-limit failure of each token. -
The exploit verifies the resulting tokens in the
auth.json.
[*] Verifying pre-exploit state.
[*] Pre-exploit tokens: ['token-acc-1', 'token-acc-2', 'token-acc-3']
[*] Triggering pool rotation (exhaustion mock).
[!] Access Tokens in pool: ['HACKED_SINGLE_ACCESS_TOKEN', 'HACKED_SINGLE_ACCESS_TOKEN', 'HACKED_SINGLE_ACCESS_TOKEN']
[SUCCESS] All pool entries were overwritten with the singleton token!
- Type: Information Leakage / Authentication Bypass (via Session Overwrite)
- Impact Flow:
By overwriting the multi-tenant or multi-account credentials pooled in
auth.jsonwith the singleton file contents from~/.claude/.credentials.json, isolated authorization boundaries are breached. This completely negates the failover and rate-limit bypassing functions, creating an Authorization Bypass variant where operations expected to be executed across diverse authorized sessions collapse into a single identity representation.
- Ecosystem: python
- Package name: hermes-agent
- Affected versions: <= v2026.4.23
- Patched versions:
- Severity: High
- Vector string: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:L
- CWE: CWE-287: Improper Authentication
- CWE: CWE-668: Exposure of Resource to Wrong Sphere
| Permalink | Description |
|---|---|
| https://github.com/NousResearch/hermes-agent/blob/main/agent/credential_pool.py#L512-L544 | The vulnerable _sync_anthropic_entry_from_credentials_file method reading from a single shared configuration rather than scoped multi-tenant secrets. |
| https://github.com/NousResearch/hermes-agent/blob/main/agent/credential_pool.py#L559-L564 | The method evaluation point in _available_entries dynamically overwriting internal records during status checks. |