Hacktricks-skills oauth-pentest

Security testing for OAuth 2.0 and OIDC implementations. Use this skill whenever the user mentions OAuth, authentication flows, account takeover, identity providers, SSO, login flows, authorization codes, access tokens, or any security testing related to third-party authentication. This skill helps identify vulnerabilities like open redirect_uri, CSRF state issues, token leakage, client secret exposure, and other OAuth misconfigurations that lead to account compromise.

install
source · Clone the upstream repo
git clone https://github.com/abelrguezr/hacktricks-skills
manifest: skills/pentesting-web/oauth-to-account-takeover/SKILL.MD
source content

OAuth Security Testing

A comprehensive guide for testing OAuth 2.0 and OpenID Connect implementations for security vulnerabilities that could lead to account takeover.

Quick Start

When testing an OAuth implementation, follow this checklist:

  1. Map the OAuth flow - Identify all endpoints, parameters, and redirect URIs
  2. Test redirect_uri validation - Check for open redirects and weak validation
  3. Verify state parameter handling - Ensure CSRF protection is properly implemented
  4. Check token handling - Look for token leakage in URLs, storage, or logs
  5. Test client secret protection - Verify secrets aren't exposed in client-side code
  6. Validate authorization code lifecycle - Test for replay, lifetime, and binding issues
  7. Review consent screen security - Check for clickjacking and prompt bypass

OAuth 2.0 Fundamentals

Key Components

ComponentDescription
Resource OwnerThe user whose data is being accessed
Resource ServerServer managing authenticated requests (e.g., socialmedia.com)
Client ApplicationApplication seeking authorization (e.g., example.com)
Authorization ServerServer issuing access tokens after authentication
client_idPublic identifier for the application
client_secretConfidential key (must never be exposed to users)
redirect_uriURL for post-authorization redirect (must be pre-registered)
stateCSRF protection token (must be cryptographically random)
codeAuthorization code exchanged for access token
access_tokenToken used for API requests on behalf of user
refresh_tokenToken to obtain new access tokens without re-prompting

Standard Authorization Code Flow

1. User → Client: Clicks "Login with [Provider]"
2. Client → Auth Server: GET /auth?response_type=code&client_id=XXX&redirect_uri=YYY&scope=ZZZ&state=ABC
3. Auth Server → User: Consent screen
4. User → Auth Server: Approves
5. Auth Server → Client: GET /callback?code=DEF&state=ABC
6. Client → Auth Server: POST /token with code, client_id, client_secret
7. Auth Server → Client: Returns access_token, refresh_token
8. Client → Resource Server: API calls with access_token

Vulnerability Testing

1. Open redirect_uri

What to test: The authorization server must redirect only to pre-registered, exact redirect URIs.

Attack patterns:

# No validation - any URL accepted
https://idp.example/auth?redirect_uri=https://attacker.tld/callback

# Weak substring checks - bypass with lookalikes
https://idp.example/auth?redirect_uri=https://evilmatch.com
https://idp.example/auth?redirect_uri=https://match.com.evil.com
https://idp.example/auth?redirect_uri=https://match.com.mx
https://idp.example/auth?redirect_uri=https://evil.com#match.com
https://idp.example/auth?redirect_uri=https://match.com@evil.com

# IDN homograph attacks
https://idp.example/auth?redirect_uri=https://xn--example.com (redirects to Unicode domain)

# Path traversal on allowed hosts
https://idp.example/auth?redirect_uri=https://example.com/oauth/../anything

# Wildcard subdomain abuse
https://idp.example/auth?redirect_uri=https://attacker.example.com/callback

# Non-HTTPS callbacks
https://idp.example/auth?redirect_uri=http://example.com/callback

Testing steps:

  1. Identify the registered redirect_uri in the OAuth flow
  2. Try replacing the domain with attacker-controlled domains
  3. Test substring bypasses if validation exists
  4. Check for path traversal on allowed hosts
  5. Verify HTTPS enforcement
  6. Review auxiliary parameters:
    client_uri
    ,
    policy_uri
    ,
    tos_uri
    ,
    initiate_login_uri
  7. Check
    /.well-known/openid-configuration
    for additional endpoints

