Open Redirect
Open redirects allow attackers to craft trusted-looking URLs on your domain that redirect victims to malicious sites — enabling phishing, credential theft, and OAuth token hijacking.
What Is an Open Redirect?
An open redirect occurs when your application redirects users to a URL controlled by user input without validating it. The vulnerability itself is low-severity, but it becomes critical when chained with OAuth flows, password reset emails, or phishing campaigns — because the redirect originates from your trusted domain.
How It Works
A common pattern — redirect after login:
// Vulnerable — redirects to whatever `next` says
app.get("/login", (req, res) => {
if (isAuthenticated(req)) {
return res.redirect(req.query.next as string)
}
// show login form...
})An attacker crafts a URL:
https://yourapp.com/login?next=https://evil.com/fake-login
Victim clicks a link that appears to come from yourapp.com, logs in, and is sent to evil.com — which looks identical to your login page and harvests their credentials.
OAuth token hijacking:
https://yourapp.com/oauth/callback?redirect_uri=https://evil.com
If redirect_uri isn't validated against a registered allowlist, the OAuth token is delivered to the attacker.
Real-World Impact
- Phishing — trusted-looking URLs increase click and credential-capture rates dramatically
- OAuth token theft — authorization codes or access tokens delivered to attacker
- Session fixation — chain with other vulnerabilities for account takeover
- Malware distribution — redirect users to drive-by download pages
How to Fix
Allowlist approach (most secure):
const ALLOWED_REDIRECT_PATHS = ["/dashboard", "/profile", "/settings"]
function safeRedirect(next: string | undefined): string {
if (!next) return "/dashboard"
// Only allow relative paths on our own domain
if (next.startsWith("/") && !next.startsWith("//") && ALLOWED_REDIRECT_PATHS.some(p => next.startsWith(p))) {
return next
}
return "/dashboard"
}
app.get("/login", (req, res) => {
if (isAuthenticated(req)) {
return res.redirect(safeRedirect(req.query.next as string))
}
})For OAuth — register exact redirect URIs and validate strictly:
REGISTERED_REDIRECT_URIS = {
"https://yourapp.com/oauth/callback",
"https://yourapp.com/auth/google/callback",
}
if redirect_uri not in REGISTERED_REDIRECT_URIS:
raise ValueError("Invalid redirect_uri")Never allow user input to construct full URLs for redirects. Only allow relative paths or compare against a strict allowlist.
What VibeWShield Detects
VibeWShield tests redirect parameters (next, return, redirect_uri, url, to) with external URLs and protocol-relative URLs. It follows redirects and checks whether responses ultimately redirect to attacker-controlled domains.
Free security scan
Test your app for Open Redirect
VibeWShield automatically checks for Open Redirect and 40+ other vulnerabilities using 63 scanners — in under 3 minutes, no signup required.
Scan your app free