Share
## https://sploitus.com/exploit?id=044C59C9-7B55-579A-BC1D-890FC5EED45D
This repo is a set of samples to demonstrate the arrangements wherein applications may be vulnerable to https://spring.io/security/cve-2023-34035[CVE-2023-34035].

An application is vulnerable when all of the following are true:

Spring MVC is on the classpath

`DispatcherServlet` and at least one other servlet are mapped; one of them having a path-based servlet mapping (for example, `/path/**`)

The application uses `requestMatchers(String)` to refer to endpoints whose servlet mapping is of the form `/path/**`

== Samples

There are a set of samples that use Spring Boot and a set that do not.

The samples that contain failing tests are vulnerable to CVE-2023-34035. The samples whose tests pass are not vulnerable.

In all cases, each of these samples contains the same mitigation error from Spring Security, though note that such a mitigation is temporary in many circumstances, pending the next maintenance release.

=== `servlet:java-configuration:dispatcher-servlet-path`

https://github.com/jzheaux/cve-2023-34035-mitigations/tree/main/servlet/java-configuration/dispatcher-servlet-path[This sample] represents a vulnerable application where `DispatcherServlet` is deployed to `/mvc/*` instead of the default `/`.

It is *vulnerable* since Spring MVC is on the classpath, `DispatcherServlet` and at least one other servlet is mapped -- one of them with a non-root, path-based servlet mapping (in this case, `DispatcherServlet`), and the application uses `requestMatchers(String)` to secure those endpoints.

=== `servlet:java-configuration:jetty`

https://github.com/jzheaux/cve-2023-34035-mitigations/tree/main/servlet/java-configuration/jetty[This sample] represents a safe application where `DispatcherServlet` is deployed to `/` (the default).

It is *not vulnerable*. While Spring MVC is on the classpath and `DispatcherServlet` is in use, it is deployed to `/` and there are no non-root, path-based servlet mappings.

=== `servlet:java-configuration:other-servlets`

https://github.com/jzheaux/cve-2023-34035-mitigations/tree/main/servlet/java-configuration/other-servlets[This sample] represents a vulnerable application where `DispatcherServlet` is deployed as well as a custom servlet `MyServlet`.

It is *vulnerable* since Spring MVC is on the classpath, `DispatcherServlet` and at least one other servlet is mapped -- one of them with a non-root, path-based servlet mapping (in this case, `MyServlet`), and the application uses `requestMatchers(String)` to secure those endpoints.

=== `servlet:java-configuration:tomcat`

https://github.com/jzheaux/cve-2023-34035-mitigations/tree/main/servlet/java-configuration/tomcat[This sample] represents a safe application where `DispatcherServlet` is deployed to `/` (the default).

It is *not vulnerable*. While Spring MVC is on the classpath and `DispatcherServlet` is in use, it is deployed to `/` and there are no non-root, path-based servlet mappings.

=== `servlet:java-configuration:two-dispatcher-servlets`

https://github.com/jzheaux/cve-2023-34035-mitigations/tree/main/servlet/java-configuration/two-dispatcher-servlets[This sample] represents a vulnerable application where `DispatcherServlet` is deployed as well as a custom servlet `MyServlet`.

It is *vulnerable* since Spring MVC is on the classpath, `DispatcherServlet` and at least one other servlet is mapped -- one of them with a non-root, path-based servlet mapping (in this case, one of the two ``DispatcherServlet``s), and the application uses `requestMatchers(String)` to secure those endpoints.

=== `servlet:spring-boot:java:dispatcher-servlet-path`

https://github.com/jzheaux/cve-2023-34035-mitigations/tree/main/servlet/spring-boot/java/dispatcher-servlet-path[This sample] represents a vulnerable application where `DispatcherServlet` is deployed to `/mvc/*` instead of the default `/`.

It is *vulnerable* since Spring MVC is on the classpath, `DispatcherServlet` and at least one other servlet is mapped -- one of them with a non-root, path-based servlet mapping (in this case, `DispatcherServlet`), and the application uses `requestMatchers(String)` to secure those endpoints.

=== `servlet:spring-boot:java:jetty`

https://github.com/jzheaux/cve-2023-34035-mitigations/tree/main/servlet/spring-boot/java/jetty[This sample] represents a safe application where `DispatcherServlet` is deployed to `/` (the default).

It is *not vulnerable*. While Spring MVC is on the classpath and `DispatcherServlet` is in use, it is deployed to `/` and there are no non-root, path-based servlet mappings.

=== `servlet:spring-boot:java:other-servlets`

https://github.com/jzheaux/cve-2023-34035-mitigations/tree/main/servlet/spring-boot/java/other-servlets[This sample] represents a vulnerable application where `DispatcherServlet` is deployed as well as a custom servlet `MyServlet`.

