Goal:

  • ๐Ÿ” Understand OAuth account linking vulnerabilities
  • ๐ŸŽฏ Exploit missing state parameter validation
  • ๐Ÿ”“ Perform CSRF attack on OAuth flow
  • ๐Ÿ’ฅ Link victim's OAuth account to attacker's profile
  • ๐Ÿ‘ค Access admin panel and delete carlos
  • ๐ŸŽ‰ Complete lab

๐Ÿง  Concept Recap

Forced OAuth Profile Linking exploits applications that don't properly validate the OAuth state parameter during account linking. When an attacker can trick a victim into completing an OAuth flow initiated by the attacker, the victim's social media account becomes linked to the attacker's application account, allowing the attacker to log in as the victim.

๐Ÿ“Š The Vulnerability

OAuth Account Linking Flow:

Normal Account Linking Process:

User with existing account โ†’ Wants to link social media
                          โ†“
                    Initiates OAuth flow
                          โ†“
                    Authorizes at OAuth provider
                          โ†“
                    Callback returns to application
                          โ†“
                    Social account linked to user's profile
                          โ†“
                    User can now login with social media
Purpose:
โ”œโ”€โ”€ Convenience: Single sign-on capability
โ”œโ”€โ”€ Security: Leverage trusted OAuth providers
โ””โ”€โ”€ User experience: Fewer passwords to remember
Security Mechanism (Should exist):
โ””โ”€โ”€ State parameter: Prevents CSRF attacks
    โ””โ”€โ”€ Random token tied to user's session
        โ””โ”€โ”€ Validated on callback to ensure same user

The Attack Flow:

VULNERABLE FLOW (Missing state validation):

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ 1. Attacker initiates OAuth linking                โ”‚
โ”‚    โ””โ”€โ”€ Starts linking their social account         โ”‚
โ”‚         โ””โ”€โ”€ GET /auth?client_id=...                โ”‚
โ”‚              โ””โ”€โ”€ No state parameter! ๐Ÿšจ            โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                     โ†“
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ 2. Attacker captures OAuth callback URL            โ”‚
โ”‚    โ””โ”€โ”€ Intercepts before completing flow           โ”‚
โ”‚         โ””โ”€โ”€ URL: /oauth-linking?code=xyz789        โ”‚
โ”‚              โ””โ”€โ”€ Drops request (preserves code)    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                     โ†“
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ 3. Attacker crafts malicious page                  โ”‚
โ”‚    โ””โ”€โ”€ iframe pointing to /oauth-linking?code=xyz  โ”‚
โ”‚         โ””โ”€โ”€ Victim visits attacker's page          โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                     โ†“
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ 4. Victim's browser makes request                  โ”‚
โ”‚    โ””โ”€โ”€ GET /oauth-linking?code=xyz789              โ”‚
โ”‚         โ””โ”€โ”€ Uses victim's session cookie           โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                     โ†“
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ 5. Application links accounts (VULNERABLE)         โ”‚
โ”‚    โ””โ”€โ”€ No state validation!                        โ”‚
โ”‚         โ””โ”€โ”€ Attacker's social account              โ”‚
โ”‚              โ””โ”€โ”€ Linked to victim's profile! ๐Ÿ’ฅ    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                     โ†“
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ 6. Attacker logs in with social media              โ”‚
โ”‚    โ””โ”€โ”€ Uses their own social account               โ”‚
โ”‚         โ””โ”€โ”€ Now logged in as admin! ๐ŸŽฏ             โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Why This Works:

Root Cause: Missing CSRF Protection on OAuth Callback

Secure OAuth Flow (Should have):

GET /oauth-linking?code=xyz789&state=random_token_123
Server validates:
โ”œโ”€โ”€ 1. Is 'state' present?
โ”œโ”€โ”€ 2. Does 'state' match session?
โ””โ”€โ”€ 3. Is 'code' fresh and unused?

If all pass:
โ””โ”€โ”€ Link social account to current user โœ“
Vulnerable Flow (This lab):
GET /oauth-linking?code=xyz789