2. Redirect Token Leakage on Allowlisted Domains

What to test: Even "trusted" domains can leak tokens if they have attacker-controlled paths.

Attack pattern:

1. Start legitimate OAuth flow to get pre-token
2. Craft authorization URL with allowlisted domain but attacker-controlled path:
   https://apps.facebook.com/<attacker_app>
3. After approval, IdP redirects with tokens in URL
4. JavaScript on attacker page reads window.location and exfiltrates
5. Replay captured tokens against privileged endpoints

Testing steps:

  1. Identify allowlisted redirect domains
  2. Check if they support user-controlled paths (legacy apps, user namespaces, CMS)
  3. Create a test page on the allowlisted domain
  4. Set it as redirect_uri and verify tokens appear in URL
  5. Attempt to exfiltrate via JavaScript
  6. Test replay against downstream endpoints

3. XSS in Redirect Implementation

What to test: Redirect URLs reflected in responses may be vulnerable to XSS.

Test payload:

https://app.victim.com/login?redirectUrl=https://app.victim.com/dashboard</script><h1>test</h1>

Testing steps:

  1. Find redirect parameters in login/auth flows
  2. Inject XSS payloads into redirect URLs
  3. Check if reflected without encoding
  4. Test in various contexts: query params, fragments, headers

4. CSRF - State Parameter Issues

What to test: The

state
parameter must be cryptographically random, per-session, and validated.

Checklist:

  • state
    parameter present in authorization request
  • state
    is cryptographically random (not predictable)
  • state
    is validated on callback (same value returned)
  • state
    is tied to user session (cookie, local storage)
  • state
    cannot be user-supplied (fixation prevention)
  • Missing
    state
    still works? (opt-in defense)
  • Tampered
    state
    accepted? (validation bypass)

Attack pattern:

1. Attacker authenticates with their account
2. Captures final redirect with ?code=XXX&state=YYY
3. Drops request, keeps URL
4. Forces victim browser to load URL (link, iframe, form)
5. If state not validated, victim account links to attacker's IdP profile

Testing steps:

  1. Remove
    state
    from authorization request - does it still work?
  2. Tamper with
    state
    in response - is it rejected?
  3. Check if
    state
    is predictable (redirect paths, JSON blobs without entropy)
  4. Test state fixation - can you supply your own
    state
    value?
  5. Verify
    state
    is bound to session (different users, different sessions)

5. Pre-Account Takeover

What to test: Account creation without email verification can enable takeover.

Attack patterns:

  1. Pre-registration:

    • Attacker creates account with victim's email
    • Victim later uses OAuth login
    • App links OAuth account to attacker's pre-created account
  2. Lax OAuth email verification:

    • Attacker registers with OAuth provider
    • Changes email to victim's address
    • Victim's OAuth login links to attacker's account

Testing steps:

  1. Create account with victim's email (no verification)
  2. Attempt OAuth login with same email
  3. Check if accounts merge or link
  4. Test OAuth provider email change flows

6. Client Secret Disclosure

What to test:

client_secret
must never be recoverable by end users.

Where to look:

  • Mobile APKs/IPAs (unpack and grep)
  • Desktop installers
  • Electron apps
  • Single-page applications
  • Bundled config files (plist, JSON, XML)
  • Decompiled strings

Testing steps:

# Unpack and search for secrets
unzip app.apk -d app/
grep -r "client_secret" app/
grep -r "oauth" app/

# Check for Base64 encoded secrets
strings app.apk | base64 -d 2>/dev/null | grep -i "secret\|token\|key"

# Review config files
cat app/Info.plist
cat app/config.json

If secret is found:

  1. Capture any victim authorization
    code
    (via redirect_uri bug, logs, etc.)
  2. Exchange code for token independently:
    POST /oauth/access_token
    Content-Type: application/x-www-form-urlencoded
    
    client_id=XXX&client_secret=YYY&code=ZZZ&grant_type=authorization_code
    
  3. Verify PKCE is not required (public clients should use PKCE, not secrets)

7. Client Secret Brute Force