It is *vulnerable* since Spring MVC is on the classpath, `DispatcherServlet` and at least one other servlet is mapped -- one of them with a non-root, path-based servlet mapping (in this case, `MyServlet`), and the application uses `requestMatchers(String)` to secure those endpoints.

=== `servlet:spring-boot:java:tomcat`

https://github.com/jzheaux/cve-2023-34035-mitigations/tree/main/servlet/spring-boot/java/tomcat[This sample] represents a safe application where `DispatcherServlet` is deployed to `/` (the default).

It is *not vulnerable*. While Spring MVC is on the classpath and `DispatcherServlet` is in use, it is deployed to `/` and there are no non-root, path-based servlet mappings.

=== `servlet:spring-boot:java:undertow`

https://github.com/jzheaux/cve-2023-34035-mitigations/tree/main/servlet/spring-boot/java/undertow[This sample] represents a safe application where `DispatcherServlet` is deployed to `/` (the default).

It is *not vulnerable*. While Spring MVC is on the classpath and `DispatcherServlet` is in use, it is deployed to `/` and there are no non-root, path-based servlet mappings.

== Mitigations

In the event that you get an error like the following:

.Bash
[source,bash,role="primary"]
----
This method cannot decide whether these patterns are Spring MVC patterns or not.
If this endpoint is a Spring MVC endpoint, please use `requestMatchers(MvcRequestMatcher)`;
otherwise, please use `requestMatchers(AntPathRequestMatcher)`.
----

you should follow it.

[NOTE]
The `5.8.5`, `6.0.5`, `6.1.2`, and `6.2.0-M1` versions of Spring Security have some false positives.
Now that in many cases the following is temporary, pending the release of `5.8.6`, `6.0.6`, `6.1.3`, and `6.2.0-M2`.

As alluded to by the error message, the primary mitigation is to use a complete `RequestMatcher`.
This is so that the servlet mapping can be more clearly accounted for.

For example, if an application has a servlet deployed to `/my-servlet/*` and is authorizing that traffic like so:

.Java
[source,java,role="primary"]
----
@Bean
SecurityFilterChain appSecurity(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests((authorize) -> authorize
            .requestMatchers("/my-servlet/**").hasRole("USER")
            .requestMatchers("/spring-mvc-controller/**").hasRole("USER")
            .anyRequest().authenticated()
        )
        // ...
    return http.build();
}
----

then, the application should instead do:

.Java
[source,java,role="primary"]
----
import static org.springframework.security.web.util.matcher.AntPathRequestMatcher.antMatcher;

@Bean
MvcRequestMatcher.Builder mvc(HandlerMappingIntrospector introspector) {
	return new MvcRequestMatcher.Builder(introspector);
}

@Bean
SecurityFilterChain appSecurity(HttpSecurity http, MvcRequestMatcher.Builder mvc) throws Exception {
    http
        .authorizeHttpRequests((authorize) -> authorize
            .requestMatchers(antMatcher("/my-servlet/*")).hasRole("USER")
            .requestMatchers(mvc.pattern("/spring-mvc-controller/**")).hasRole("USER")
            .anyRequest().authenticated()
        )
        // ...
    return http.build();
}
----

Or, if `DispatcherServlet` is deployed to a different path, like `/spring-mvc/*`, then instead of:

.Java
[source,java,role="primary"]
----
@Bean
SecurityFilterChain appSecurity(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests((authorize) -> authorize
            .requestMatchers("/spring-mvc/controller/**")).hasRole("USER")
            .anyRequest().authenticated()
        )
        // ...
    return http.build();
}
----

an application should do:

.Java
[source,java,role="primary"]
----
@Bean
MvcRequestMatcher.Builder mvc(HandlerMappingIntrospector introspector) {
	return new MvcRequestMatcher.Builder(introspector).servletPath("/spring-mvc");
}

@Bean
SecurityFilterChain appSecurity(HttpSecurity http, MvcRequestMatcher.Builder mvc) throws Exception {
    http
        .authorizeHttpRequests((authorize) -> authorize
            .requestMatchers(mvc.pattern("/controller/**")).hasRole("USER")
            .anyRequest().authenticated()
        )
        // ...
    return http.build();
}
----

Separating the servlet path when constructing an `MvcRequestMatcher` is important to ensure that the request is correctly matched.

== Branches

In this repo, there is a branch for each minor release of Spring Security.
On that branch, there is a commit for each affected sample with the needed mitigation.

For example, on the `5.8.x` branch, there are eight commits to repair the eight samples that require mitigation.

When `5.8.6`, `6.0.6`, `6.1.3`, and `6.2.0-M2` are released, additional changes will be made to those branches so the best-practice mitigation is clear.