Spring blog
Spring Framework RCE, Early Announcement
Updates
disallowedFields
Table of Contents
Overview
I would like to announce an RCE vulnerability in the Spring Framework that was leaked out ahead of CVE publication. The issue was first reported to VMware late on Tuesday evening, close to Midnight, GMT time by codeplutos, meizjm3i of AntGroup FG. On Wednesday we worked through investigation, analysis, identifying a fix, testing, while aiming for emergency releases on Thursday. In the mean time, also on Wednesday, details were leaked in full detail online, which is why we are providing this update ahead of the releases and the CVE report.
Vulnerability
The vulnerability impacts Spring MVC and Spring WebFlux applications running on JDK 9+. The specific exploit requires the application to be packaged and deployed as a traditional WAR on a Servlet container. If the application is deployed as a Spring Boot executable jar, i.e. the default, it is not vulnerable to the exploit. However, the nature of the vulnerability is more general, and there may be other ways to exploit it.
Am I Impacted?
These are the requirements for the specific scenario from the report:
spring-webmvc
or
spring-webflux
dependency.
Additional notes:
ClassLoader
access and depends on the actual Servlet Container in use. Tomcat 10.0.19, 9.0.61, 8.5.77, and earlier versions are known to be vulnerable. Payara and Glassfish are also known to be vulnerable. Other Servlet containers may also be vulnerable.
@ModelAttribute
or optionally without it, and without any other Spring Web annotation.
@RequestBody
controller method parameters (e.g. JSON deserialization). However, such methods may still be vulnerable if they have another method parameter populated via data binding from query parameters.
Status
Suggested Workarounds
The preferred response is to update to Spring Framework 5.3.18 and 5.2.20 or greater. If you have done this, then no workarounds are necessary. However, some may be in a position where upgrading is not possible to do quickly. For that reason, we have provided some workarounds below.
Please note that, workarounds are not necessarily mutually exclusive since security is best done "in depth".
Upgrading Tomcat
For older applications, running on Tomcat with an unsupported Spring Framework version, upgrading to Apache Tomcat 10.0.20 , 9.0.62 , or 8.5.78 , provides adequate protection. However, this should be seen as a tactical solution, and the main goal should be to upgrade to a currently supported Spring Framework version as soon as possible. If you take this approach, you should consider setting Disallowed Fields as well for defense in depth approach.
Downgrading to Java 8
Downgrading to Java 8 is a viable workaround, if you can neither upgrade the Spring Framework nor upgrade Apache Tomcat.
Disallowed Fields
Another viable workaround is to disable binding to particular fields by setting
disallowedFields
on
WebDataBinder
globally:
This works generally, but as a centrally applied workaround fix, may leave some loopholes, in particular if a controller sets
disallowedFields
locally through its own
@InitBinder
method, which overrides the global setting.
To apply the workaround in a more fail-safe way, applications could extend
RequestMappingHandlerAdapter
to update the
WebDataBinder
at the end after all other initialization. In order to do that, a Spring Boot application can declare a
WebMvcRegistrations
bean (Spring MVC) or a
WebFluxRegistrations
bean (Spring WebFlux).
For example in Spring MVC (and similar in WebFlux):
package car.app;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcRegistrations;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.annotation.InitBinderDataBinderFactory;
import org.springframework.web.method.support.InvocableHandlerMethod;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.ServletRequestDataBinderFactory;
@SpringBootApplication
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(CarApp.class, args);
@Bean
public WebMvcRegistrations mvcRegistrations() {
return new WebMvcRegistrations() {
@Override
public RequestMappingHandlerAdapter getRequestMappingHandlerAdapter() {
return new ExtendedRequestMappingHandlerAdapter();
private static class ExtendedRequestMappingHandlerAdapter extends RequestMappingHandlerAdapter {
@Override
protected InitBinderDataBinderFactory createDataBinderFactory(List<InvocableHandlerMethod> methods) {
return new ServletRequestDataBinderFactory(methods, getWebBindingInitializer()) {
@Override
protected ServletRequestDataBinder createBinderInstance(
Object target, String name, NativeWebRequest request) throws Exception {
ServletRequestDataBinder binder = super.createBinderInstance(target, name, request);
String[] fields = binder.getDisallowedFields();
List<String> fieldList = new ArrayList<>(fields != null ? Arrays.asList(fields) : Collections.emptyList());
fieldList.addAll(Arrays.asList("class.*", "Class.*", "*.class.*", "*.Class.*"));
binder.setDisallowedFields(fieldList.toArray(new String[] {}));
return binder;