What to test: Weak client secrets can be brute-forced.

Test request:

POST /token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: target.com

code=77515&redirect_uri=http://target.com/callback&grant_type=authorization_code&client_id=public_client_id&client_secret=[bruteforce]

Testing steps:

  1. Capture a valid authorization code
  2. Use Burp Intruder to brute-force
    client_secret
  3. Look for different response codes/sizes indicating success
  4. Test common weak secrets:
    secret
    ,
    password
    ,
    123456
    , client_id itself

8. Referer/Header/Location Artifacts

What to test: OAuth codes and tokens leaked via HTTP headers or browser APIs.

Attack patterns:

  1. Classic Referer leak:

    • OAuth redirect includes
      ?code=&state=
      in URL
    • Any navigation sends Referer header to CDNs/analytics/ads
    • Third parties receive OAuth artifacts
  2. Telemetry confused deputy:

    • SDKs react to
      postMessage
      events
    • Send
      location.href
      /
      referrer
      to backend APIs
    • Attacker injects token into flow
    • Later reads SDK API logs to recover OAuth artifacts

Testing steps:

  1. Check if
    code
    /
    state
    appear in URL after OAuth redirect
  2. Monitor Referer headers sent to third parties
  3. Check analytics/telemetry SDKs for URL logging
  4. Test
    postMessage
    relay attacks
  5. Review server logs for OAuth parameter exposure

9. Access Token in Browser History

What to test: Access tokens should never reach the browser in Authorization Code flow.

Check for:

  • Tokens in URL query/fragment
  • Tokens in browser history
  • Tokens in server logs
  • Tokens in JavaScript state (React/Vue stores, global variables)
  • Tokens in Web Storage (localStorage/sessionStorage)
  • Tokens over HTTP (not HTTPS)
  • Tokens through debugging/corporate proxies

Impact: Any XSS, Referer leak, or proxy logging becomes instant account compromise.

10. Authorization Code Lifecycle

What to test: Codes must be short-lived, single-use, and replay-aware.

Testing steps:

  1. Lifetime test:

    • Capture authorization code
    • Wait 5-10 minutes
    • Attempt to redeem - should fail
  2. Sequential reuse test:

    • Redeem code once (success)
    • Redeem same code again - should fail
  3. Concurrent redemption test:

    • Fire two token requests in parallel
    • Only one should succeed
  4. Replay handling test:

    • Attempt reuse after successful redemption
    • Verify any minted tokens are revoked

11. Token Binding to Client

What to test: Authorization codes must be bound to the issuing client.

Testing steps:

  1. Capture
    code
    for App A
  2. Send to App B's token endpoint
  3. If token is returned, audience binding is broken
  4. Test first-party token minting endpoints
  5. Check if arbitrary
    state
    /
    app_id
    accepted
  6. Verify nonce/redirect URI validation

12. Response Mode Variations

What to test: Different response modes may have different security properties.

response_mode=query      -> ?code=2397rf3gu93f (in URL, visible in history/logs)
response_mode=fragment   -> #code=2397rf3gu93f (not sent to server, but in browser)
response_mode=form_post  -> POST form with code (more secure)
response_mode=web_message -> postMessage (requires careful implementation)

Testing steps:

  1. Try each response_mode value
  2. Check if server accepts all modes
  3. Verify security implications of each mode
  4. Test for mode confusion attacks

13. Prompt Parameter Bypass

What to test:

prompt=none
may bypass user consent.

Test:

https://idp.example/auth?response_type=code&client_id=XXX&redirect_uri=YYY&prompt=none

Testing steps:

  1. Add
    prompt=none
    to authorization request
  2. Check if consent screen is skipped
  3. Verify this is only allowed for trusted flows
  4. Test with
    prompt=login
    ,
    prompt=consent
    ,
    prompt=select_account

14. Clickjacking Consent Dialogs

What to test: OAuth consent/login dialogs should not be frameable.

