What is an Open Redirect Vulnerability?

An open redirect is a vulnerability that occurs when a web application accepts a user-controlled parameter to determine where to send the browser after completing some action, and fails to validate that the destination is safe. The server issues an HTTP redirect (a 301 or 302 response) to whatever URL the attacker specifies, effectively turning a trusted domain into a launchpad for phishing, credential theft, and more sophisticated attack chains.

Open redirects are deceptively simple. The vulnerable code might be a single line that reads a redirect_url query parameter and passes it to an HTTP Location header. But the consequences are severe: an attacker can craft a link that starts with your trusted domain and lands the victim on a malicious site, inheriting every ounce of trust your brand has earned.

How Open Redirects Work

Most web applications need to redirect users at some point. After logging in, you get sent back to the page you were trying to visit. After clicking a link in an email, you pass through a tracking redirect. After OAuth authorization, you return to the application. In each case, the application needs to know where to send you.

The vulnerability arises when this destination is controlled by user input without proper validation. Consider a login page with a URL like:

https://example.com/login?return_to=/dashboard

After successful authentication, the server redirects to /dashboard. But what if an attacker changes the parameter?

https://example.com/login?return_to=https://evil.com/steal-creds

If the server blindly redirects to whatever return_to contains, the user lands on evil.com after logging in with their real credentials. The attacker's page can mimic the original site and prompt for additional information ("Your session expired, please log in again") or silently capture tokens passed in URL fragments.

Victim Browser example.com Trusted Application evil.com Phishing Page 1. Clicks link 2. 302 Redirect 3. Browser follows redirect to evil.com Crafted URL: https://example.com/login?return_to=https://evil.com/phish

Common Redirect Parameters

Open redirects hide in many parameter names. Attackers scan for all of these:

The vulnerability exists regardless of the parameter name. What matters is whether the server validates the destination before issuing the redirect.

Exploitation for Phishing

The most immediate exploitation of an open redirect is phishing. Users are trained to check the domain in a URL before clicking. A link like https://yourbank.com/redirect?url=https://evil.com passes visual inspection because the domain is yourbank.com. Security awareness training, email filters, and corporate URL scanners often allowlist known-good domains, so a link starting with your bank's URL will sail through filters that would block a direct link to evil.com.

The phishing page can be an exact replica of the login form. Since the victim just clicked a link on the legitimate domain (and may have even successfully authenticated), they have no reason to suspect they have been redirected elsewhere. Modern phishing kits can act as transparent proxies, relaying credentials to the real site in real-time and capturing session cookies, bypassing even multi-factor authentication.

Chaining with OAuth and SSO Flows

Open redirects become far more dangerous when they exist on domains that participate in OAuth 2.0 or Single Sign-On (SSO) flows. These protocols rely heavily on redirect URIs, and a mismatch between the application's registered redirect URI and where tokens actually end up can have catastrophic consequences.

OAuth Authorization Code Theft

In a standard OAuth 2.0 authorization code flow, the user authenticates with an identity provider (IdP) and is redirected back to the application's redirect_uri with an authorization code appended to the URL. The application exchanges this code for an access token.

If the application at client.example.com has an open redirect and has registered https://client.example.com/callback as its redirect URI, an attacker can construct a flow like this:

  1. The attacker initiates the OAuth flow with the identity provider, specifying redirect_uri=https://client.example.com/callback
  2. After authentication, the IdP redirects to https://client.example.com/callback?code=AUTHZ_CODE
  3. The application processes the callback, and if the user then hits the open redirect (perhaps via a next parameter embedded in state), the authorization code or access token can leak via the Referer header to the attacker's site

More directly, some OAuth implementations perform loose matching on redirect URIs. If the IdP only checks that the redirect URI starts with the registered URI, an attacker might register https://client.example.com/callback but use https://client.example.com/callback/../redirect?url=https://evil.com. Path traversal and URL normalization differences between the IdP's validator and the actual HTTP routing can enable this attack.

Victim Browser IdP OAuth Server Client App Open Redirect Attacker evil.com 1. /authorize?redirect_uri=client.com/cb 2. Login prompt 3. Credentials 4. 302 to /cb?code=AUTHZ_CODE 5. Open redirect leaks code 6. Attacker exchanges code for access token

SAML and SSO Relay State Abuse

SAML-based SSO uses a RelayState parameter to remember where the user should end up after authentication. If the service provider does not validate RelayState, it becomes an open redirect. The user authenticates with the corporate identity provider, a valid SAML assertion is generated, and then the service provider redirects the user to the attacker-controlled URL embedded in RelayState. The SAML assertion itself may travel along, leaking session information.

Bypassing SSRF Protections

Open redirects on internal or trusted services can be weaponized to bypass Server-Side Request Forgery (SSRF) protections. Many SSRF defenses work by validating the initial URL before making the request. They check whether the hostname resolves to a public IP address and whether the domain is on an allowlist. But if the server follows redirects, the validation only applies to the first hop.