Server only validates:
โ””โ”€โ”€ Is 'code' valid?

Missing validations:
โ”œโ”€โ”€ โœ— No state parameter check
โ”œโ”€โ”€ โœ— No CSRF token validation
โ””โ”€โ”€ โœ— Trusts any authenticated request

๐Ÿ› ๏ธ Step-by-Step Attack

๐Ÿ”ง Step 1 โ€” Access Lab and Login

  1. ๐ŸŒ Click "Access the lab"
  2. ๐Ÿ‘ค Click "My account" in top-right corner
  3. โœ๏ธ Login with blog credentials:
  • Username: wiener
  • Password: peter

4. โœ… Successfully logged in to the blog website

What you see:

My Account Page:
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  Email: wiener@normal-user.net       โ”‚
โ”‚                                      โ”‚
โ”‚  [Attach a social profile]           โ”‚
โ”‚                                      โ”‚
โ”‚  This feature is currently in beta!  โ”‚
โ”‚  Link your social media account for  โ”‚
โ”‚  a more seamless login experience.   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Key observation:
โ””โ”€โ”€ "Attach a social profile" button available
    โ””โ”€โ”€ This is the vulnerable feature!

Note: There are two sets of credentials in this lab:

  • Blog website: wiener / peter
  • Social media profile: peter.wiener / hotdog

๐Ÿ“ก Step 2 โ€” Analyze Account Linking Flow

First, complete the full OAuth linking flow to understand it:

  1. ๐Ÿ”— Click "Attach a social profile"
  2. ๐ŸŒ You are redirected to the social media OAuth provider
  3. โœ๏ธ Login with social media credentials:
  • Username: peter.wiener
  • Password: hotdog

4. โœ… Authorize โ€” you'll be redirected back to the blog

5. ๐Ÿ” Open Burp Suite โ†’ Proxy โ†’ HTTP history and study the flow

Look for this request in history:

GET /auth?client_id=xxxxxxxxxxxx&redirect_uri=https://YOUR-LAB-ID.web-security-academy.net/oauth-linking&response_type=code&scope=openid%20profile%20email HTTP/1.1
Host: oauth-YOUR-OAUTH-ID.oauth-server.net

Note: No 'state' parameter! ๐Ÿšจ
โ””โ”€โ”€ This is the vulnerability indicator!

Key finding:

โœ“ Authorization URL has NO state parameter
โœ“ redirect_uri sends code to /oauth-linking (not /oauth-callback!)
โœ“ This means the callback endpoint is /oauth-linking?code=...
โœ“ No CSRF protection โ€” exploitable!

๐ŸŽฏ Step 3 โ€” Intercept and Capture the /oauth-linking Request

Now intercept the flow to steal the authorization code:

  1. ๐Ÿ› ๏ธ Open Burp Suite โ†’ Proxy โ†’ Intercept
  2. ๐Ÿ”ด Turn Intercept ON
  3. ๐ŸŒ Click "Attach a social profile" again
  4. ๐Ÿ”„ Keep forwarding requests until you intercept this one:
GET /oauth-linking?code=h8Kd9fJ2mN5pQ7rS4tU6vW1xY3zA0bC8 HTTP/1.1
Host: YOUR-LAB-ID.web-security-academy.net
Cookie: session=wiener_session_token

โš ๏ธ STOP HERE! Do NOT forward this request!

  1. ๐Ÿ–ฑ๏ธ Right-click on this request โ†’ "Copy URL"
  2. ๐Ÿ“ Paste the URL somewhere safe โ€” you'll need it shortly
  3. ๐Ÿ—‘๏ธ Click "Drop" to drop the request
  4. ๐Ÿ”ด Turn Intercept OFF

Why drop it:

Authorization code is single-use:
โ””โ”€โ”€ If we forward it โ†’ our social account links to our account
    โ””โ”€โ”€ Code gets consumed
        โ””โ”€โ”€ Can no longer be used to exploit the victim!