Testing steps:

  1. Load IdP authorization URL in iframe:
    <iframe sandbox="allow-forms allow-scripts allow-same-origin" src="https://idp.example/auth?..."></iframe>
    
  2. Check for
    X-Frame-Options: DENY/SAMEORIGIN
  3. Check for
    Content-Security-Policy: frame-ancestors 'none'
  4. If frameable, create clickjacking PoC with overlaid buttons
  5. Use NCC Group's clickjacking PoC generator

15. OAuth ROPC Flow - 2FA Bypass

What to test: Resource Owner Password Credentials flow may bypass 2FA.

What to look for:

  • OAuth endpoints accepting username/password directly
  • Tokens returned with full user permissions
  • No 2FA challenge in the flow

Testing steps:

  1. Find ROPC endpoint (usually
    /token
    with
    grant_type=password
    )
  2. Test with username/password
  3. Check if 2FA is required
  4. Verify token permissions

16. AWS Cognito Abuse

What to test: Cognito tokens may have excessive permissions.

Test commands:

# Read user info
aws cognito-idp get-user --region us-east-1 --access-token <token>

# Change email (if permitted)
aws cognito-idp update-user-attributes \
  --region us-east-1 \
  --access-token <token> \
  --user-attributes Name=email,Value=attacker@example.com

Testing steps:

  1. Obtain Cognito access token
  2. Check token permissions
  3. Attempt to modify user attributes
  4. Test email change for account takeover

17. Abusing Other Apps' Tokens

What to test: Apps expecting tokens (not codes) may not validate token ownership.

Attack pattern:

  1. Attacker creates OAuth app and logs in with victim's OAuth provider
  2. Attacker gets victim's OAuth token for their app
  3. Attacker uses this token to login to victim's target app
  4. If target app doesn't validate token's client_id, account is compromised

Testing steps:

  1. Create test OAuth application
  2. Login with OAuth provider
  3. Capture the access token
  4. Try using token on other apps expecting OAuth tokens
  5. Check if client_id validation exists

18. Dynamic Client Registration SSRF

What to test: Client registration endpoints may enable SSRF.

Vulnerable parameters:

  • logo_uri
    - Logo URL fetched by server
  • jwks_uri
    - JWK document URL
  • sector_identifier_uri
    - Redirect URI array URL
  • request_uris
    - Request URI list

Test request:

POST /register
Content-Type: application/json

{
  "client_name": "Test App",
  "redirect_uris": ["https://example.com/callback"],
  "logo_uri": "http://internal-server/admin",
  "jwks_uri": "http://169.254.169.254/latest/meta-data/"
}

Testing steps:

  1. Find client registration endpoint (usually
    /register
    )
  2. Test with internal URLs in URI parameters
  3. Check for SSRF indicators (different response, timeout, internal IP access)
  4. Test with metadata service URLs

19. OAuth Discovery URL Abuse (RCE)

What to test: Desktop clients forwarding IdP metadata to OS may enable RCE.

Attack pattern:

  1. Host malicious OAuth server
  2. Return dangerous
    authorization_endpoint
    in discovery:
    {
      "authorization_endpoint": "file:///c:/windows/system32/calc.exe",
      "token_endpoint": "https://evil/idp/token"
    }
    
  3. Client calls OS URL handler with malicious URI
  4. Code executes under user context

Test payloads:

// Windows
"authorization_endpoint": "file:///c:/windows/system32/calc.exe"
"authorization_endpoint": "cmd://powershell -enc <base64>"

// macOS/Linux
"authorization_endpoint": "file:///Applications/Calculator.app/Contents/MacOS/Calculator"
"authorization_endpoint": "xdg-open /etc/passwd"

// Custom schemes
"authorization_endpoint": "ms-excel:"
"authorization_endpoint": "data:text/html,<script>alert(1)</script>"

Testing steps:

  1. Target OAuth-capable desktop/agent clients
  2. Intercept or host discovery response
  3. Replace endpoints with dangerous schemes
  4. Observe if client validates scheme/host
  5. Test cross-platform variations

20. Mutable Claims Attack

What to test: Relying on mutable claims (email) instead of immutable

sub
can enable takeover.

Attack pattern:

  1. Attacker creates Azure AD organization
  2. Uses Microsoft login with attacker's account
  3. Changes email to victim's email in Entra ID
  4. Target app relying on email field links accounts

