All vulnerabilities
MediumA10:2021CWE-601Server-Side

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.

#open-redirect#phishing#oauth#redirect

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