Skip to content

VNX-JAVA-007: Java open redirect

Reports sendRedirect(), Spring redirect: views, RedirectView and Location headers whose target is a request value or a variable assigned from one, unless it is prefixed with a fixed path, looked up in an allowlist or guarded.

Updated 02 Nov 2026Checked against cli@de9b52a
Field Value
Rule ID VNX-JAVA-007
Severity Medium
SARIF level warning
Kind sast
Languages Java
CWE CWE-601
CAPEC CAPEC-194
ATT&CK T1566
CWSS vector CWSS:1.0/TI:M/AP:A/AL:A/IC:N/FC:LT/RP:N/RL:A/AV:I/AS:N/IN:A/SC:A/BI:M/DI:H/EX:M/EC:N/P:C
Tags open-redirect web phishing
Source internal/sast/rules/vnx-java-007.rego

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.

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 reports sendRedirect(), a "redirect:" + value view name, new RedirectView() and a Location header (setHeader/addHeader, HttpHeaders.LOCATION, ResponseEntity.location(URI.create(...))) whose target reads the request, is a @RequestParam/@PathVariable/@RequestHeader parameter, or is a variable assigned from one (directly or through one step such as URLDecoder.decode) within the 40 lines above. It does not report a target that starts with a fixed local path ("/account?id=" + id) or fixed absolute URL, a lookup in a map of allowed destinations, a value checked by an if guard (startsWith, allowlist contains, isSafe…) before the redirect, on the value itself or on a URI parsed from it, or values from configuration.

// 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

  1. 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);
  2. 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 %2F and 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("/");
    }
  3. 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");
    }
  4. Use Spring Security’s SavedRequestAwareAuthenticationSuccessHandler. For post-login redirects in Spring Security applications, delegate to this handler rather than reading and forwarding a next parameter yourself. It uses its own URL validation before redirecting.

References

Suppressing this rule

Put a nosec comment on the line, or on line 1 to cover the whole file. Use the comment marker of the file’s language (#, //, -- or ;):

# nosec vnx-java-007
// nosec vnx-java-007

Or record an ignore rule: vulnetix ignore add --rule vnx-java-007 --reason "...". See Suppressing findings.

Edit this pageSources: cli/internal/sast/rules/vnx-java-007.rego, cli/internal/sast/docs/vnx-java-007.md
esc
↑ ↓ move↵ openSearches in your browser. A key like autonomy.max or a code like threshold_required jumps straight to it.