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 Permanently
  • 302 Found
  • 303 See Other
  • 307 Temporary Redirect
  • 308 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 Location header containing a parameter value.
  • Read JavaScript for window.location assignments 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

  1. Avoid redirects based on user input. If you don’t need the parameter, remove it.
  2. Whitelist allowed redirect destinations. Match the full URL against an explicit list of permitted domains.
  3. 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.
  4. For OAuth/OIDC: Validate redirect_uri against registered values using exact string comparison, not prefix or substring matching.

References

HackerOne Reports

Cheat Sheets

Further Reading