VNX-JAVA-007 – Java Open Redirect
Overview
This rule detects patterns where a value read from request.getParameter() or req.getParameter() is passed directly — without validation — to response.sendRedirect(), a Spring ModelAndView redirect string, or a RedirectView constructor. An open redirect allows an attacker to craft a link that appears to originate from your trusted domain but silently redirects the user to an attacker-controlled site. This is CWE-601.
Severity: Medium | CWE: CWE-601 – URL Redirection to Untrusted Site (‘Open Redirect’)
Why This Matters
Open redirects are a reliable tool in phishing campaigns precisely because they abuse the victim’s trust in the source domain. An attacker sends a link such as https://yourapp.example.com/login?next=https://attacker.com/harvest. The victim sees yourapp.example.com in the URL and clicks it. After any authentication flow, the server sends a 302 Location: https://attacker.com/harvest response and the browser follows it silently. The victim is now on the attacker’s page, which may credential-harvest, deliver malware, or redirect again to the real site to avoid suspicion.
Open redirects are also used as an intermediate step in OAuth phishing attacks, where an open_redirect on the authorisation server or relying party can be combined with the redirect_uri parameter to steal authorisation codes or access tokens. Bug-bounty programmes and security researchers routinely report open redirects, and the presence of one in a login or post-authentication flow raises your overall risk profile.
What Gets Flagged
The rule matches lines that directly combine a parameter read with a redirect call.
// FLAGGED: user-controlled URL sent directly to sendRedirect
String next = request.getParameter("next");
response.sendRedirect(next);
// FLAGGED: Spring MVC redirect with user-controlled string
String target = request.getParameter("url");
return new ModelAndView("redirect:" + target);
// FLAGGED: RedirectView with user-supplied parameter
String dest = request.getParameter("destination");
return new RedirectView(request.getParameter("destination"));
Remediation
Validate the redirect target against an allowlist of permitted destinations. The safest approach is to not accept an arbitrary URL at all — instead accept a short token or named destination that maps to a known URL.
// SAFE: token-based redirect — user never controls the URL directly private static final Map<String, String> ALLOWED_REDIRECTS = Map.of( "dashboard", "/app/dashboard", "profile", "/app/profile", "home", "/" ); String token = request.getParameter("next"); String destination = ALLOWED_REDIRECTS.getOrDefault(token, "/"); response.sendRedirect(destination);If you must accept arbitrary URLs, validate that the destination belongs to your own domain. Parse the URL, extract the host, and compare it to a set of trusted hostnames. Reject anything that does not match, including encoded forms like
%2Fand protocol-relative URLs like//attacker.com.// SAFE: host allowlist validation before redirect String rawUrl = request.getParameter("next"); try { URI uri = new URI(rawUrl).normalize(); String host = uri.getHost(); Set<String> allowedHosts = Set.of("example.com", "www.example.com"); if (host != null && allowedHosts.contains(host.toLowerCase())) { response.sendRedirect(rawUrl); } else { response.sendRedirect("/"); // fall back to safe default } } catch (URISyntaxException e) { response.sendRedirect("/"); }Prefer relative URLs for post-login redirects. If the redirect target is always within your own application, accept only path-relative URLs (starting with
/) and reject any value containing://or starting with//.// SAFE: only relative paths accepted String next = request.getParameter("next"); if (next != null && next.startsWith("/") && !next.startsWith("//")) { response.sendRedirect(next); } else { response.sendRedirect("/home"); }Use Spring Security’s
SavedRequestAwareAuthenticationSuccessHandler. For post-login redirects in Spring Security applications, delegate to this handler rather than reading and forwarding anextparameter yourself. It uses its own URL validation before redirecting.