Skip to content

fix(security): separate OAuth PKCE state from code_verifier (#10693)#26861

Merged
teknium1 merged 3 commits into
mainfrom
hermes/hermes-8f7079e4
May 16, 2026
Merged

fix(security): separate OAuth PKCE state from code_verifier (#10693)#26861
teknium1 merged 3 commits into
mainfrom
hermes/hermes-8f7079e4

Conversation

@teknium1

Copy link
Copy Markdown
Contributor

Salvage of #10699 by @shaun0927 — cherry-picked clean onto current main with contributor authorship preserved.

Summary

run_hermes_oauth_login_pure() reused the PKCE code_verifier as the OAuth state parameter, leaking the verifier into the authorization URL (browser history, Referer headers, auth-server logs) and removing CSRF protection on the callback. Now generates an independent secrets.token_urlsafe(32) for state and validates it before token exchange.

Regression context

This exact bug was fixed in PR #1775 on the old run_hermes_oauth_login(). PR #2647 (commit b17e5c1, credential pools) added a new run_hermes_oauth_login_pure() and silently copy-pasted the pre-#1775 vulnerable pattern. PR #3107 then removed the old (fixed) function, leaving only the regressed copy.

Changes

  • agent/anthropic_adapter.py (+10/-3) — @shaun0927's fix, cherry-picked
  • tests/agent/test_anthropic_oauth_pkce.py (+159) — two regression tests:
    • test_authorization_url_state_is_not_pkce_verifier — asserts state in the auth URL is independent from the verifier sent in the token exchange, and the verifier never appears in the URL
    • test_callback_state_mismatch_aborts — asserts the flow returns None (no token exchange) when callback state does not match
  • scripts/release.py — AUTHOR_MAP entry for shaun0927

Validation

  • Targeted: 200/200 pass across test_anthropic_oauth_pkce.py, test_anthropic_adapter.py, test_anthropic_oauth_flow.py, test_auth_commands.py
  • Negative control: reintroducing the b17e5c1 vulnerable pattern (state = verifier, no callback validation) makes both new tests fail

Closes #10693
Supersedes #10699

shaun0927 and others added 3 commits May 16, 2026 02:25
The PKCE flow reused the code_verifier as the OAuth state parameter.
Per RFC 6749 §10.12 and RFC 7636, these serve different purposes:
state is an anti-CSRF token visible in the authorization URL; the
code_verifier must remain secret for the token exchange.

Generate an independent secrets.token_urlsafe(32) for state and
validate it on callback to provide actual CSRF protection.

Closes #10693
Group the secrets import with time and webbrowser at the top of
run_hermes_oauth_login_pure(), matching the existing pattern.
Drop the _secrets alias — no name conflict in this scope.
…tion

Two unit tests for run_hermes_oauth_login_pure():

1. test_authorization_url_state_is_not_pkce_verifier — asserts state in the
   auth URL is independent from the PKCE code_verifier sent in the token
   exchange, and that the verifier never appears in the URL.

2. test_callback_state_mismatch_aborts — asserts the flow returns None
   (no token exchange) when the callback state does not match the value
   we generated.

Negative control verified: reintroducing the b17e5c1 vulnerable pattern
(state = verifier, no callback validation) makes both tests fail.

Also adds AUTHOR_MAP entry for shaun0927 (contributor of the fix).
@teknium1 teknium1 merged commit 72f94f4 into main May 16, 2026
16 of 17 checks passed
@teknium1 teknium1 deleted the hermes/hermes-8f7079e4 branch May 16, 2026 09:38
@github-actions

Copy link
Copy Markdown
Contributor

🔎 Lint report: hermes/hermes-8f7079e4 vs origin/main

ruff

Total: 0 on HEAD, 0 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 0 pre-existing issues carried over.

ty (type checker)

Total: 8329 on HEAD, 8329 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 4355 pre-existing issues carried over.

Diagnostics are surfaced as warnings — this check never fails the build.

@alt-glitch alt-glitch added type/security Security vulnerability or hardening P0 Critical — data loss, security, crash loop area/auth Authentication, OAuth, credential pools comp/agent Core agent loop, run_agent.py, prompt builder provider/anthropic Anthropic native Messages API labels May 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/auth Authentication, OAuth, credential pools comp/agent Core agent loop, run_agent.py, prompt builder P0 Critical — data loss, security, crash loop provider/anthropic Anthropic native Messages API type/security Security vulnerability or hardening

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OAuth PKCE code_verifier reused as state parameter — verifier leaked via authorization URL

3 participants