CVE-2016-5007 Spring Security / MVC Path Matching Inconsistency feature image

Both Spring Security 3.2.x, 4.0.x, 4.1.0 and the Spring Framework 3.2.x, 4.0.x, 4.1.x, 4.2.x rely on URL pattern mappings for authorization and for mapping requests to controllers respectively. Differences in the strictness of the pattern matching mechanisms, for example with regards to space trimming in path segments, can lead Spring Security to not recognize certain paths as not protected that are in fact mapped to Spring MVC controllers that should be protected. The problem is compounded by the fact that the Spring Framework provides richer features with regards to pattern matching as well as by the fact that pattern matching in each Spring Security and the Spring Framework can easily be customized creating additional differences.

Description 🔗

This vulnerability affects Spring Web and Security when used together if HttpSecurity.authorizeRequests is used for URL access control. Spring provides an example of this in its Spring Security documentation: http://docs.spring.io/spring-security/site/docs/current/reference/html/jc.html#authorize-requests

protected void configure(HttpSecurity http) throws Exception {
	http
		.authorizeRequests()
			.antMatchers("/resources/**", "/signup", "/about").permitAll()
			.antMatchers("/admin/**").hasRole("ADMIN")  
			.antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")
			.anyRequest().authenticated()
			.and()
		// ...
		.formLogin();
}

In the following example, the user “user” is not an admin and cannot access “/admin/”:

However, if a space (or another whitespace character) is prepended or appended to “admin” in the URL, the security filter is easily bypassed.

  • Space appended (automatically encoded as “%20” by the browser):

  • %0D prepended:

The problem is that different matchers are used to implement the access control, and to identify which controller class should handle the request.

The first matcher, used for access control, is strict: “admin” is considered different than “admin”:

However, the second matcher, used to find the appropriate controller, applies a trim operation which removes whitespaces before and after each URL token, so “admin” becomes “admin”:

In conclusion: the access control matcher does not recognize the protected path, thus a default “allow” rule applies, while the controller finder matcher finds the protected controller.

A mismatch of strictness between both matchers is responsible for this condition.

External references 🔗