Open Redirect Vulnerability: Risks, Examples & Prevention
An open redirect vulnerability exists when a web application accepts a URL as a parameter and redirects users to that URL without validating whether it's a safe destination. While it might seem like a low-severity issue, open redirects are consistently abused for sophisticated phishing attacks, OAuth flow hijacking, and as a component in SSRF exploit chains — all leveraging the trust users place in your domain.
Check your application for open redirects and 79 other vulnerabilities — [scan free with ZeriFlow](https://zeriflow.com).
How Open Redirect Vulnerabilities Work
The pattern appears in countless web applications. After login, send users to where they were going. After an action, redirect back. It looks innocent:
https://legitimate-company.com/login?next=/dashboard
https://legitimate-company.com/logout?redirect=https://legitimate-company.com/The vulnerability arises when the next or redirect parameter isn't validated:
# Vulnerable Python/Flask example
from flask import redirect, request
@app.route('/login', methods=['POST'])
def login():
# ... authenticate user ...
next_url = request.args.get('next', '/')
return redirect(next_url) # DANGEROUS: redirects to any URLAn attacker crafts:
https://legitimate-company.com/login?next=https://evil-phishing-site.comThe user authenticates on the real site, then gets redirected to the attacker's page — which can be a pixel-perfect clone asking them to "re-enter" credentials. The browser address bar showed legitimate-company.com during authentication, so the user has no reason to be suspicious.
Why Open Redirects Are More Dangerous Than They Appear
Phishing Bypass
Email security gateways and anti-phishing tools look for malicious domains in URLs. An open redirect on a trusted domain becomes a proxy:
https://google.com/url?q=https://phishing.com (a real, frequently abused open redirect)
https://accounts.legitimate-bank.com/login?return=https://evil.comThe email scanner sees accounts.legitimate-bank.com — a trusted domain — and allows the message through. Users see the trusted domain in their email and click confidently.
OAuth Token Theft
OAuth 2.0 is particularly vulnerable. An open redirect on the legitimate authorization server can be used to steal access tokens via the redirect_uri:
GET /oauth/authorize?
client_id=myapp&
response_type=token&
redirect_uri=https://legitimate.com/callback?next=https://attacker.comIf redirect_uri validation is loose, the OAuth server might redirect to the legitimate callback, which then open-redirects to the attacker, leaking the token in the URL fragment.
SSRF Chain Component
An open redirect on your server can sometimes be chained with SSRF vulnerabilities. If a service follows redirects when fetching URLs, an SSRF protection that blocks direct requests to internal IPs can be bypassed by first hitting an open redirect that points to the internal address.
Credential Harvesting via Referrer
When users click a link from your open redirect to an attacker site, the Referer header includes the full URL — including any session tokens or sensitive data that were in the URL at redirect time.
Code Examples: Vulnerable vs Secure
Vulnerable Node.js/Express
// VULNERABLE
app.get('/callback', (req, res) => {
const redirectTo = req.query.url;
res.redirect(redirectTo); // no validation!
});Vulnerable PHP
// VULNERABLE
$redirect = $_GET['url'];
header("Location: $redirect");
exit();Secure: Allowlist Approach
from urllib.parse import urlparse
from flask import redirect, request, abort
ALLOWED_HOSTS = {'myapp.com', 'www.myapp.com', 'app.myapp.com'}
def is_safe_redirect(url):
if not url:
return False
# Only allow relative URLs (no scheme/host)
parsed = urlparse(url)
if parsed.scheme or parsed.netloc:
# Absolute URL — check against allowlist
return parsed.netloc in ALLOWED_HOSTS
# Relative URL — ensure it starts with /
return url.startswith('/')
@app.route('/login', methods=['POST'])
def login():
next_url = request.args.get('next', '/')
if not is_safe_redirect(next_url):
next_url = '/'
return redirect(next_url)Secure: Relative-Only Redirects
The simplest approach: only allow relative URLs (paths), never absolute URLs:
// Node.js — allow only relative redirects
function safeRedirect(res, url) {
// Must start with / and not contain //
// (// could be treated as protocol-relative URL)
if (url && url.startsWith('/') && !url.startsWith('//')) {
return res.redirect(url);
}
return res.redirect('/');
}Gotcha: //evil.com/path is a valid protocol-relative URL — browsers will follow it to evil.com. Always check that the URL doesn't start with //.
Framework-Level Protections
Django
Django's django.utils.http.url_has_allowed_host_and_scheme provides safe redirect validation:
from django.utils.http import url_has_allowed_host_and_scheme
from django.http import HttpResponseRedirect
def login_view(request):
next_url = request.GET.get('next', '/')
allowed = url_has_allowed_host_and_scheme(
url=next_url,
allowed_hosts={request.get_host()},
require_https=request.is_secure()
)
if not allowed:
next_url = '/'
return HttpResponseRedirect(next_url)Ruby on Rails
# Safe redirect helper
def safe_redirect(url)
uri = URI.parse(url) rescue nil
if uri && uri.relative?
redirect_to url
else
redirect_to root_path
end
endSpring Boot (Java)
@GetMapping('/callback')
public String callback(@RequestParam String next, HttpServletResponse response) {
URI uri = URI.create(next);
if (uri.isAbsolute()) {
return 'redirect:/'; // block absolute URLs
}
return 'redirect:' + next;
}Detecting Open Redirects in Your Codebase
Search for common redirect patterns with user-supplied input:
# Find potential open redirects in Python
grep -rn 'redirect(request\.' . --include='*.py'
grep -rn 'redirect(.*GET\[' . --include='*.py'
# Find in JavaScript/Node
grep -rn 'res\.redirect(req\.' . --include='*.js'
# Find in PHP
grep -rn 'header.*Location.*\$_GET' . --include='*.php'Also look for: 302, 301, window.location, document.location, location.href set to user-controlled values.
FAQ
Q: Is open redirect a high-severity vulnerability?
A: By itself, open redirect is typically classified as medium severity. However, context matters significantly. When combined with OAuth flows, it becomes critical (token theft). When leveraged for phishing against high-value targets (banking, enterprise SaaS), the real-world impact is high. Many bug bounty programs pay $500–$5,000 for open redirects depending on exploitability.
Q: Can I use a blocklist to prevent open redirects?
A: Blocklists are notoriously insufficient. Attackers use IP addresses, URL encoding, Unicode homoglyphs, and other techniques to bypass string-matching filters. Always use an allowlist approach — only permit redirects to known good destinations.
Q: Does meta http-equiv='refresh' create open redirects?
A: Yes. If user input is reflected in a meta refresh tag, it's an open redirect. The same validation rules apply. Additionally, meta refresh bypasses some X-Frame-Options protections.
Q: How do I find open redirects in my third-party dependencies?
A: Check your dependency tree for known open redirect CVEs using npm audit, pip-audit, or bundler-audit. For runtime detection, integrate a WAF rule that logs requests with next, url, redirect, return_to parameters containing external domains. ZeriFlow can also flag common open redirect patterns in HTTP responses.
Q: Are URL shorteners open redirects?
A: By design, yes — URL shorteners redirect to arbitrary destinations. This is why security tools flag them in phishing detection. If you build a redirect service, add phishing detection (Google Safe Browsing API), implement rate limiting, and log all redirects for abuse investigation.
Conclusion
Open redirect vulnerabilities sit at an interesting intersection: trivial to implement safely, yet consistently found in production applications. The fix is always an allowlist or relative-only redirect policy — a few lines of code that eliminates the entire attack vector.
The danger is in dismissing them as "low severity." A weaponized open redirect on a banking or enterprise SaaS domain can facilitate credential theft at scale, with a phishing success rate far higher than a link to an unknown domain.
[Scan your application with ZeriFlow](https://zeriflow.com) to check for open redirect indicators alongside 79 other security controls. Free, no account required — know your exposure before an attacker exploits it.