Laravel Open Redirect: How to Validate Redirect URLs and Prevent Phishing Attacks

Redirects using unvalidated user input let attackers craft links that appear to come from your domain but redirect victims to malicious sites.

High severity Application Security Updated 2026-05-01 Markdown

An open redirect is a URL redirection vulnerability where an application redirects users to a destination taken from unvalidated user input. These most commonly appear in authentication flows — login pages that redirect users back to their intended destination after authentication using a redirect or return_to query parameter. The parameter's usefulness makes it pervasive: nearly every web application with authentication has one, and nearly every implementation is vulnerable without explicit validation.

Attackers weaponize open redirects for phishing campaigns. They craft URLs that begin with your trusted domain — https://yourapp.com/login?redirect=https://attacker.com/fake-login — and send them to victims via email or social media. Because the link starts with a domain the victim recognizes, they click it. Email spam filters and browser security tools also trust the domain. After logging in (or being shown a fake login page), the victim is redirected to the attacker's phishing site where credentials are harvested.

Open redirects also enable more sophisticated attacks. In OAuth flows, an open redirect can redirect authorization codes to an attacker-controlled server, granting them access tokens. They can also chain with server-side request forgery to reach internal services. Bug bounty programs consistently accept open redirect reports because they serve as enablers for more serious attacks. The fix is simple: validate redirect URLs against your own domain and use Laravel's built-in redirect()->intended() for authentication flows.

The Problem

An open redirect occurs when your application redirects users to a URL taken from request input without validating that the URL is safe. Attackers exploit this by sending victims links like yourdomain.com/login?redirect=https://evil-site.com. Because the link starts with your trusted domain, users and email filters trust it. After login, the victim is redirected to the attacker's phishing page. This is commonly used in credential harvesting attacks.

How to Fix

  1. 1

    Validate redirect URLs against an allowlist

    Never redirect to arbitrary user-supplied URLs:

    // DANGEROUS
    return redirect($request->input('redirect'));
    // SAFE — validate against your own domain
    $url = $request->input('redirect', '/');
    if (!Str::startsWith($url, '/') || Str::startsWith($url, '//')) {
        $url = '/';
    }
    return redirect($url);
    // SAFEST — use named routes
    $allowed = ['dashboard', 'profile', 'settings'];
    $route = $request->input('redirect', 'dashboard');
    if (!in_array($route, $allowed)) {
        $route = 'dashboard';
    }
    return redirect()->route($route);
  2. 2

    Use Laravel's intended() for post-login redirects

    Laravel provides a built-in safe redirect mechanism for post-authentication flows:

    return redirect()->intended('/dashboard');

    This redirects to the URL the user originally requested (stored in the session by the auth middleware), falling back to /dashboard. Since the URL comes from the session (not user input), it cannot be manipulated by attackers.

  3. 3

    Audit all redirect() calls that use request input

    Search your codebase for potentially unsafe redirects:

    grep -rn 'redirect(.*request\|redirect(.*\$_GET\|redirect(.*input' app/ routes/ --include='*.php'
    Also check for:
    - header('Location: ' . $userInput)
    - Response::redirectTo($userInput)
    - redirect()->away($userInput) — this explicitly bypasses domain validation

    Every occurrence needs validation.

How to Verify

Test with an external URL:

curl -v 'https://yourapp.com/login?redirect=https://evil-site.com'

After login, the redirect should go to your default page (like /dashboard), not to the external URL. Also test protocol-relative URLs:

curl -v 'https://yourapp.com/login?redirect=//evil-site.com'

Run php artisan stackshield:scan --check=SS041 to verify.

Prevention

Only accept relative paths (starting with / but not //) for redirect parameters. Use Laravel's redirect()->intended() for auth flows. Never use redirect()->away() with user input. Add redirect validation to your code review checklist.

Frequently Asked Questions

Is Str::startsWith($url, '/') sufficient validation?

Not alone. The URL //evil-site.com starts with / but is a protocol-relative URL that redirects to an external domain. Always check for both: must start with / AND must not start with //.

Can open redirects lead to more than phishing?

Yes. Open redirects can be chained with other vulnerabilities: OAuth token theft (redirect authorization codes to attacker), SSRF (server-side request forgery), and bypassing URL-based security controls. Many bug bounty programs accept open redirect reports.

Does Laravel's redirect()->intended() prevent open redirects?

Yes. redirect()->intended() reads the intended URL from the session, which was stored by Laravel's auth middleware when the unauthenticated user first hit a protected route. Since the value comes from the session and not request input, attackers cannot inject an external URL through this mechanism. Always prefer redirect()->intended() over redirect($request->input("redirect")) for post-login flows.

What is a protocol-relative URL and why is it dangerous in redirects?

A protocol-relative URL like //evil.com/fake starts with // rather than https://. Browsers treat this as an absolute URL using the current page's protocol, making it effectively https://evil.com/fake. A check that only verifies the URL starts with / would incorrectly pass this as a relative path. Always also check that the URL does not start with //.

Should I validate the return_url parameter in OAuth and social login flows?

Yes. OAuth callbacks often encode a return URL in the state parameter. Validate that after a successful OAuth flow, the redirect destination is a relative path on your domain. Attackers have exploited OAuth return URL parameters to steal authorization codes from legitimate providers by injecting an open redirect into the flow.

Related Security Terms

Free security check

Is your Laravel app exposed right now?

34% of Laravel apps we scan have at least one critical issue. Most teams don't find out until something breaks. Our free scan checks your live application in under 60 seconds.

18% have debug mode on
72% missing security headers
12% have exposed .env
Scan My App Free No signup required. Results in 60 seconds.