TL;DR
Open redirects let an attacker abuse a trusted domain to send users to a malicious site. This post covers what they are, how to find them, bypass techniques, exploitation chains, and fixes.
What Are Redirects
HTTP redirects use 3xx status codes to send the client to a different URL:
301 Moved Permanently302 Found303 See Other307 Temporary Redirect308 Permanent Redirect
Redirects happen server-side (via Location header in the response) or client-side (via JavaScript or HTML meta refresh).
What Makes a Redirect “Open”
An open redirect exists when the application accepts an arbitrary URL in a redirect parameter and forwards the user there without validation.
Consider a signup flow:
https://example.com/signup?redirectUrl=https://example.com/login
After signup, the user is sent to the redirectUrl value. If the server doesn’t validate that value against a whitelist, an attacker can replace it:
https://example.com/signup?redirectUrl=https://attacker.com/
The user clicks what looks like a legitimate example.com link. They end up at attacker.com.
Why This Matters
The domain in the URL bar is the primary trust signal for most users. An open redirect on a trusted domain lets an attacker weaponize that trust for phishing, credential harvesting, or as a stepping stone for more complex attack chains.
Vulnerable Code Patterns
PHP
<?php
$url = $_GET['redirect_url'];
header('Location: ' . $url);
die();
No validation. The redirect_url parameter is passed directly to the Location header.
Java
response.sendRedirect(request.getParameter("u"));
Same pattern. Parameter u goes straight to sendRedirect().
JavaScript (Client-Side)
window.location.href = getUrlParam('next');
If getUrlParam pulls from the query string without checking the value, this is exploitable.
HTML Meta Refresh
<meta http-equiv="refresh" content="0;URL='http://attacker.com/'" />
Less common but still seen in older applications.
Finding Open Redirects
- Walk every endpoint that includes a URL parameter (
redirect,next,url,return,continue,dest,redir,redirect_uri). - Review proxy history for 3xx responses. Filter by
Locationheader containing a parameter value. - Read JavaScript for
window.locationassignments sourced from URL parameters. - Google dorking:
inurl:redirectUrl=http site:target.com - Focus on post-authentication flows (login, signup, password reset, OAuth callbacks) - these commonly use redirect parameters.
Bypass Techniques
When basic ?redirect_url=https://attacker.com is blocked, try:
| Technique | Payload | Why It Works |
|---|---|---|
| Double slashes | //attacker.com |
Protocol-relative URL, browser resolves to https://attacker.com |
| @ notation | [email protected] |
Userinfo syntax - target.com becomes the username, attacker.com is the host |
| JavaScript protocol | javascript:alert(1) |
Bypasses domain-based checks entirely |
| Subdomain confusion | target.com.attacker.com |
Weak regex matching target.com anywhere in the string |
| Backslashes | https:/\attacker.com |
Some URL parsers normalize \ to / |
| Chinese dot separator | attacker%E3%80%82com |
Unicode character 。 interpreted as . by some parsers |
| RTL override | %E2%80%AE |
Unicode right-to-left override reverses visual display of the URL |
| IP representations | http://0x7f000001 |
Hex, octal, or decimal IP encoding bypasses domain-string checks |
| No slashes | https:attacker.com |
Some parsers accept this as valid |
| Appended TLD | redirect_url=.jp |
Results in target.com.jp - different domain entirely |
Test multiple techniques in combination. Parsers are inconsistent across languages and frameworks.
Exploitation
Phishing via Password Reset
Target has a password reset flow:
https://example.com/reset-password/<token>?redirect=https://example.com/login
Modify the redirect:
https://example.com/reset-password/<token>?redirect=https://attacker.com/login
User resets their password, gets redirected to a fake login page, enters the new credentials. Attacker captures them.
Chaining with SSRF
If an SSRF endpoint restricts requests to a specific domain:
https://example.com/?fetch=https://images.example.com/cat.jpg
And you find an open redirect on a subdomain:
https://test.example.com/?redirect_url=https://attacker.com/
Chain them:
https://example.com/?fetch=https://test.example.com/?redirect_url=https://attacker.com/
The SSRF hits test.example.com (allowed), which redirects to attacker.com. The domain restriction is bypassed.
SSRF endpoint → test.example.com (allowed) → redirect → attacker.com
Open redirects on their own are often rated low severity. Chained with SSRF, OAuth token theft, or post-auth flows, the impact jumps significantly.
Mitigation
- Avoid redirects based on user input. If you don’t need the parameter, remove it.
- Whitelist allowed redirect destinations. Match the full URL against an explicit list of permitted domains.
- Don’t use pattern matching. Regex-based domain validation is consistently bypassed. Use URL parsing libraries to extract the host, then compare against the whitelist.
- For OAuth/OIDC: Validate
redirect_uriagainst registered values using exact string comparison, not prefix or substring matching.
References
HackerOne Reports
- #226408 - Shopify
- #211213 - Nextcloud
- #246897 - Twitter
- #103772 - Shopify
- #309058 - WordPress
- #260744 - Twitter (Open Redirect + XSS)
- #320376 - HackerOne
- #299403 - HackerOne
- #119236 - Uber
- #126203 - Uber
- #144525 - New Relic
Cheat Sheets
- EdOverflow - Open Redirect Cheat Sheet
- cujanovic - Open Redirect Payloads
- OWASP - Unvalidated Redirects and Forwards