cd ../blog

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_uri and SAML RelayState.
  • 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 confusionnext=https:/\evil.com or next=/\evil.com; browsers normalize \ to /, validators often do not.
  • Allowlist substring — if it requires the string app.example.com to appear, satisfy it elsewhere: next=https://app.example.com.evil.com or next=https://evil.com/app.example.com or next=https://evil.com?app.example.com.
  • @ userinfo tricknext=https://app.example.com@evil.com; everything before @ is credentials, the real host is evil.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 authorization code or implicit-flow access_token rides 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.