OAuth
OAuth is a gift to bug bounty hunters. The spec is complex, implementations vary wildly, and developers frequently misunderstand what they're supposed to be protecting. Every app with "Login with Google/GitHub/Facebook" is worth testing here.
OAuth Flow with Attack Points
flowchart TD A["User clicks Login with Provider"] --> B["Redirect to Auth Server"] B --> C["GET /authorize"] C --> D["User authenticates + consents"] D --> E["Redirect to redirect_uri with auth code"] E --> F["Client exchanges code for token"] F --> G["access_token + refresh_token"] B -.- X1["ATTACK: redirect_uri validated?"] B -.- X2["ATTACK: state param present?"] E -.- X3["ATTACK: code leaks via Referer?"] F -.- X4["ATTACK: state validated? CSRF if not"] G -.- X5["ATTACK: token storage secure?"]
redirect_uri Manipulation
This is the big one. If the redirect_uri isn't strictly validated, you can steal auth codes.
Open redirect chaining - if the app allows redirect_uri=https://target.com/callback and there's an open redirect at https://target.com/redirect?to=, try:
redirect_uri=https://target.com/redirect?to=https://evil.comPath traversal - if the app validates the domain but not the path:
# Registered: https://target.com/callback
# Try:
redirect_uri=https://target.com/callback/../../../attacker-controlled-path
redirect_uri=https://target.com/callback%2F..%2F..%2FevilSubdomain/path confusion:
redirect_uri=https://target.com.evil.com/callback
redirect_uri=https://target.com/callback?x=https://evil.com
redirect_uri=https://target.com/callback#https://evil.comState Parameter - CSRF on OAuth
If there's no state parameter, or it's not validated on return, the entire OAuth flow is vulnerable to CSRF. You can force a victim to link your account to theirs.
PoC:
- Start an OAuth flow, capture the authorization URL
- Don't complete it - grab the URL up to the redirect
- Send that URL to a victim (logged in to the target app)
- If the app doesn't validate
state, victim's account gets linked to your OAuth identity
Token Leakage via Referer
Same issue as Password Reset - if the redirect lands on a page with third-party scripts and the access token appears in the URL fragment or query string, it leaks.
https://target.com/callback?code=AUTH_CODE - that code ends up in Referer headers.
PKCE Bypass
PKCE (Proof Key for Code Exchange) is supposed to prevent code interception. Common implementation bugs:
code_verifieraccepted withoutcode_challengebeing checked- Server accepts any
code_verifiervalue regardless of what was sent during authorization - PKCE entirely optional when it should be required
Test by starting a PKCE flow, intercepting the token exchange, and removing or altering the code_verifier:
POST /oauth/token HTTP/1.1
Host: auth.target.com
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&code=AUTH_CODE&redirect_uri=https://target.com/callback
# No code_verifier - does the server reject this?Scope Escalation
Request scopes beyond what the app normally requests. Sometimes the auth server approves anything the client asks for without checking against what was registered.
# Normal request
scope=read:profile email
# Try escalating
scope=read:profile email admin write:all repoAlso look for scope confusion - if the app uses offline_access to get a refresh token but the refresh token has broader permissions than intended.
Account Takeover via Unlinked Email
Classic chain: target app allows sign-up with email and also supports OAuth. You register victim@gmail.com with a password. Victim later logs in via "Login with Google" using the same email. If the app merges these accounts automatically without email verification - you have the victim's account.
Implicit Flow
If the app is using the implicit flow (token returned directly in the URL fragment, not via code exchange), that's worth noting. Tokens in URL fragments can leak via:
- Browser history
- Server logs if the fragment gets accidentally server-side
- JavaScript on the page reading
window.location.hash
Public Reports
Real-world OAuth findings across bug bounty programs:
- Open redirect on cs.money chained with OAuth for account takeover - HackerOne #905607
- Account takeover via Pornhub OAuth flow using unverified email - HackerOne #192648
- Account takeover via Google OneTap on Priceline without email verification - HackerOne #671406
- GitLab OAuth email verification bypass leading to third-party account takeover - HackerOne #922456
Related Pages
- SSO - SAML-based SSO has overlapping attack patterns
- Session Management - where OAuth tokens end up and how they're stored
- Password Reset - apps with OAuth sometimes have a broken legacy password reset too