Consider a server that fetches URLs to generate link previews. It validates that the URL points to a public IP, then follows redirects. An attacker can submit:

https://trusted-internal-app.corp/redirect?url=http://169.254.169.254/latest/meta-data/

The SSRF validation sees trusted-internal-app.corp, which is on the allowlist. The server makes the request. The internal app responds with a 302 redirect to http://169.254.169.254/latest/meta-data/ (the cloud metadata endpoint). The server follows the redirect and fetches the instance metadata, which can contain IAM credentials, API keys, and other sensitive data.

This pattern was central to the 2019 Capital One breach, where SSRF combined with overly permissive IAM roles allowed an attacker to access over 100 million customer records from AWS S3. While that specific incident involved a WAF misconfiguration rather than an open redirect, the technique of chaining SSRF with redirects to reach cloud metadata services is a well-established attack pattern.

Attacker Crafted URL App Server Fetches URLs Internal App Open Redirect 169.254.169.254 Cloud Metadata 1. URL 2. Fetch 3. 302 4. Follows redirect IAM credentials, API keys leaked to attacker

URL Parsing Inconsistencies

Defending against open redirects seems simple: just check that the redirect URL points to your own domain. In practice, URL parsing is surprisingly complex, and different components in the stack may parse the same URL differently. Attackers exploit these inconsistencies to bypass validation.

The Backslash Trick

Some URL parsers treat backslashes as path separators, while others treat them as part of the hostname. The URL https://example.com\@evil.com is parsed differently across browsers and server-side libraries. Some see the host as example.com (treating \@evil.com as a path), while others see evil.com (treating example.com\ as the userinfo portion of the URL). A server-side validator might see example.com and approve it, while the browser interprets it as evil.com.

The @ Symbol and Userinfo

URLs support a userinfo component before the hostname: https://user:pass@hostname/path. An attacker can craft https://[email protected]/, which looks like it points to example.com at a casual glance but actually points to evil.com with the userinfo example.com. Browser address bars handle this inconsistently, and many server-side URL parsers accept it.

Protocol-Relative URLs

A URL like //evil.com is a protocol-relative URL that inherits the scheme from the current page. Some validation code checks for http:// or https:// prefixes on redirect targets but misses //, allowing the redirect to an external domain. Similarly, ///evil.com or ////evil.com may bypass checks that look for exactly two slashes.

Unicode and Encoded Characters

URL encoding, double encoding, and Unicode normalization create further opportunities. https://example.com%40evil.com, https://example.com%2F%2Fevil.com, and URLs using Unicode characters that normalize to ASCII slashes or dots can all confuse validators. The validator checks the raw string, the HTTP client decodes it, and the resulting URL points somewhere unintended.

Null Bytes and Whitespace

Some parsers truncate URLs at null bytes (%00), while others include them. The URL https://example.com%00.evil.com might pass a suffix check (it ends with .evil.com... wait, or example.com?). Similarly, tabs, newlines, and other whitespace characters embedded in URLs are handled inconsistently across libraries.

Common Bypass Techniques

A non-exhaustive list of tricks attackers use to bypass open redirect protections:

https://evil.com                          # Direct external URL
//evil.com                                # Protocol-relative
/\evil.com                                # Backslash as separator
https://[email protected]              # Userinfo abuse
https://example.com.evil.com              # Subdomain of evil.com
https://evil.com#.example.com             # Fragment after actual host
https://evil.com?.example.com             # Query as fake domain
https://example.com%252F%252Fevil.com     # Double-encoded slashes
/%0D%0ALocation:%20https://evil.com       # CRLF injection
https://evil.com/example.com              # Path confusion
javascript:alert(1)//example.com          # JavaScript scheme

Each of these exploits a specific parsing inconsistency or validation gap. Robust defense must account for all of them.

JavaScript-Based Redirects

Not all open redirects use HTTP 3xx responses. Client-side redirects via JavaScript are equally dangerous:

// Vulnerable pattern
const params = new URLSearchParams(window.location.search);
window.location = params.get('next');

If the next parameter is set to javascript:alert(document.cookie), some browsers will execute the JavaScript instead of navigating. This turns an open redirect into a cross-site scripting (XSS) vulnerability. Even when the javascript: scheme is blocked, data: URIs and other exotic schemes can achieve similar results.

Client-side redirects via window.location.href, window.location.assign(), window.location.replace(), and meta http-equiv="refresh" tags are all potential vectors. Framework-specific methods like React Router's navigate() or Angular's router.navigateByUrl() may also be vulnerable if they accept user input.

Defense Strategies

Defending against open redirects requires multiple layers. No single check is sufficient because URL parsing is inherently complex and attackers are creative at finding edge cases.

