Description
An open redirect occurs when an application uses an unvalidated user-supplied URL in a redirect response, such as redirect or sendRedirect. A link may begin with a legitimate domain but send the user to an external phishing or malicious download site.
Common locations include post-login navigation, an OAuth callback's returnUrl, and a page shown after payment.
Potential impact
- Phishing through links that use a trusted service address
- Token disclosure or session compromise when an authentication flow trusts an unvalidated redirect
- Redirection to malicious downloads or vulnerable external sites
- Bypassing filters by redirecting through a permitted domain
Remediation
- Restrict destinations to paths or domains in a server-owned allow-list.
- Prefer fixed identifiers such as
next=profile, mapped to actual paths on the server, over accepting a complete URL. - If external URLs are necessary, validate the scheme, host, port and normalized result, and permit only
https. - Do not rely on
startsWithorcontainschecks. A value such ashttps://trusted.example.com.evil.examplemay bypass them. - Reject unapproved values or use a safe default path.
Examples
These Spring controller excerpts omit the required imports and application-defined internal routes.
Before
java
@GetMapping("/login/success")
public void loginSuccess(
@RequestParam("next") String next,
HttpServletResponse response
) throws IOException {
response.sendRedirect(next);
}
After
java
private static final Map<String, String> ALLOWED_REDIRECTS = Map.of(
"profile", "/account/profile",
"orders", "/account/orders"
);
@GetMapping("/login/success")
public void loginSuccess(
@RequestParam(value = "next", defaultValue = "profile") String next,
HttpServletResponse response
) throws IOException {
String redirectPath = ALLOWED_REDIRECTS.getOrDefault(next, "/account/profile");
response.sendRedirect(redirectPath);
}
Explanation:
- Before: Uses the request parameter directly as a redirect URL. A user clicking a legitimate service link may end up on an external site.
- After: Treats input as a server-known identifier rather than a URL. Unrecognized values use a safe default path.