Open Redirect Vulnerability
1. Definition
An Open Redirect vulnerability occurs when a web application accepts a user-controlled parameter and uses it to redirect users to an external URL without proper validation.
While open redirects may seem low-severity on their own, they are highly valuable to attackers because they abuse the trust users place in legitimate domains. A phishing link using trusted-bank.com/redirect?url=evil.com appears more legitimate than a direct link to evil.com.
2. Technical Explanation
Many legitimate applications need redirect functionality:
- Post-login redirects: Return users to their original page after authentication
- Marketing tracking: Redirect through tracking systems before reaching destinations
- Single Sign-On: Redirect between identity providers and applications
Vulnerable Pattern:
https://example.com/login?redirect=https://evil.comAfter successful login, the application redirects to evil.com without validation.
Common Vulnerable Parameters:
redirect,redirect_uri,return,returnUrlnext,url,target,destinationcontinue,goto,out,redir
Bypass Techniques: Attackers bypass weak validation using various tricks:
# Basic
?redirect=https://evil.com
# Protocol-relative
?redirect=//evil.com
# Domain confusion
?redirect=https://example.com.evil.com
?redirect=https://[email protected]
?redirect=https://evil.com/example.com
# URL encoding
?redirect=https%3A%2F%2Fevil.com
# Parameter pollution
?redirect=https://example.com&redirect=https://evil.com3. Attack Flow
sequenceDiagram
participant Victim
participant Attacker
participant TrustedSite as Trusted Site
participant PhishingSite as Phishing Site
Attacker->>Victim: Sends phishing email with link<br/>trusted-bank.com/redirect?url=evil.com
Note over Victim: Link appears legitimate<br/>Domain is trusted-bank.com
Victim->>TrustedSite: Clicks link to trusted-bank.com
TrustedSite->>TrustedSite: Processes redirect parameter
TrustedSite-->>Victim: 302 Redirect to evil.com
Victim->>PhishingSite: Browser follows redirect
Note over PhishingSite: Fake login page<br/>identical to trusted-bank.com
Victim->>PhishingSite: Enters credentials
PhishingSite->>Attacker: Credentials captured4. Real-World Case Study: Google OAuth Open Redirect (2016)
Target: Google OAuth 2.0 authentication flow. Vulnerability Class: Open Redirect in OAuth callback.
The Vulnerability: In 2016, researcher Egor Homakov discovered that Google’s OAuth implementation had an open redirect vulnerability in the redirect_uri parameter validation.
The Attack:
- OAuth requires applications to register allowed
redirect_urivalues. - Google’s validation was too permissive for certain registered domains.
- An attacker could find a legitimate application with an open redirect on its own domain.
- Chain: Google OAuth -> Legitimate App (with open redirect) -> Attacker site.
Attack Chain Example:
1. User clicks: accounts.google.com/oauth?redirect_uri=legitimate-app.com
2. Google validates: legitimate-app.com is registered - OK
3. Google redirects to: legitimate-app.com/callback?code=AUTH_CODE
4. legitimate-app.com has open redirect: /goto?url=evil.com
5. Attacker receives: evil.com?code=AUTH_CODE
6. Attacker exchanges code for access tokenImpact: This allowed attackers to steal OAuth tokens by chaining vulnerabilities. Google strengthened their redirect_uri validation and encouraged stricter matching patterns.
5. Detailed Defense Strategies
A. Allowlist Validation
Only allow redirects to pre-approved destinations.
const ALLOWED_DOMAINS = [
'example.com',
'subdomain.example.com',
'partner-site.com'
];
function validateRedirect(url) {
try {
const parsed = new URL(url);
return ALLOWED_DOMAINS.includes(parsed.hostname);
} catch {
return false;
}
}B. Relative URL Only
Restrict redirects to relative paths (same-origin only).
function safeRedirect(url) {
// Only allow paths starting with /
if (url.startsWith('/') && !url.startsWith('//')) {
return url;
}
return '/'; // Default safe redirect
}Warning: Be careful with protocol-relative URLs (//evil.com).
C. Indirect Reference Maps
Use tokens instead of direct URLs.
const REDIRECT_MAP = {
'dashboard': '/user/dashboard',
'settings': '/user/settings',
'logout': '/auth/logout'
};
// Usage: /redirect?target=dashboard
function handleRedirect(target) {
const destination = REDIRECT_MAP[target];
if (destination) {
return redirect(destination);
}
return redirect('/');
}D. User Confirmation
For external redirects, show a warning page.
<div class="redirect-warning">
<h2>You are leaving example.com</h2>
<p>You are being redirected to an external site:</p>
<p><strong>https://external-site.com</strong></p>
<p>We are not responsible for the content of external sites.</p>
<a href="https://external-site.com">Continue</a>
<a href="/">Go back to example.com</a>
</div>E. Strict OAuth Configuration
For OAuth implementations:
- Exact Match: Require exact
redirect_urimatching, not prefix matching. - No Wildcards: Avoid wildcard patterns in registered redirect URIs.
- HTTPS Only: Only allow HTTPS redirect URIs in production.
# Good: Exact match only
Registered: https://app.example.com/oauth/callback
Valid: https://app.example.com/oauth/callback
Invalid: https://app.example.com/oauth/callback/evil
# Bad: Prefix matching
Registered: https://app.example.com/
Valid: https://app.example.com/anything <- Dangerous