Skip to content

CVE-2023-34034: Spring Security Authorization Bypass

CVE-2023-34034 is another authorization bypass in Spring Security. Like CVE-2022-31692 it’s nasty because it allows completely unrestricted access to supposedly protected resources. Also like CVE-2022-31692 it requires very specific configuration to be vulnerable and is easily fixed.

This post demonstrates the vulnerability, the problem configuration and suggested fixes. A demonstration vulnerable application is on GitHub.

The vulnerability

Consider this security configuration for a WebFlux application:

@Configuration
@EnableWebFluxSecurity
public class WebFluxSecurityConfig {

    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        http
                // disable CSRF
                .csrf().disable()

                // add AuthenticationWebFilter and set the handler
                .formLogin()
                .authenticationSuccessHandler(new WebFilterChainServerAuthenticationSuccessHandler())
                .authenticationFailureHandler(((webFilterExchange, exception) -> Mono.error(exception)))


                .and()
                .authorizeExchange()
                .pathMatchers("admin/**")
                .hasRole("ADMIN")

                .and()
                .authorizeExchange()
                .anyExchange()
                .permitAll();
        return http.build();
    }

Here we have a protected path (admin/**) that requires authentication. Everything else is public (permitAll()). With this configuration we’d expect a resource on /admin to pop up the login form. And with later (fixed) versions of Spring Security, it does.

However, vulnerable versions of Spring Security mishandle paths without a leading /. In Spring Security 6.0.4, the path /admin is not matched and resources can be accessed without authentication.

Configuration

CVE-2023- is exploitable only if:

  • It is a WebFlux application
  • A protected path is defined without a leading slash and
  • It uses a vulnerable version of Spring Security (5.6.0 to 5.6.11, 5.7.0 to 5.7.9, 5.8.0 to 5.8.4, 6.0.0 to 6.0.4 or 6.1.0 to 6.1.1

Fixes

Fortunately, remediation is simple. We can either define our paths with leading slashes or we can upgrade to a fixed version of Spring Security (5.6.12+, 5.7.10+, 5.8.5+, 6.0.5+, 6.1.2+).

Also, as general good practice, don’t use permitAll() for unmatched paths. It’s safer to enforce security on all unmatched paths and permit only defined public pages. For example, we could allow access to all paths beginning /public/ and restrict everything else:

    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        http
                // disable CSRF
                .csrf().disable()

                // add AuthenticationWebFilter and set the handler
                .formLogin()
                .authenticationSuccessHandler(new WebFilterChainServerAuthenticationSuccessHandler())
                .authenticationFailureHandler(((webFilterExchange, exception) -> Mono.error(exception)))

                .and()
                .authorizeExchange()
                .pathMatchers("/public/**")
                .permitAll()

                .and()
                .authorizeExchange()
                .anyExchange()
                .hasRole("ADMIN");


        return http.build();
    }

If our pathMatcher failed here, we would fail safe. Our public pages would become restricted but our admin pages would remain restricted.

Published inSecurity

Be First to Comment

Leave a Reply

Your email address will not be published. Required fields are marked *