Research / OAuth 2.0: типові помилки реалізації і як їх зламати
RESEARCH
UA EN

OAuth 2.0: Common Implementation Flaws and How to Exploit Them

✍ admin 📅 21.05.2026 👁 110

How OAuth 2.0 Works

OAuth 2.0 is an authorization protocol that allows applications (clients) to obtain limited access to resources on behalf of a user without knowing their password.

Typical Authorization Code Flow:

1. User clicks "Sign in with Google"
2. App redirects to Google:
   https://accounts.google.com/oauth/authorize?
     client_id=APP_ID&
     redirect_uri=https://app.com/callback&
     response_type=code&
     scope=email&
     state=RANDOM_STATE

3. User logs into Google and approves access

4. Google redirects to redirect_uri with a code:
   https://app.com/callback?code=AUTH_CODE&state=RANDOM_STATE

5. App exchanges code for access_token:
   POST https://oauth2.googleapis.com/token
   grant_type=authorization_code&code=AUTH_CODE&
   client_secret=SECRET&redirect_uri=...

6. Google returns access_token
7. App uses token to access the API

Attack 1: Missing or Predictable State Parameter (CSRF)

Idea: the state parameter prevents CSRF attacks. If it's absent or static — an attacker can force the victim to link their account to the attacker's.

Exploit:

1. Attacker initiates an OAuth flow, stops at step 4
   (gets a URL with the code but doesn't complete authorization)

2. Sends this URL to the victim:
   https://victim-app.com/callback?code=ATTACKER_CODE

3. Victim (already logged in) visits the link

4. App binds ATTACKER_CODE to the victim's account

5. Attacker can now log into the victim's account via their own Google

Check:

1. Start an OAuth flow
2. Get a callback URL with a code
3. Open the same URL in another browser (no session)
4. If authorization succeeds — state is not being validated

Attack 2: Open redirect_uri

Idea: if the OAuth server doesn't strictly validate redirect_uri — an attacker can steal the authorization code.

Scenario 1: Wildcard

# Registered: https://app.com/callback
# Server allows: https://app.com/*

# Attack: find an open redirect on app.com
# https://app.com/redirect?url=https://attacker.com

# Malicious OAuth URL:
https://accounts.google.com/oauth/authorize?
  client_id=APP_ID&
  redirect_uri=https://app.com/redirect?url=https://attacker.com&
  response_type=code

# Victim authorizes -> code is sent to attacker.com via redirect

Scenario 2: Path traversal

# Registered: https://app.com/callback
# Vulnerable server accepts: https://app.com/callback/../evil

redirect_uri=https://app.com/callback%2F..%2Fevil

Attack 3: Authorization Code Interception via Referer

Idea: if the /callback page loads external resources (analytics, CDN) — the URL containing code may leak via the Referer header.

GET https://app.com/callback?code=SECRET_CODE
# The callback page loads:
<script src="https://analytics.example.com/track.js">
<img src="https://cdn.company.com/logo.png">

# These requests will include:
Referer: https://app.com/callback?code=SECRET_CODE

Check: look at network requests in DevTools during the OAuth callback. Is code in the Referer of any request?


Attack 4: Insufficient Token Validation

Idea: some apps don't validate the access_token — they just trust the email or user_id returned by the OAuth provider.

# Vulnerable implementation
@app.route('/oauth/callback')
def callback():
    code = request.args.get('code')
    token = exchange_code_for_token(code)
    user_info = get_user_info(token)

    # BUG: not checking token audience
    user = User.query.filter_by(email=user_info['email']).first()
    login_user(user)

# Attack: register your own Google OAuth app,
# get a token for the victim (if you know their email),
# replace the token in the request

Attack 5: Token Leakage via Fragment (#)

Idea: in the Implicit Flow (old, not recommended), access_token is passed via the URL fragment.

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

# Problem: the fragment can leak via:
# - document.referrer if there's a redirect
# - window.location.hash accessible to JS on the page
# - Browser history

Attack 6: Account Takeover via Email Claim

Idea: if a Google account can be registered with the victim's email, or the OAuth provider doesn't verify email.

1. Victim: alice@company.com
2. Attacker registers a Google account with alice@company.com
   (some providers don't verify email on registration)
3. OAuth flow: Google returns email=alice@company.com
4. App looks up User by email -> finds victim's account
5. Attacker is logged in!

Where to Look for OAuth Vulnerabilities

1. Is the state parameter present? Is it validated?
2. Check redirect_uri: what will the server accept?
   - Try: redirect_uri=https://attacker.com
   - Try: redirect_uri=https://app.com.attacker.com
   - Try: redirect_uri=https://app.com/callback/../evil

3. Is ?code= in the URL on the callback page?
   Are external resources loaded?

4. Check /oauth/callback in Burp — how is the code used?
   Is it validated?

5. Implicit Flow: is there a #access_token in the URL?

Defenses

# 1. State parameter — cryptographically random and session-bound
import secrets
state = secrets.token_urlsafe(32)
session['oauth_state'] = state

@app.route('/callback')
def callback():
    if request.args.get('state') != session.pop('oauth_state', None):
        abort(403)

# 2. Strict redirect_uri comparison
ALLOWED_REDIRECT_URIS = ['https://app.com/oauth/callback']
if redirect_uri not in ALLOWED_REDIRECT_URIS:
    raise ValueError

# 3. Validate token audience claim
decoded = jwt.decode(token, key, audience='APP_CLIENT_ID')

# 4. Use Authorization Code Flow + PKCE instead of Implicit

Useful Resources

Коментарі (0)
Увійди, щоб залишити коментар.
Коментарів поки немає.
Вперше тут?
Новачок на Bastion?
Почни з гайду користувача.
Відкрити гайд →
?