An open redirect is when your app sends the user to a URL taken from input, without checking it.
How attackers use ?returnTo=:
- Phishing: the link
https://app.example/login?returnTo=https://evil.examplestarts with your trusted domain. After login, the user lands on a fake "session expired, log in again" page. - XSS: if the code does
location.href = returnTo, ajavascript:URL runs script in your origin. - Token theft: if the redirect sits on a path that OAuth allows as a
redirect_uri, it can forward codes or tokens to the attacker.
How to validate:
- Parse it:
const url = new URL(returnTo, location.origin). - Require
url.origin === location.origin. - Navigate to
url.pathname + url.search + url.hash, not to the raw string. - Or don't put the URL in the link at all. Save it in
sessionStoragebefore the login starts. - Or accept only names from a list, such as
returnTo=billing.
Don't check with startsWith("/") or a regex. Values like //evil.example and /\evil.example pass those checks, but browsers treat them as other sites.
- An open redirect sends users to a URL from input without checking it.
- Attackers use it for phishing links that start with your domain.
- A
javascript:value can turn the redirect into XSS. - Parse with
new URLand require the same origin before you navigate. - Simple checks like
startsWith("/")miss//evil.example.