Open Redirect: The Low-Severity Bug That Unlocks Bigger Ones
An unvalidated redirect target sends victims to attacker sites and serves as a gadget for OAuth token theft and SSRF. We cover finding redirect parameters and bypassing weak validators.
An open redirect is an endpoint that sends the browser to a URL taken from user input without verifying it stays on-site. On its own it is a phishing aid; chained, it is a high-value gadget — stealing OAuth codes, satisfying an SSRF allowlist, or bouncing past a redirect-based filter. The skill is finding the parameter and defeating whatever half-validation guards it.
Where it hides
Redirect parameters cluster around navigation and authentication flows. Hunt for query/body fields whose value is a URL or path:
- Post-login/logout returns:
?returnUrl=,?next=,?redirect=,?continue=,?dest=,?url=,?return_to=. - "Back to", "continue to", and interstitial "you are leaving the site" pages.
- OAuth/SSO
redirect_uriand SAMLRelayState. - Email-link landing pages and shortlink expanders.
The detection method is to point the parameter at an external host and see whether the response bounces there — a 302 with your domain in Location, or a client-side redirect to it:
GET /login?next=https://evil.com HTTP/1.1
Host: app.example.com
A response of 302 Location: https://evil.com (or a meta-refresh/JS redirect to it) is an open redirect. Map every redirect parameter quickly by replaying a URL list with the value swapped and grepping for your host in the Location header:
cat urls.txt | qsreplace 'https://evil.com' | while read u; do
loc=$(curl -s -o /dev/null -w '%{redirect_url}' "$u")
echo "$loc" | grep -q 'evil.com' && echo "OPEN REDIRECT: $u -> $loc"
done
Reproducing it
When the value is reflected raw into Location, the PoC is the URL itself — sending a victim to https://app.example.com/login?next=https://evil.com lands them on your site while the address bar started on the trusted domain.
Most targets have a validator, so the work is bypassing it. Walk the common weaknesses, watching which variant still redirects off-site:
- Scheme-relative URL — drop the scheme so the browser keeps the host:
next=//evil.com. - Backslash confusion —
next=https:/\evil.comornext=/\evil.com; browsers normalize\to/, validators often do not. - Allowlist substring — if it requires the string
app.example.comto appear, satisfy it elsewhere:next=https://app.example.com.evil.comornext=https://evil.com/app.example.comornext=https://evil.com?app.example.com. @userinfo trick —next=https://app.example.com@evil.com; everything before@is credentials, the real host isevil.com.- Whitelisted-host open redirect — if only a relative path is allowed, find a second redirect on-site and stack it.
A compact list of payloads to fire at any redirect parameter:
//evil.com
/\evil.com
https:/\evil.com
https://app.example.com@evil.com
https://app.example.com.evil.com
https://evil.com\@app.example.com
//evil.com/%2f..
Confirm by following redirects and checking the final host:
curl -s -o /dev/null -w '%{url_effective}\n' -L \
"https://app.example.com/login?next=//evil.com"
# final URL on evil.com == bypass succeeded
Going further
The real value is as a chain link. Demonstrate one of these escalations to lift it above "just phishing":
- OAuth code/token theft. If the open redirect lives on a domain the OAuth provider accepts as
redirect_uri(exact-match satisfied, then bounced), the authorizationcodeor implicit-flowaccess_tokenrides through your redirect to an attacker host. Show the code landing on your server. - SSRF allowlist bypass. When a server-side fetcher only allows the app's own domain, point it at the open-redirect endpoint, which 302s onward to an internal address — the fetcher follows and reaches
169.254.169.254. - Filter/WAF bypass. Use the trusted-domain redirect to smuggle a victim into a payload-bearing URL that direct links would block.
A practical recon habit is to fire the bypass list at every url/next/return style parameter and follow redirects, logging the effective host. Capture the request, the off-site Location, and — for a chain — the downstream effect (the OAuth code on your listener, or the internal response via SSRF). Test only on authorized targets and use a benign destination you control.