Open Redirect Vulnerability Enables Phishing and Token Theft
What Is This Vulnerability?
An open redirect occurs when your application accepts a user-supplied URL in a query parameter and redirects the browser to it without validation. Attackers use this to craft links that appear to come from your trusted domain but actually send users to a malicious site, making phishing campaigns highly effective.
Why It Happens
Login flows, OAuth callbacks, and post-action redirects often use a return URL parameter for convenience. Developers trust that the parameter will contain an internal path, but without explicit validation, an attacker can supply an external URL. URL parsing edge cases (like protocol-relative URLs or encoded characters) make basic string checks unreliable.
Example Code
import { NextRequest, NextResponse } from "next/server";
export async function GET(request: NextRequest) {
const returnTo = request.nextUrl.searchParams.get("returnTo") || "/";
// Redirects to whatever URL the user provides
return NextResponse.redirect(returnTo);
}import { NextRequest, NextResponse } from "next/server";
const ALLOWED_HOSTS = ["myapp.com", "www.myapp.com"];
function isSafeRedirect(url: string, baseUrl: string): boolean {
try {
const parsed = new URL(url, baseUrl);
return ALLOWED_HOSTS.includes(parsed.hostname);
} catch {
return false;
}
}
export async function GET(request: NextRequest) {
const returnTo = request.nextUrl.searchParams.get("returnTo") || "/";
const baseUrl = request.nextUrl.origin;
if (!isSafeRedirect(returnTo, baseUrl)) {
return NextResponse.redirect(new URL("/", baseUrl));
}
return NextResponse.redirect(new URL(returnTo, baseUrl));
}How Hackers Exploit It
An attacker crafts a URL like https://myapp.com/auth/callback?returnTo=https://evil.com/phish and distributes it via email or social media. Victims see the trusted domain in the link and click it. After authentication, they are silently redirected to the attacker's page, which mimics the real site and harvests credentials or session tokens.
How to Fix It
Always validate redirect URLs against an allowlist of trusted hostnames. Parse the URL using the URL constructor to handle edge cases like protocol-relative URLs and encoded characters. For internal-only redirects, only accept relative paths that start with a single forward slash and reject anything containing a double slash or external protocol.