By dropping it:
โ””โ”€โ”€ Code remains valid and unused
    โ””โ”€โ”€ We'll make the victim's browser consume it
        โ””โ”€โ”€ Linking our social account to their (admin) profile!

The copied URL looks like:

https://YOUR-LAB-ID.web-security-academy.net/oauth-linking?code=h8Kd9fJ2mN5pQ7rS4tU6vW1xY3zA0bC8

๐Ÿ’€ Step 4 โ€” Craft Exploit on Exploit Server

Log out of the blog website first:

  1. ๐Ÿšช Click "Log out"

Access exploit server:

2. ๐ŸŒ Click "Go to exploit server" button in lab

Create the exploit payload using the URL you copied:

<iframe src="https://YOUR-LAB-ID.web-security-academy.net/oauth-linking?code=h8Kd9fJ2mN5pQ7rS4tU6vW1xY3zA0bC8"></iframe>

How it works:

Exploit mechanism:
โ””โ”€โ”€ Victim (admin) visits exploit page
    โ””โ”€โ”€ iframe silently loads /oauth-linking?code=...
        โ””โ”€โ”€ Victim's browser sends their session cookie automatically
            โ””โ”€โ”€ Server receives: attacker's code + admin's session
                โ””โ”€โ”€ Links attacker's social ID โ†’ admin's account! ๐Ÿ’ฅ

The application is vulnerable because:
โ””โ”€โ”€ No state parameter to validate
    โ””โ”€โ”€ Server blindly links whatever code arrives
        โ””โ”€โ”€ To whoever's session cookie is present

Paste this in the Body field of the exploit server:

<iframe src="https://YOUR-LAB-ID.web-security-academy.net/oauth-linking?code=YOUR_AUTHORIZATION_CODE"></iframe>

3. ๐Ÿ’พ Click "Store"

๐Ÿš€ Step 5 โ€” Deliver Exploit to Victim

  1. ๐ŸŽฏ Click "Deliver exploit to victim"
  2. โณ Wait a few seconds

What happens behind the scenes:

Victim (administrator) is logged in on the blog.
1. Victim receives the exploit link and opens it
   โ””โ”€โ”€ Their browser loads the exploit page

2. iframe loads /oauth-linking?code=ATTACKER_CODE
   โ””โ”€โ”€ Admin's session cookie sent automatically
       โ””โ”€โ”€ Cookie: session=admin_session_token

3. Application processes the callback:
   โ””โ”€โ”€ Exchanges code โ†’ gets attacker's social profile (peter.wiener)
       โ””โ”€โ”€ Links peter.wiener's social ID โ†’ admin's account
           โ””โ”€โ”€ CSRF attack complete! โœ“

๐ŸŽ‰ Step 6 โ€” Log In as Administrator

  1. ๐Ÿ‘ค Click "My account" on the blog
  2. ๐Ÿ”— Click "Log in with social media" option
  3. โœ๏ธ Login with social media credentials:
  • Username: peter.wiener
  • Password: hotdog

4. โœ… Authorize

What happens:

Social login flow:
1. OAuth provider confirms identity: peter.wiener
   โ””โ”€โ”€ Returns social ID

2. Blog application looks up social ID in database
   โ””โ”€โ”€ Finds: peter.wiener โ†’ administrator's account
       โ””โ”€โ”€ (Because of our exploit!)

3. Session created for administrator โœ“
   โ””โ”€โ”€ You're logged in as admin! ๐ŸŽฏ

๐Ÿ† Step 7 โ€” Delete Carlos and Solve Lab

  1. ๐ŸŒ Navigate to Admin panel (top navigation)
  2. ๐Ÿ—‘๏ธ Find carlos in the user list
  3. โŒ Click "Delete" next to carlos
  4. โœ… Lab solved!
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  โœ… Congratulations!                โ”‚
โ”‚                                     โ”‚
โ”‚  You successfully exploited         โ”‚
โ”‚  forced OAuth profile linking       โ”‚
โ”‚  to access the administrator        โ”‚
โ”‚  account and deleted carlos!        โ”‚
โ”‚                                     โ”‚
โ”‚  Lab: Forced OAuth profile linking  โ”‚
โ”‚  Status: SOLVED โœ“                   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

