app.get("/logout", (req, res) => {
res.clearCookie("sid");
res.redirect(req.query.next || "/");
});
It is an open redirect. A link like https://app.example/logout?next=https://evil.example/login starts with your trusted domain, so people and email filters trust it. The user ends up on the attacker's fake login page.
Open redirects cause more harm when combined with other bugs:
- In OAuth, a redirect on an allowed callback path can forward codes or tokens to the attacker.
- An SSRF allowlist that trusts your own domain can be bypassed, because the server follows the redirect to an internal address.
How to validate:
- Best: don't accept URLs. Accept a key, like
next=billing, and map it to a path on the server. - Or accept only same-origin paths. Parse with
new URL(next, "https://app.example"), require that the origin is your own, and redirect tourl.pathname + url.search. - For several domains, compare the host against an exact allowlist.
- Don't use regexes or
startsWith("/"). Values like//evil.exampleand/\evil.examplepass them, but browsers treat them as other sites. - Check the type.
req.query.nextcan be an array.
- Redirecting to an unchecked
nextparameter is an open redirect. - Attackers use it for phishing links that start with your domain.
- It can also help OAuth token theft and SSRF allowlist bypasses.
- Map keys to paths, or parse the URL and require your own origin.
- Prefix checks and regexes miss
//evil.example.