Open Redirect: How Unvalidated Redirects Launder Phishing
How open redirects let attackers borrow your domain's trust to send victims to malicious sites, why filters fail, and how an allowlist stops it.
An open redirect looks harmless on its own. A URL on your site takes a parameter that says where to go next and sends the browser there. No data leaks, nothing is overwritten, the vulnerable page itself is never damaged. The value of the bug is entirely borrowed. What an attacker gets is your domain's good name printed at the front of a link that ends up somewhere hostile. In a world where users and security filters both judge a link by its starting domain, that is worth a great deal.
Open redirects rarely rank as the most severe finding in a report, and they are frequently dismissed. That dismissal is the reason they persist, and the reason phishing campaigns keep reaching for them.
The core idea
Applications legitimately redirect users all the time. After login, send them back to the page they came from. After an action, forward them to a confirmation. To remember the original destination, the app often stashes it in a URL parameter:
https://your-app.example/login?next=/dashboard
That is fine when next can only ever be an internal path. The vulnerability appears when the application takes whatever is in that parameter and redirects to it verbatim, including a full external URL:
https://your-app.example/login?next=https://evil.example/login
A victim who clicks sees a link that begins with your-app.example, a domain they trust and may have bookmarked. They land on evil.example, which has been built to look exactly like your login page. They type their password into it. The redirect did its job silently, and your domain supplied the credibility that made the lure convincing.
Why this is a phishing multiplier
Phishing succeeds or fails on whether the target believes the link. Two things judge a link before a human decides to click:
- The person, who glances at the visible domain and reads it as safe because it is one they know.
- The email or messaging security filter, which scores links partly on the reputation of the domain they point to.
An open redirect on a reputable domain satisfies both. The human sees a familiar brand. The filter sees a request to a trusted, well-established site and lets it through, because the malicious destination is hidden in a parameter rather than in the visible host. The redirect is the sleight of hand that converts your reputation into cover for someone else's attack.
Open redirects are often triaged as informational because the vulnerable page leaks nothing directly. Judge them by what they enable instead. A redirect on a bank, a government portal, or a widely trusted SaaS domain is a premium phishing asset, and it is exactly those high-trust domains where the bug does the most damage.
Beyond phishing
The trust an open redirect provides feeds other attacks:
- OAuth and SSO token theft. Authorization flows send tokens or codes to a redirect URI. If the redirect target can be steered to an attacker origin, those secrets can leak. This is why OAuth specifications insist on strict, pre-registered redirect URIs.
- Filter and control bypass. Server-side checks that allow requests to your own domain can be tricked when your domain then bounces the request onward, chaining an open redirect into requests the filter meant to block.
- Two-stage credential flows. An attacker can pass through your legitimate login, then use the redirect to hand the now-authenticated user to a page that harvests a second factor or a session.
Where open redirects hide
| Location | Typical parameter role |
|---|---|
| Login and logout flows | Remembering where to return the user after auth |
| OAuth and SSO callbacks | Carrying the post-authorization destination |
| Marketing and tracking links | Bouncing through a redirector to log the click |
| Language or region switchers | Returning the user to their prior page |
Legacy redirect, url, return, next, dest params | Generic "go here next" handlers |
DOM-based open redirects are a related class, where client-side JavaScript reads a value from the URL or fragment and assigns it to location, moving the same flaw into the browser.
Why filtering the URL fails
The tempting fix is to check that the destination "contains your domain" or "starts with your domain." Attackers have a long list of ways past this:
- Subdomain and lookalike tricks, where
your-app.example.evil.exampleoryour-app-example.evil.examplecontains your brand as a substring but is not your site. - The
@credential syntax, wherehttps://[email protected]/is parsed by the browser as a request toevil.examplewithyour-app.exampletreated as a username. - Protocol-relative URLs like
//evil.example, which the browser resolves to an external site while passing a naive "does not start with http" check. - Encoding and obfuscation, including URL-encoded characters, backslashes, and mixed forms that your validator normalizes differently from the browser.
Every one of these exploits a gap between how your check reads the string and how the browser interprets it. Blocklists lose this race by design.
How to defend against open redirects
The controls that hold up remove the attacker's ability to name an arbitrary destination.
- Do not redirect to user-supplied URLs at all where you can avoid it. Most "return here" needs can be met by redirecting only to internal, relative paths and rejecting anything that looks like an absolute URL or a protocol-relative one.
- Use an allowlist resolved from an opaque key. Instead of accepting a destination, accept a short identifier and look up the real URL server-side from a fixed table of approved destinations. The attacker never controls the URL, only which approved entry is chosen.
- Validate that internal redirects stay internal. If you accept a path, confirm it begins with a single
/and not//or/\, and reject anything containing a scheme or host. Parse with a real URL parser, then check the resulting host against your own, rather than string-matching the raw input. - Lock down OAuth redirect URIs. Pre-register exact redirect URIs and match them strictly, including path, with no wildcard host segments.
- Show an interstitial for unavoidable external redirects. Where a redirector genuinely must reach third-party URLs, route through a page that displays the full destination and requires a deliberate click, breaking the silent hand-off phishing relies on.
- Sanitize DOM sinks. In client-side code, never assign a URL read from
location, the query string, or the fragment directly tolocationorwindow.openwithout the same allowlist check.
Never decide a redirect is safe by searching the raw parameter for your domain name. Parse the value with a proper URL parser, read the resolved host, and compare that host to your allowlist. The vulnerability lives precisely in the gap between naive string matching and how the browser actually resolves the address.
A worked example of the phishing relay
Follow a single lure from craft to compromise to see why the redirect is the load-bearing part.
An attacker wants credentials for users of a trusted service. They find that the service's login flow accepts a next parameter and redirects to whatever it contains after authentication, including full external URLs. They register a lookalike domain and build a copy of the login page there. Then they construct the lure link so that it begins with the trusted service's own domain, carries the login path, and places their lookalike URL in the next parameter. The visible start of the link is the real, trusted brand.
They send this link in an email styled as a routine notice from the service. The recipient glances at the link, sees the familiar domain at the front, and trusts it. The organization's email security gateway scores the link partly on the reputation of the host it points at, sees a well-established, trusted domain, and delivers the message. Both the human and the filter judged the link by its starting domain, and both were satisfied.
The victim clicks. Their browser goes to the trusted service, which processes the request and then honors the next parameter by redirecting the browser onward to the attacker's lookalike page. The address bar may flash the trusted domain before landing on the copy. The victim, having started at a domain they trust, sees a login page that matches what they expect and enters their password. The credentials go to the attacker. The trusted service was never compromised. It contributed only one thing: the redirect that let the attacker begin the journey under a trusted name. Remove the redirect and the lure has to start on the attacker's own unknown domain, where both the human and the filter are far more likely to reject it.
Nothing about the vulnerable page is damaged, and no data leaks from it directly. Its entire contribution to the attack is lending its reputation to the front of a link. That is why open redirects are dangerous in proportion to how trusted the hosting domain is, and why a redirect on a bank, a government portal, or a widely used platform is worth far more to an attacker than the low severity score usually assigned to it.
The bypass techniques in detail
The reason blocklist-style validation fails is worth understanding precisely, because each bypass exploits a difference between how a naive check reads a string and how a browser resolves an address. Consider a check that tries to confirm the destination belongs to your-app.example.
- Substring and lookalike hosts. A check that asks whether the destination contains the string
your-app.examplepasseshttps://your-app.example.evil.example/, where the real registrable domain isevil.exampleand the brand is merely a subdomain label. It also passeshttps://your-app-example.evil.example/, where the brand appears with a hyphen. The browser resolves both to the attacker's site. - The credential syntax. A URL of the form
https://[email protected]/is parsed by the browser with everything before the at-sign treated as a userinfo component andevil.exampleas the actual host. A check that looks for the brand near the start of the string is fooled, because the brand really is near the start, just in the wrong role. - Protocol-relative URLs. A value like
//evil.example/pathhas no scheme. A browser resolves it against the current page's scheme and navigates toevil.example. A check that only rejects strings starting withhttplets it through, because it does not start withhttp. - Encoding and normalization gaps. Percent-encoding, backslashes that some parsers treat as forward slashes, doubled slashes, and mixed-case schemes all create forms that a validator may normalize one way and the browser another. Wherever the two normalizations differ, a bypass lives in the gap.
- Whitelisted-prefix confusion. A check that a value starts with an allowed path such as
/redirectcan be defeated by/redirect/../..//evil.examplestyle tricks or by values that are paths to the check but resolve as network locations to the browser.
The unifying point is that string inspection of a URL is not the same as parsing it. The only reliable approach is to parse the value with a real URL parser, read the resolved host, and compare that host to an allowlist, which is what the defenses below build on.
Detection signals
Open redirects can be found in code and watched for in traffic.
- Redirect responses whose destination came from input. In code review and dynamic testing, the signature is a response that sets the browser's location to a value derived from a request parameter, cookie, or fragment without an allowlist check. Any handler that echoes a user-supplied URL into a location header deserves scrutiny.
- Generic redirect parameter names. Parameters like
url,next,return,returnUrl,dest,redirect,continue, andrare the usual carriers. Inventorying every place these appear and checking how each is validated finds most instances. - Location headers pointing off-domain. In traffic monitoring, redirect responses from your application that send users to external hosts are worth logging and reviewing, especially from authentication and callback endpoints that should only ever redirect internally.
- DOM sinks fed by the URL. Client-side code that reads from the query string, the fragment, or the current location and assigns the value to the page location or opens a window with it is the DOM-based form. Static analysis for these sinks surfaces the browser-side variant.
- Spikes of outbound redirects to a new host. A sudden rise in redirects steering users to a freshly seen external domain can indicate a live phishing campaign abusing an existing open redirect.
How open redirect compares to related web flaws
Open redirect is one of several weaknesses that abuse trust in a URL or a host, and separating them clarifies which fix applies.
| Flaw | What the attacker controls | Who gets sent where | Primary impact |
|---|---|---|---|
| Open redirect (CWE-601) | The destination of a client redirect | The victim's browser, to an external site | Phishing credibility, token leakage in auth flows |
| Server-side request forgery | The destination of a server-side request | The server, to an internal or chosen host | Access to internal services and metadata |
| Host header injection | The host value the application trusts | The application's own generated links | Poisoned links, cache and password-reset abuse |
| Cross-site scripting | Script that runs in the victim's page | The victim's browser executes attacker code | Session theft, full client-side compromise |
The distinctions matter because the defenses do not transfer cleanly. An open redirect steers the victim's browser outward, so the fix is an allowlist of permitted destinations resolved server-side. Server-side request forgery steers the server, so the fix constrains where the server may connect, covered in SSRF explained. Host header injection abuses the host the application trusts when building its own URLs, addressed in host header injection explained. Grouping these as trust-abuse flaws is useful for reasoning about an application's attack surface, and keeping their fixes distinct is what actually closes each one. An open redirect chained into an authentication flow can also feed the others, for example by delivering a victim to a page that then attempts a cross-site attack, which is why closing the redirect removes a stepping stone as well as a standalone risk.
Common mistakes
- Treating the finding as purely informational. Because the vulnerable page leaks nothing directly, open redirects are often closed as low priority and left in place. Judged by what they enable, a redirect on a high-trust domain is a premium phishing asset, and the trust it borrows is exactly what makes the low severity score misleading.
- Blocklisting instead of allowlisting. Trying to enumerate bad destinations, or to confirm the brand appears in the string, loses to the bypasses above. Allowlisting the small set of destinations you actually permit is the model that holds.
- Validating with string operations rather than a parser. Checking prefixes and substrings reads the URL differently from the browser. Parsing and comparing the resolved host removes that gap.
- Forgetting the client side. Server-side validation does nothing for a DOM-based redirect where JavaScript reads the fragment and assigns it to the location. The same allowlist discipline has to apply in the browser.
- Wildcarding OAuth redirect URIs. Loosely matching pre-registered redirect URIs, especially with wildcard host segments, reintroduces the flaw in the exact place it does the most damage, by leaking authorization codes or tokens.
How the problem evolved
Open redirects have been recognized as a web weakness for a long time, cataloged as CWE-601 and covered by OWASP guidance on unvalidated redirects and forwards. Their prominence has tracked the rise of email and messaging security filters that score links by destination reputation. As those filters improved at blocking links to known-bad domains, attackers needed a way to launder their links through a trusted host, and open redirects on reputable domains became the tool for it. The technique also grew alongside federated login. OAuth and single sign-on flows carry secrets to a redirect URI, so a redirect that can be steered to an attacker origin turned from a phishing aid into a token-theft primitive, which is why the specifications insist on strictly pre-registered redirect URIs. The client-side variant emerged as applications moved logic into the browser, moving the same flaw into DOM sinks. The defensive consensus has settled on allowlists resolved from opaque keys and on parsing rather than string matching, because every attempt to filter destinations by inspecting the raw string has been outpaced by bypasses.
Frequently asked questions
Is an open redirect really a serious vulnerability? On its own it leaks nothing from the vulnerable page, which is why it is often rated low. Its seriousness comes from what it enables: laundering phishing links through a trusted domain and, in authentication flows, leaking tokens. On a high-trust domain it is a valuable attack asset.
Why does the trusted domain matter so much? Both people and email filters judge a link partly by the domain at its start. A redirect on a reputable domain satisfies both, so the malicious destination hidden in a parameter passes checks that would stop a link pointing straight at the attacker.
Why not just check that the destination contains our domain? Because a browser resolves a URL differently from a substring check. Subdomain tricks, the at-sign credential syntax, protocol-relative URLs, and encoding gaps all produce strings that contain your brand yet resolve to an attacker's host. Parse the URL and compare the resolved host instead.
What is the most robust fix? Accept an opaque key rather than a URL, and look up the real destination server-side from a fixed table of approved targets. The attacker never controls the URL, only which approved entry is selected, so no bypass on the URL string is possible.
How is a DOM-based open redirect different? It lives in client-side JavaScript that reads a value from the URL, query string, or fragment and assigns it to the browser location. The flaw is the same, but it runs in the browser, so it needs the allowlist check applied client-side, not only on the server.
What does an open redirect have to do with OAuth? Authorization flows deliver codes or tokens to a redirect URI. If that target can be steered to an attacker origin, the secrets can leak. This is why OAuth requires strict, pre-registered redirect URIs matched exactly, with no wildcard hosts.
If we must redirect to external sites, what reduces the risk? Route external hops through an interstitial page that shows the full destination and requires a deliberate click, which breaks the silent hand-off phishing relies on. Combine it with strict URL parsing. This reduces the risk without fully removing it, so reserve external redirects for cases that genuinely need them.
Open redirects trade on trust you spent years building, and they hand it to whoever crafts the link. Attackers hunt for them specifically because a redirect on a reputable domain makes their phishing convert. To see how these trust-abuse techniques fit into the wider exploitation landscape, our Exploit Intelligence dashboard tracks the methods and campaigns in active use. Stop redirecting to raw input, resolve destinations from an allowlist, and gate any unavoidable external hop behind a visible warning, and your domain stops working for the attacker.
Related guides
Sources & further reading
Related guides
- Clickjacking Explained: UI Redress Attacks & Frame Defenses
How clickjacking hijacks a user's clicks with transparent iframes, what an attacker can trigger, and how to block framing with headers and CSP.
- Command Injection: Shell Metacharacters & Safe APIs
How OS command injection breaks out of an intended command via shell metacharacters, and why argument-array APIs beat string concatenation.
- CSRF Explained: SameSite Cookies & Anti-CSRF Tokens
How cross-site request forgery rides a logged-in user's cookies to force state-changing requests, and how SameSite, tokens, and double-submit stop it.