Loaning your domain's credibility to a phishing scam.
An Open Redirect vulnerability occurs when an application takes a URL from user input (like a query parameter) and redirects the user to that URL without validating it first. Attackers exploit this by sending victims a link that *looks* like it points to a trustworthy site (e.g., your bank), but immediately redirects them to a malicious phishing site.
The `next` or `return_to` parameter is incredibly common in login flows. To prevent Open Redirects, you must ensure the destination is either a relative path (staying on your domain) or strictly matches a hardcoded whitelist of allowed external domains.
# VULNERABLE: Open Redirect
@app.route("/login")
def login():
# ... check credentials ...
# DANGER: Blindly redirecting to whatever the user provided
next_url = request.args.get("next")
return redirect(next_url)
# SECURE: Validating the redirect
@app.route("/login")
def login():
# ... check credentials ...
next_url = request.args.get("next")
# Only allow relative paths (starts with single slash, not double slash //)
if next_url and next_url.startswith("/") and not next_url.startswith("//"):
return redirect(next_url)
return redirect("/dashboard") # Safe default
An attacker sends a phishing email: "Your account is locked. Please login to unlock it: `https://chase.com/login?next=http://chase-security-update.com`". The victim checks the domain, sees `chase.com`, and clicks it. Chase logs them in, then blindly redirects them to `chase-security-update.com` (which the attacker owns). The attacker's site looks identical to Chase and asks the user for their Social Security Number.
Why is filtering out `http://` and `https://` from the `next` parameter not enough to prevent Open Redirects?