← All news
security4 min read

Open redirect vulnerabilities in AI-generated auth flows

By Seaworthy · June 25, 2026

Wooden directional arrow signs pointing in different directions against a blue sky

Photo by Nick Fewings on Unsplash

Open redirect vulnerabilities in AI-generated auth flows

Here is a pattern I see constantly in AI-generated login flows:

GET /login?redirect=/dashboard

User logs in. Server validates credentials. Server reads the redirect query parameter. Server sends a 302 to wherever that parameter points. User lands where they expected.

It works. The problem is what happens when an attacker controls that parameter.

https://yourapp.com/login?redirect=https://evil.example.com/fake-login

Your server authenticates the user against your real credentials database, then helpfully sends them to the attacker's phishing page. The URL bar showed yourapp.com during login. The user had no reason to distrust it. By the time they notice the redirect, they may have already typed their credentials into the fake page.

This is an open redirect vulnerability. It is not exotic. It sits comfortably in OWASP's Top 10, and it is one of the most reliably generated security bugs I've seen come out of AI coding assistants.

Why AI assistants generate this pattern

LLMs are trained on enormous amounts of web code, much of which implements post-login redirects without any validation. The pattern is simple, functional, and incredibly common. When you ask an AI to "add a redirect back to the page the user was on after login," it will produce something like this:

const redirectTo = req.query.redirect as string;
res.redirect(redirectTo || '/dashboard');

That's it. No validation. No allowlist. Works perfectly for the happy path, and that's all the AI was optimizing for.

Some assistants will add a URL decode step, making the situation worse because it opens the door to double-encoding bypasses. A few will mention that "you should validate this in production," then leave you to figure out what that means.

How to fix it

The fix has two parts: decide what a valid redirect looks like, and enforce it.

For most applications, a valid post-login redirect is a path on your own domain. Absolute URLs to external hosts should be rejected outright. Relative paths starting with / are usually safe, but you still need to watch for protocol-relative URLs (//evil.example.com) which are parsed as absolute by browsers.

function isSafeRedirect(url: string): boolean {
  // Reject empty or obviously wrong values
  if (!url || typeof url !== 'string') return false;

  // Protocol-relative URLs are absolute URLs in disguise
  if (url.startsWith('//')) return false;

  // Reject anything with a scheme (http://, https://, javascript:, etc.)
  if (/^[a-zA-Z][a-zA-Z0-9+\-.]*:/.test(url)) return false;

  // At this point we have a relative path — ensure it starts with /
  // to avoid path traversal tricks like "../admin"
  if (!url.startsWith('/')) return false;

  return true;
}

// Usage in your login handler
const raw = req.query.redirect as string;
const redirectTo = isSafeRedirect(raw) ? raw : '/dashboard';
res.redirect(redirectTo);

If you genuinely need to redirect to external domains (some SSO setups do), use an explicit allowlist rather than trying to parse and validate arbitrary URLs. URL parsing is hard. Attackers have had decades to find edge cases in every language's URL parser.

const ALLOWED_REDIRECT_HOSTS = new Set([
  'app.yourcompany.com',
  'admin.yourcompany.com',
]);

function isSafeExternalRedirect(url: string): boolean {
  try {
    const parsed = new URL(url);
    return (
      (parsed.protocol === 'https:') &&
      ALLOWED_REDIRECT_HOSTS.has(parsed.hostname)
    );
  } catch {
    return false;
  }
}

Note the explicit check for https: only. Redirecting to http:// URLs from a post-auth flow is its own category of problem.

The validation gaps that bite people

A few things that look like validation but aren't:

Checking that the URL "starts with" your domain string is not safe. https://yourapp.com.evil.com starts with https://yourapp.com.

Checking that the URL "contains" your domain string is not safe. https://evil.com/?ref=yourapp.com contains your domain.

Using URL.hostname === 'yourapp.com' without also checking the protocol is not safe. javascript:alert(1) has no hostname, but javascript: URIs in redirect targets have been used in the wild.

The isSafeRedirect function above rejects the problem at the scheme level rather than trying to parse and compare hostnames. For same-origin redirects that is the right approach. Let the browser construct the full URL from the relative path; don't do it yourself.

Where to look in your own codebase

Search for these patterns:

  • req.query.redirect, req.query.returnUrl, req.query.next, req.query.return_to
  • Any res.redirect() or response.redirect() call where the argument is not a string literal
  • OAuth callback handlers that forward state parameters

Auth flows written by AI assistants are the most likely place to find this, but it appears in hand-written code too. Any time a developer wants to preserve navigation state across a login boundary, the temptation is to stuff a URL in a parameter and trust it on the way out.

Seaworthy's configuration check category flags unvalidated redirect parameters in auth route handlers as part of its static analysis pass.

This article was generated by AI and summarises publicly available sources.

From the makers of Seaworthy

Seaworthy scans your repo for the issues covered in articles like this one.

Security gaps, exposed secrets, and misconfigurations — caught before you deploy. Free to run, no account needed.

$ npx seaworthycode