๐Ÿ”— Complete Attack Chain

Step 1: Login to blog as wiener (wiener:peter)
         โ””โ”€โ”€ Understand the account linking feature
         โ†“
Step 2: Complete full OAuth flow once to study it
         โ””โ”€โ”€ Social media credentials: peter.wiener:hotdog
         โ””โ”€โ”€ Confirm /auth URL has NO state parameter ๐Ÿšจ
         โ””โ”€โ”€ Confirm callback goes to /oauth-linking?code=...
         โ†“
Step 3: Turn on Burp Intercept โ†’ Click "Attach a social profile"
         โ””โ”€โ”€ Forward until you see GET /oauth-linking?code=XXXXX
         โ””โ”€โ”€ Right-click โ†’ Copy URL
         โ””โ”€โ”€ DROP the request (keep code unused!)
         โ†“
Step 4: Log out of blog
         โ””โ”€โ”€ Go to exploit server
         โ””โ”€โ”€ Create: <iframe src="/oauth-linking?code=XXXXX">
         โ””โ”€โ”€ Store exploit
         โ†“
Step 5: Deliver exploit to victim
         โ””โ”€โ”€ Admin's browser loads iframe
         โ””โ”€โ”€ Admin's session cookie sent
         โ””โ”€โ”€ Admin's account links to peter.wiener's social ID โœ“
         โ†“
Step 6: Click "Log in with social media"
         โ””โ”€โ”€ Login with peter.wiener:hotdog
         โ””โ”€โ”€ Logged in as administrator! ๐ŸŽฏ
         โ†“
Step 7: Admin panel โ†’ Delete carlos โ†’ Lab solved! ๐ŸŽ‰

โš™๏ธ Understanding the Vulnerability

OAuth State Parameter

Purpose of state parameter:

State Parameter Fundamentals:

Definition:
โ””โ”€โ”€ Cryptographically random value
    โ””โ”€โ”€ Tied to user's session
        โ””โ”€โ”€ Prevents CSRF attacks on OAuth flow

How it works (SECURE):

1. Application generates random state
   โ””โ”€โ”€ state = generate_random_token()

2. Store in user's session
   โ””โ”€โ”€ session['oauth_state'] = state

3. Include in authorization URL
   โ””โ”€โ”€ GET /auth?client_id=...&state=a7f3d9c2e5b8k1m4n6p9q2r5

4. OAuth provider returns state in callback
   โ””โ”€โ”€ GET /oauth-linking?code=xyz&state=a7f3d9c2e5b8k1m4n6p9q2r5

5. Application validates state
   โ””โ”€โ”€ if request_state == session['oauth_state']:
           # Proceed with linking
       else:
           # CSRF attack detected!
           abort(403)

Security guarantee:
โ””โ”€โ”€ Only the user who initiated OAuth flow
    โ””โ”€โ”€ Can complete the flow
        โ””โ”€โ”€ Attackers can't force victims to use attacker's codes

This lab's vulnerability:

Missing state validation:

Authorization URL:
GET /auth?client_id=xxx&redirect_uri=.../oauth-linking
โ””โ”€โ”€ No state parameter! โœ—

Callback URL:
GET /oauth-linking?code=xyz
โ””โ”€โ”€ No state parameter! โœ—

Server-side (VULNERABLE):
def oauth_linking(code):
    profile = exchange_code(code)
    current_user = get_current_user()  # from session cookie
    
    # โœ— CRITICAL FLAW: No CSRF protection!
    link_profile(current_user, profile)

Attack succeeds because:
โ”œโ”€โ”€ No state parameter to validate
โ”œโ”€โ”€ Server trusts any authenticated request
โ”œโ”€โ”€ Authorization code can come from anyone
โ””โ”€โ”€ Attacker's code + Victim's session = Account takeover!

