Skip to content

Java: Add Spring MVC URL redirect sinks - #22362

Open
theinfosecguy wants to merge 4 commits into
github:mainfrom
theinfosecguy:java-spring-mvc-redirect-sinks
Open

theinfosecguy wants to merge 4 commits into
github:mainfrom
theinfosecguy:java-spring-mvc-redirect-sinks

Conversation

@theinfosecguy

@theinfosecguy theinfosecguy commented Aug 17, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #21771.

Adds stable java/unvalidated-url-redirection coverage for Spring MVC redirect view names and returned RedirectView objects, building on the existing experimental Spring coverage.

Covers leading redirect: string concatenations, helper-generated names returned directly or supplied to returned ModelAndView objects, RedirectView constructor overloads, and setUrl. Returned view objects remain covered under response-body annotations; string return values retain their response-body and model-attribute semantics.

The sinks follow the actual returned view and its view-name argument. Precision checks cover ordinary view names, discarded and model-only values, helper sanitizers, and definite local constant replacements. Views that escape or have ambiguous aliases are handled conservatively.

Validation:

  • Stable and experimental CWE-601 tests
  • Experimental CWE-625 tests
  • Apache HTTP and JAX-RS framework tests
  • Strict query compilation, QL formatting, and whitespace checks

@theinfosecguy
theinfosecguy marked this pull request as ready for review August 17, 2026 10:28
@theinfosecguy
theinfosecguy requested a review from a team as a code owner August 17, 2026 10:28

@owen-mc owen-mc left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the delay in reviewing this.

private predicate isSpringMvcViewResult(Expr value) {
contributesToReturn(value) and
value.getEnclosingCallable() instanceof SpringRequestMappingMethod and
not value.getEnclosingCallable().(SpringRequestMappingMethod).isResponseBody()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spring processes view objects before the response-body handler, so a @RestController returning new RedirectView(next) still performs a redirect. This condition excludes that case, as well as redirecting ModelAndView results. Please keep the response-body exclusion for string view names, but allow returned view objects. A regression test for a @RestController returning a user-controlled redirect would cover this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed this and added regression tests.

SpringUrlRedirectHelperSink() {
exists(MethodCall call |
this.asExpr() = call and
isSpringMvcViewResult(call) and

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This misses return new ModelAndView(redirect(next));, where the helper returns "redirect:" + next. The helper call supplies the view name, but the returned value is the enclosing ModelAndView, so this direct-return check fails. Please also recognize helper calls used as the name of a returned ModelAndView, and add a regression test for this case.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed this and added a regression test for new ModelAndView(redirect(next)).


pragma[nomagic]
private predicate appendedToRedirectPrefix(DataFlow::ExprNode exprNode) {
exists(SpringRedirectPrefix prefix | exprNode.asExpr() = prefix.getAnAppendedExpression())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can match a redirect: literal in the middle of an ordinary view name. For example, String base = "home"; return base + "redirect:" + next; marks next as a sink, although the result starts with homeredirect: and is not a Spring redirect. Please require redirect: to start the resulting view name, and add a negative test for this case.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. The view name must start with redirect:. Added your example as a negative test.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

False negative in java/unvalidated-url-redirection for Spring MVC redirect view names

3 participants