The safest redirect design never accepts a destination URL from the user. Accept a short key or a local path, map it on the server to a known target, and reject everything else. If you must take full URLs, compare the parsed scheme, host and port against an allowlist, not a string prefix.
Why a redirect bug matters
A link that starts at your trusted domain and ends at an attacker's page makes phishing look more credible. OWASP notes that such a link looks trustworthy because it begins with your own domain. Crafted URLs can also pass an access check and forward users to functions they would not normally reach.
The usual location is a next or returnTo parameter on a login or logout page.
Pattern 1: avoid it
If you can, do not redirect based on input. Send the user to a fixed page after login.
Pattern 2: map a key to a target
Let the request carry a short name or ID, and have the server look up the real URL. OWASP says to guard against enumeration, where someone cycles through IDs to discover every target.
Pattern 3: local paths only
For a return to a page in your own app, use a framework helper that rejects non-local destinations. OWASP cites ASP.NET Core's LocalRedirect and IsLocalUrl as examples. Other frameworks have similar helpers, so check yours.
Pattern 4: allowlist for external destinations
When a redirect to another site is required, allow only explicitly approved destinations. Prefer a server side mapping from an approved ID. Better still, route through an interstitial page that shows the destination and asks the user to click to confirm.
If you must validate raw URLs
OWASP's validation advice:
- Use a maintained URL parser that matches the redirect API and browser behaviour.
- Compare the parsed scheme, canonical host and effective port against an explicit allowlist. Constrain the path if only certain endpoints are allowed.
- Reject userinfo and ambiguous input.
- Redirect to the validated URL itself, not a version transformed afterwards.
- Do not use raw prefix or suffix matching. OWASP points to a GitLab case where userinfo and misleading hostnames bypassed such checks.
The classic failure looks like a check that the URL starts with your domain, which an attacker beats with a hostname that merely begins with the same text, or with credentials placed before the real host.
Test it
- Try an absolute URL to another domain in the return parameter.
- Try a protocol relative form that starts with two slashes.
- Try a URL with credentials before an at sign.
- Try a hostname that starts with your domain but continues with more text.
- Confirm each is refused and the user lands on a safe default.
Quick check
Is checking that the URL starts with a slash enough?
Not always. Some forms that start with two slashes are treated as other hosts by browsers. Use a parser or a framework helper that tests for local paths.
Sources
Last reviewed: 19 October 2026.