Vulnerability Analysis

Spring4Shell (CVE-2022-22965): Remote Code Execution in Spring Framework

A critical RCE in Spring Framework sent Java teams scrambling. While less catastrophic than Log4Shell, Spring4Shell exposed dangerous assumptions about ClassLoader access in Java web applications.

Yukti Singhal
Security Researcher
5 min read

On March 29, 2022, rumors of a critical remote code execution vulnerability in the Spring Framework began circulating on Chinese social media. Within 24 hours, proof-of-concept exploits were public, and the vulnerability — quickly dubbed "Spring4Shell" — was confirmed as CVE-2022-22965 with a CVSS score of 9.8.

The timing was particularly cruel. The Java ecosystem was still recovering from the Log4Shell aftermath when a new critical vulnerability in another foundational framework appeared. But Spring4Shell, while serious, turned out to be less universally exploitable than Log4Shell — a distinction that required nuanced understanding to appreciate.

What Is Spring4Shell?

CVE-2022-22965 is a remote code execution vulnerability in Spring Framework's data binding mechanism. When a Spring MVC application runs on Apache Tomcat as a WAR deployment, an attacker can manipulate the ClassLoader through specially crafted HTTP requests to write a malicious JSP file to the server, achieving remote code execution.

The vulnerability affects:

  • Spring Framework 5.3.0 to 5.3.17 and 5.2.0 to 5.2.19
  • Running on JDK 9 or later
  • Deployed as a WAR on Apache Tomcat

Technical Deep Dive

Spring Framework's data binding feature automatically maps HTTP request parameters to Java object properties. For example, a request like ?name=John&age=30 would automatically populate a User object's name and age fields.

The vulnerability exploits the fact that Spring's data binding traverses the entire object graph, including the class property that every Java object inherits. Through class, an attacker can navigate to the ClassLoader, and from there to Tomcat's internal logging configuration.

The exploitation chain:

class.module.classLoader.resources.context.parent.pipeline.first.pattern=<malicious JSP>
class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp
class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT
class.module.classLoader.resources.context.parent.pipeline.first.prefix=shell
class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=

This sequence of parameters:

  1. Navigates from the bound object through classmoduleclassLoader
  2. Reaches Tomcat's AccessLogValve configuration
  3. Configures the access log to write a JSP webshell to the web application directory
  4. Any subsequent request triggers the access log write, creating the webshell
  5. The attacker then requests the webshell to execute arbitrary commands
GET /?class.module.classLoader.resources.context.parent.pipeline.first.pattern=
%25%7Bc2%7Di%20if(%22j%22.equals(request.getParameter(%22pwd%22)))
%7B%20java.io.InputStream%20in%20%3D%20Runtime.getRuntime().exec(request.getParameter(%22cmd%22))
.getInputStream()%3B%20...%20%7D%25 HTTP/1.1

Why JDK 9+ Was Required

The critical path through class.module.classLoader only works on JDK 9 and later because the module property was introduced with the Java Module System (Project Jigsaw) in JDK 9. On JDK 8, the path from class to classLoader was blocked by a security fix applied in 2010 (in response to CVE-2010-1622).

The JDK 9 module system inadvertently created a new path to the ClassLoader that bypassed the old security fix. This is a textbook example of how new features can reintroduce previously-patched vulnerabilities.

Why WAR on Tomcat Was Required

The exploitation technique depends on Tomcat's AccessLogValve being accessible through the ClassLoader hierarchy. This specific path exists when:

  • The application is deployed as a WAR file (not an executable JAR)
  • The servlet container is Apache Tomcat

Spring Boot applications running as executable JARs with the embedded Tomcat were not vulnerable through this specific exploitation path, though the underlying data binding issue still existed.

The Initial Confusion

The disclosure of Spring4Shell was messy. Before the real vulnerability was confirmed, a different Spring vulnerability (CVE-2022-22963, in Spring Cloud Function) was widely conflated with it. This led to:

  • Incorrect patches being applied
  • False negatives from scanners looking for the wrong CVE
  • Confusion about which applications were actually affected
  • Premature "all clear" announcements from organizations that only patched the wrong issue

This confusion underscored the importance of precise vulnerability tracking. CVE-2022-22963 and CVE-2022-22965 are completely different vulnerabilities in different components with different attack vectors.

Mitigation and Patching

Upgrade Spring Framework to 5.3.18+ or 5.2.20+ — this is the definitive fix.

Upgrade to Tomcat 10.0.20+, 9.0.62+, or 8.5.78+ — Tomcat also patched its side by restricting what properties can be accessed through data binding.

Upgrade to JDK 18.0.1+ or equivalent — JDK vendors also addressed the issue by restricting ClassLoader access from the module property.

For immediate mitigation without patching, Spring provided a workaround using @InitBinder:

@ControllerAdvice
public class BinderControllerAdvice {
    @InitBinder
    public void setAllowedFields(WebDataBinder dataBinder) {
        String[] denylist = new String[]{
            "class.*", "Class.*", "*.class.*", "*.Class.*"
        };
        dataBinder.setDisallowedFields(denylist);
    }
}

Impact Assessment

While the CVSS score of 9.8 suggested catastrophic risk, the actual impact was more contained than Log4Shell because of the specific conditions required for exploitation:

  • JDK 9+ (many enterprise applications still ran JDK 8)
  • WAR deployment on Tomcat (Spring Boot JAR deployments were not directly exploitable)
  • Spring MVC with data binding (not all Spring applications use this pattern)

That said, organizations running Spring MVC applications as WAR files on Tomcat with JDK 9+ were fully vulnerable to unauthenticated remote code execution. Active exploitation was observed in the wild within days of disclosure.

How Safeguard.sh Helps

Safeguard.sh provides precise vulnerability matching that distinguishes between CVE-2022-22963 and CVE-2022-22965, avoiding the confusion that plagued the initial response. Our platform correlates Spring Framework versions, JDK versions, and deployment configurations from your SBOM data to determine which applications are actually exploitable — not just theoretically vulnerable. This means your team focuses remediation efforts on genuinely at-risk systems rather than chasing false positives.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.