Testing steps:

  1. Check what claims the app uses for user identification
  2. Verify if
    sub
    (immutable) or email (mutable) is used
  3. Test with OAuth providers allowing email changes
  4. Attempt account linking via email change

21. Client Confusion Attack

What to test: Apps not validating token's client_id can be confused.

Attack pattern:

  1. Attacker creates public OAuth app
  2. Users login, attacker harvests access tokens
  3. Attacker reuses tokens on vulnerable app
  4. If app doesn't validate client_id, accounts are compromised

Testing steps:

  1. Create test OAuth application
  2. Login and capture access token
  3. Try token on other apps
  4. Check if client_id is validated in token

22. Scope Upgrade Attack

What to test: Authorization servers trusting scope parameter in token request.

Attack pattern:

  1. Get authorization code with limited scope
  2. Request token with elevated scope parameter
  3. If server trusts scope parameter, token has higher privileges

Testing steps:

  1. Capture authorization code
  2. Modify scope in token request
  3. Check if returned token has elevated permissions
  4. Verify JWT signature and scope validation

23. Redirect Scheme Hijacking (Mobile)

What to test: Custom URI schemes on mobile can be hijacked.

Attack pattern:

  1. Multiple apps can register same URI scheme
  2. Attacker app registers
    com.example.app://
  3. OAuth redirect goes to attacker app
  4. Attacker captures authorization code

Testing steps:

  1. Identify custom URI schemes used
  2. Check if scheme-only or scheme+path
  3. Test with malicious app registering same scheme
  4. Verify intent filter specificity on Android

Testing Workflow

Phase 1: Reconnaissance

  1. Identify OAuth endpoints (
    /auth
    ,
    /token
    ,
    /callback
    ,
    /register
    )
  2. Map all redirect URIs used
  3. Document OAuth parameters and their values
  4. Check for OpenID Connect discovery (
    /.well-known/openid-configuration
    )
  5. Identify OAuth providers in use

Phase 2: Vulnerability Testing

  1. Test redirect_uri validation (open redirect)
  2. Verify state parameter handling (CSRF)
  3. Check token storage and transmission
  4. Test authorization code lifecycle
  5. Verify client secret protection
  6. Test consent screen security
  7. Check for additional attack vectors

Phase 3: Exploitation

  1. Attempt account takeover with identified vulnerabilities
  2. Test token replay and reuse
  3. Verify impact of each finding
  4. Document exploitation steps

Phase 4: Reporting

  1. Document each vulnerability with:
    • Description
    • Impact
    • Steps to reproduce
    • Proof of concept
    • Remediation recommendations

Remediation Guidelines

For Developers

  1. redirect_uri validation:

    • Use exact match against pre-registered URIs
    • Validate scheme (HTTPS only)
    • Normalize URLs before comparison
    • Reject wildcard subdomains
  2. State parameter:

    • Generate cryptographically random value per session
    • Store in secure, HttpOnly cookie
    • Validate on callback (exact match)
    • Reject if missing or mismatched
  3. Token handling:

    • Never expose access tokens to browser in Authorization Code flow
    • Use PKCE for public clients
    • Store tokens securely (not in localStorage)
    • Implement token rotation
  4. Client secrets:

    • Never embed in client-side code
    • Use PKCE for mobile/desktop apps
    • Rotate secrets regularly
    • Monitor for leaked secrets
  5. Authorization codes:

    • Short lifetime (5-10 minutes)
    • Single-use only
    • Bind to client_id and redirect_uri
    • Revoke on reuse attempt

For Security Teams

  1. Regularly audit OAuth implementations
  2. Monitor for leaked client secrets
  3. Test third-party OAuth integrations
  4. Implement OAuth security monitoring
  5. Review consent screen configurations

References

Tools

  • Burp Suite - Intercept and modify OAuth flows
  • OAuth Tester - Automated OAuth vulnerability scanning
  • Postman - Test OAuth endpoints
  • NCC Group Clickjacking PoC - Test consent screen framing
  • Custom scripts - See bundled scripts for common tests