An open redirect is a vulnerability where an application accepts a user-controlled URL parameter and redirects the browser to that URL without sufficient validation. The application's own domain appears in the original URL, lending the redirect a degree of legitimacy that makes it useful in phishing attacks and as a component in more complex attack chains.
This article explains the attack scenarios that open redirects enable, the URL validation patterns that are commonly bypassed, and the correct approaches to redirect validation.
What an Open Redirect Is
Many web applications redirect users to a return URL after an action: after login, after a password reset, after a payment. The destination URL is often passed as a query parameter:
https://example.com/login?next=https://example.com/dashboard
https://example.com/logout?returnTo=/home
https://example.com/auth/callback?redirect_uri=https://app.example.com/When the application validates the next or redirect_uri parameter insufficiently, an attacker can substitute an external URL:
https://example.com/login?next=https://evil.attacker.com/phishingIf the application redirects to the attacker's URL after a successful login, the user sees their browser navigate to a page on example.com, enter their credentials, and then be redirected to a site they did not expect to visit.
Attack Scenarios
Phishing via Trusted Domain
The primary use of open redirects is phishing. An attacker sends a link to https://example.com/login?next=https://attacker.com/fake-login. Email security tools, link preview systems, and user inspection of the URL bar may all indicate a safe link because the URL starts with https://example.com. After visiting the real site, the user is redirected to the attacker's page.
The redirect destination can be a credential harvesting page, a malware download page, or a lookalike version of the legitimate site. The initial trust established by the legitimate domain increases the probability that users proceed without suspicion.
OAuth Token Theft
OAuth 2.0 authorization codes and tokens are delivered via the redirect_uri parameter. If the authorization server uses an open redirect on the legitimate domain as a registered redirect URI, an attacker can manipulate the flow to have authorization tokens delivered to an attacker-controlled endpoint.
The attack works when: the authorization server validates that redirect_uri starts with the registered domain, but the open redirect on that domain then forwards the token-bearing request to an external URL. This is why OAuth specifications (RFC 6749) require exact matching of redirect URIs, not prefix matching.
SSRF Chain Enablement
Server-Side Request Forgery (SSRF) attacks sometimes require the vulnerable server to make requests to attacker-controlled external URLs. Some SSRF mitigations block external URLs but allow requests to the application's own domain. An open redirect on the trusted domain can be used to forward the server's request to the internal or external destination the attacker actually wants to reach.
URL Validation Failures That Allow Bypasses
Most open redirect vulnerabilities exist not because the developer added no validation, but because the validation implemented has bypass vectors.
Scheme and Double-Slash Confusion
Checking that a URL starts with / is meant to restrict redirects to relative paths. But URLs starting with // are protocol-relative and resolve to the scheme of the current page, then navigate to the specified host:
// Vulnerable: only checks for leading slash
if (redirectUrl.startsWith('/')) {
res.redirect(redirectUrl);
}
// Bypass: //attacker.com resolves to https://attacker.com
/login?next=//attacker.com/phishingSimilarly, URL parsers may interpret unusual sequences differently from simple string checks:
// These may pass a simple "no external URL" check:
///attacker.com
/\/attacker.com // backslash treated as slash in some parsers
/%09/attacker.com // tab character between slashes
//%09attacker.comDomain Check Bypasses
Checking that the URL contains or starts with the trusted domain is insufficient:
// Vulnerable: checks that URL includes the trusted domain
if (redirectUrl.includes('example.com')) {
res.redirect(redirectUrl);
}
// Bypass: https://attacker.com?ref=example.com
// or: https://example.com.attacker.com
// Vulnerable: prefix check
if (redirectUrl.startsWith('https://example.com')) {
res.redirect(redirectUrl);
}
// Bypass: https://example.com.attacker.comCorrect URL Validation
The Allowlist Approach
The most robust approach is an explicit allowlist of permitted redirect destinations. For applications where users may only be redirected to a known set of internal paths or partner domains, enumerate those destinations and reject anything else:
const ALLOWED_REDIRECT_ORIGINS = new Set([
'https://app.example.com',
'https://dashboard.example.com',
]);
function isSafeRedirect(url: string): boolean {
try {
const parsed = new URL(url, 'https://example.com');
// For absolute URLs, check against allowlist
if (parsed.hostname !== 'example.com' &&
!parsed.hostname.endsWith('.example.com')) {
return false;
}
// Reject URLs with unexpected schemes
if (parsed.protocol !== 'https:') return false;
return true;
} catch {
return false;
}
}Restricting to Relative URLs
If the application only needs to redirect within its own origin, restrict to path-only relative URLs. Parse the input with the URL constructor and verify it has no host component:
function isSafeRelativeRedirect(input: string): boolean {
// Parse as relative URL against a base — if it resolves to a different origin, reject
try {
const base = 'https://example.com';
const parsed = new URL(input, base);
// Reject if the resolved URL leaves the expected origin
if (parsed.origin !== base) return false;
// Reject protocol-relative URLs (double slash)
if (input.startsWith('//') || input.startsWith('\/')) return false;
return true;
} catch {
return false;
}
}
// Fallback: if validation fails, redirect to a safe default
const target = isSafeRelativeRedirect(requestedUrl) ? requestedUrl : '/dashboard';
res.redirect(target);Always provide a safe default redirect destination that is used when the requested URL fails validation, rather than returning an error that might expose the redirect logic.
How WebDefect Detects Open Redirects
WebDefect checks for open redirect vulnerabilities by inspecting URL parameters discovered during the crawl phase and testing common redirect parameter names with controlled values. The check (redir-002) works as follows:
- The crawler identifies URL parameters with names commonly used for redirect destinations:
next,redirect,returnTo,return,url,goto,destination,target, and similar. - The scanner replaces the parameter value with a known safe external URL from an infrastructure controlled by WebDefect, then follows the redirect chain and checks whether the final destination is the injected URL.
- If the application redirects to the injected URL without modification, the finding is reported as confirmed open redirect, medium severity.
- The finding includes the vulnerable parameter name, the original URL, and the redirect destination that was followed.
Because the check is passive and non-destructive (the injected URL is infrastructure under WebDefect's control, not a third-party attacker domain), the test does not create any real risk to the scanned application.