Attack Prerequisites

Required conditions:

1. Account linking feature exists
   โ””โ”€โ”€ "Attach social profile" or similar

2. Missing state parameter
   โ””โ”€โ”€ Authorization URL has no state
       โ””โ”€โ”€ OR state not validated on callback

3. Authorization code usable in any session
   โ””โ”€โ”€ Code from attacker's OAuth flow
       โ””โ”€โ”€ Can be consumed by victim's session

4. Victim is authenticated
   โ””โ”€โ”€ Admin must be logged in to have account to link to

5. Attacker can deliver payload to victim
   โ””โ”€โ”€ Exploit server iframe

Attack fails if:
โ”œโ”€โ”€ State parameter properly validated โœ—
โ”œโ”€โ”€ Code tied to specific session โœ—
โ”œโ”€โ”€ CSRF tokens required โœ—
โ””โ”€โ”€ SameSite=Strict cookie attribute โœ—

Key Indicators of Vulnerability

Vulnerability indicators:

1. Authorization URL analysis:
   GET /auth?client_id=xxx&redirect_uri=.../oauth-linking&response_type=code
   โ””โ”€โ”€ โœ— No state parameter โ†’ VULNERABLE!

2. Callback endpoint is /oauth-linking (not /authenticate):
   GET /oauth-linking?code=xxx
   โ””โ”€โ”€ โœ— No state parameter โ†’ VULNERABLE!

3. Code works across different sessions:
   โ””โ”€โ”€ No session-binding on code โ†’ VULNERABLE!

๐Ÿ›ก๏ธ How to Fix (Secure Code)

Fix 1: Implement Proper State Validation

# โœ… COMPLETE SECURE IMPLEMENTATION

import secrets
import time
from flask import Flask, session, request, redirect, abort
@app.route('/oauth-linking')
def initiate_oauth_linking():
    # โœ… Generate cryptographically secure random state
    state = secrets.token_urlsafe(32)
    session['oauth_state'] = state
    session['oauth_timestamp'] = time.time()
    params = {
        'client_id': CLIENT_ID,
        'redirect_uri': REDIRECT_URI,
        'response_type': 'code',
        'scope': 'openid profile email',
        'state': state  # โœ… Include state!
    }
    return redirect(f"{OAUTH_PROVIDER}/auth?{urlencode(params)}")
@app.route('/oauth-linking')
def oauth_linking_callback():
    code = request.args.get('code')
    state = request.args.get('state')
    # โœ… VALIDATION: Check state exists and matches session
    if not state or state != session.get('oauth_state'):
        abort(403, 'CSRF detected: State mismatch')
    # โœ… Check not expired
    if time.time() - session.get('oauth_timestamp', 0) > 600:
        abort(400, 'OAuth session expired')
    # โœ… Clear one-time use state
    session.pop('oauth_state', None)
    session.pop('oauth_timestamp', None)
    # Exchange code and link profile
    token = exchange_code_for_token(code)
    user_info = get_user_info(token['access_token'])
    link_social_profile(get_current_user(), user_info)
    return redirect('/my-account?success=account_linked')

Fix 2: Additional Security Headers

# โœ… SECURITY HEADERS

@app.after_request
def set_security_headers(response):
    # โœ… Prevent clickjacking (defeats iframe attacks)
    response.headers['X-Frame-Options'] = 'DENY'
    response.headers['Content-Security-Policy'] = "frame-ancestors 'none'"
    return response
# Configure session cookie securely
app.config.update(
    SESSION_COOKIE_SECURE=True,
    SESSION_COOKIE_HTTPONLY=True,
    SESSION_COOKIE_SAMESITE='Lax',  # Blocks cross-site iframe requests
)

๐Ÿ‘ If this helped you โ€” clap it up (you can clap up to 50 times!)

๐Ÿ”” Follow for more writeups โ€” dropping soon

๐Ÿ”— Share with your pentest team

๐Ÿ’ฌ Drop a comment