1. Use an Allowlist of Permitted Destinations

The most secure approach is to maintain an explicit list of permitted redirect destinations. Instead of passing a full URL, pass an identifier that maps to a pre-configured URL:

# Instead of:
/login?return_to=https://app.example.com/dashboard

# Use:
/login?return_to=dashboard

# Server-side mapping:
ALLOWED_REDIRECTS = {
    "dashboard": "/dashboard",
    "settings": "/settings",
    "billing": "/billing"
}

This eliminates the entire class of vulnerability because the user never controls the actual URL. The identifier is just a lookup key, and unknown keys default to a safe destination like the home page.

2. Restrict to Relative URLs (Same-Origin)

If you must accept URL paths, restrict to relative paths that stay on the same origin. Parse the input as a URL, reject anything with a scheme or host, and ensure the path starts with a single / (not //):

def safe_redirect(target):
    parsed = urlparse(target)
    # Reject anything with a scheme or netloc
    if parsed.scheme or parsed.netloc:
        return "/"
    # Reject protocol-relative URLs
    if target.startswith("//"):
        return "/"
    # Reject backslash tricks
    if "\\" in target:
        return "/"
    # Must start with /
    if not target.startswith("/"):
        return "/"
    return target

Be aware that this approach still has edge cases. The path /\evil.com can be interpreted as a host in some contexts. Always canonicalize the URL after validation to ensure the server and browser interpret it the same way.

3. Domain Validation with a Parsed URL

If you must allow absolute URLs (e.g., for OAuth or multi-domain applications), parse the URL using a robust library and validate the extracted hostname against an allowlist of permitted domains:

ALLOWED_HOSTS = {"example.com", "app.example.com", "api.example.com"}

def validate_redirect(url):
    try:
        parsed = urlparse(url)
    except ValueError:
        return False
    # Must be http or https
    if parsed.scheme not in ("http", "https"):
        return False
    # Exact hostname match against allowlist
    if parsed.hostname not in ALLOWED_HOSTS:
        return False
    return True

Crucially, match the hostname exactly -- do not use substring matching, suffix matching, or regex. The host evil-example.com would pass a suffix check for example.com. And always extract the hostname from a parsed URL object rather than using string manipulation on the raw URL.

4. Token-Based Redirects

For cases where redirect destinations must be dynamic, use a signed or HMAC'd token that encodes the destination. The server generates a redirect URL with a token, and when the redirect happens, it verifies the token before following it:

# Generate a redirect token
token = hmac_sign(secret_key, target_url + timestamp)
redirect_url = f"/redirect?url={target_url}&token={token}&ts={timestamp}"

# Verify on redirect
def handle_redirect(url, token, timestamp):
    if time.time() - timestamp > 300:  # 5 minute expiry
        return abort(400)
    expected = hmac_sign(secret_key, url + timestamp)
    if not hmac.compare_digest(token, expected):
        return abort(400)
    return redirect(url)

This ensures that only redirect URLs generated by the server can be followed. An attacker cannot forge a valid token for an arbitrary URL without knowing the secret key.

5. Interstitial Warning Pages

When redirecting to an external URL is a feature (e.g., link shorteners, link aggregators), show an interstitial page warning the user they are leaving the site. This does not prevent the redirect but gives the user a chance to verify the destination before proceeding. Google, Slack, and many other services use this pattern.

6. Set the Referrer-Policy Header

Even with proper redirect validation, sensitive information can leak via the Referer header. Set Referrer-Policy: no-referrer or Referrer-Policy: same-origin to prevent tokens or authorization codes in URLs from being sent to external sites.

Real-World CVEs

Open redirects are common enough that the CVE database contains thousands of entries. Here are notable examples that illustrate the range of impact:

CVE-2023-45812: Thrust Wallet Browser Extension

The Trust Wallet browser extension contained an open redirect that allowed attackers to redirect users to malicious sites after interacting with the wallet, potentially leading to phishing for seed phrases and private keys.

CVE-2023-22726: act (GitHub Actions Local Runner)

The act tool, used to run GitHub Actions locally, had an open redirect vulnerability in its artifact server that could be chained with other issues to achieve code execution on the developer's machine.

CVE-2021-21289: Mechanize Ruby Gem

The Mechanize library for Ruby automatically followed redirects, and an open redirect on a trusted site could cause it to make requests to internal services. This is the SSRF-via-redirect pattern: the library validated the initial URL but followed redirects to arbitrary destinations.

CVE-2020-26943: OpenAM / ForgeRock

ForgeRock's OpenAM identity platform had an open redirect in its OAuth 2.0 implementation. Because OpenAM is used as an SSO provider, the open redirect could be used to steal authorization codes and access tokens. This is precisely the OAuth-chaining attack described above, affecting enterprise SSO deployments globally.

CVE-2019-19844: Django

Django's password reset mechanism used the HTTP Host header to construct password reset links. An attacker could send a password reset request with a spoofed Host header, causing the reset email to contain a link pointing to the attacker's site. When the victim clicked the link, they would enter their new password on the attacker's page. While technically a host header injection rather than a classic open redirect, the underlying pattern is the same: unvalidated user input determining a redirect destination.

CVE-2017-8451: Kibana

Elasticsearch's Kibana dashboard had an open redirect that allowed attackers to craft URLs pointing to Kibana's domain that would redirect to arbitrary external sites. Given that Kibana is typically deployed on internal networks and used by administrators with elevated privileges, this open redirect was a serious phishing vector for credential theft in corporate environments.

Severity and OWASP Classification

Open redirects appear in the OWASP Top 10. In the 2017 edition, they were explicitly listed as category A10: "Unvalidated Redirects and Forwards." In the 2021 revision, they are covered under A1: "Broken Access Control," which reflects the broader industry consensus that open redirects are often chained with other vulnerabilities to break access controls.

OWASP's testing guide (WSTG-CLNT-04) provides specific testing procedures for open redirects. The CWE classification is CWE-601: URL Redirection to Untrusted Site ('Open Redirect').

Bug bounty programs have an inconsistent relationship with open redirects. Many programs classify them as low or informational severity when standalone, but medium or high when chained with other vulnerabilities (OAuth token theft, SSRF bypass, XSS via javascript: URLs). Google's Vulnerability Reward Program, for example, accepts open redirects on Google domains because of the phishing risk associated with Google's trusted brand.

CVSS Scoring

A standalone open redirect typically receives a CVSS score of 4.7 to 6.1 (medium). When chained with OAuth token theft, the score can rise to 7.5 to 8.8 (high). When chained with SSRF to access cloud metadata, the effective severity can be critical (9.0+), though the open redirect itself is only one link in the chain.

Open Redirects in the Network Context

Open redirects are a web application vulnerability, but they intersect with network infrastructure in meaningful ways. Phishing links that use open redirects on trusted domains are more likely to pass email security gateways, corporate proxies, and DNS-based content filters. The initial DNS resolution and TCP connection go to the legitimate server, so network-level monitoring sees only traffic to a trusted IP address. The redirect happens at the HTTP layer, invisible to network-level analysis.

From a network routing perspective, you can investigate suspicious URLs by looking up the IP addresses they resolve to. If a phishing link claims to go to yourbank.com, you can verify that the resolved IP actually belongs to your bank's autonomous system. After the redirect, though, the browser is on an entirely different server -- potentially hosted on a bulletproof hosting provider in a different AS altogether.

Testing for Open Redirects

When testing a web application for open redirect vulnerabilities, systematically check every parameter that could influence navigation:

  1. Identify all redirect parameters -- crawl the application and catalog every parameter that appears to control a redirect (query parameters, form fields, headers like Host and X-Forwarded-Host).
  2. Test with an external URL -- set the parameter to https://evil.com and check if the response is a 3xx redirect to that URL.
  3. Test bypass techniques -- if the direct URL is blocked, try protocol-relative URLs (//evil.com), backslash tricks (/\evil.com), URL encoding, double encoding, and unicode characters.
  4. Check JavaScript redirects -- look for client-side code that reads URL parameters and assigns them to window.location. Test with javascript: and data: URIs.
  5. Test OAuth/SSO flows -- check whether the redirect_uri in OAuth flows is strictly validated. Try appending paths, using different ports, and using subdomains.
  6. Verify SSRF implications -- if the application fetches URLs server-side, test whether an open redirect on an allowlisted host can be used to reach internal services.

Automated scanners like Burp Suite, OWASP ZAP, and Nuclei include checks for open redirects, but manual testing is essential because the bypass techniques often depend on the specific URL parsing library and validation logic used by the target application.

Framework-Specific Guidance

Most modern web frameworks provide utilities to handle redirects safely, but developers must use them correctly:

Related Security Topics

Open redirects rarely exist in isolation. Understanding related vulnerabilities helps you see the full attack surface:

The connection between these vulnerability classes underscores a broader principle: security controls that validate input at one point in a request lifecycle but not at subsequent points create gaps that attackers chain together. An open redirect is "just a redirect" until it becomes the pivot point in an attack that steals access tokens, exfiltrates cloud credentials, or delivers malware to high-value targets.

See BGP routing data in real time

Open Looking Glass
More Articles
How TLS/HTTPS Works: Securing the Internet's Traffic
Certificate Transparency: How CT Logs Secure the Web's PKI
How Firewalls Work: Packet Filtering, Stateful Inspection, and Beyond
What is Cross-Site Scripting (XSS)?
What is Cross-Site Request Forgery (CSRF)?
What is Server-Side Request Forgery (SSRF)?