Just when we thought we could go a few months without a critical framework vulnerability dominating every security channel, Spring4Shell (CVE-2022-22965) has arrived. A remote code execution vulnerability in the Spring Framework — arguably the most widely used Java application framework in the world — was disclosed this week, and the internet immediately went into panic mode with flashbacks to December’s Log4Shell disaster.
But after spending a couple of days analyzing this one, I think the reality is more nuanced than the catchy name suggests. Let me break down what we actually know.
What’s the Vulnerability?#
CVE-2022-22965 is a remote code execution (RCE) vulnerability affecting Spring MVC and Spring WebFlux applications running on JDK 9 or later. The vulnerability exploits a class-level data binding mechanism in Spring that, under specific conditions, allows an attacker to modify the class.module.classLoader properties through crafted HTTP requests.
The practical exploitation path that’s been demonstrated involves manipulating Tomcat’s AccessLogValve through the classloader to write a JSP webshell to the server. Once the webshell is planted, the attacker has arbitrary command execution on the server.
Spring has released patches in Spring Framework 5.3.18 and 5.2.20, and Spring Boot 2.6.6 and 2.5.12 include the fixed versions. If you’re running Spring in production, stop reading and go patch. I’ll wait.
Why It’s Not Quite Log4Shell#
The inevitable comparisons to Log4Shell are understandable — both affect ubiquitous Java frameworks, both enable RCE, and both have catchy names with “4” and “Shell” in them. But the actual risk profiles are significantly different:
The conditions are more restrictive. The known exploitation requires: (1) Spring MVC or WebFlux, (2) running on JDK 9+, (3) deployed as a WAR to a servlet container like Tomcat, and (4) using Spring’s data binding with specific parameter types. That’s a meaningful set of prerequisites. Many Spring Boot applications deploy as embedded containers (executable JARs), which changes the exploitation path.
Log4Shell was trivially exploitable. A single crafted string in any log message could trigger the vulnerability. Spring4Shell requires more targeted exploitation — the attacker needs to know or guess specific endpoint parameters and the application’s data binding configuration.
The attack surface is narrower. Log4Shell could be triggered through any input that ended up in a log statement — HTTP headers, form fields, query parameters, you name it. Spring4Shell requires specific HTTP request parameters that map to Spring’s data binding.
This doesn’t mean you should ignore it. It means you should prioritize patching without succumbing to the same level of all-hands-on-deck panic that Log4Shell warranted.
The Confusing Disclosure Timeline#
One of the frustrating aspects of this vulnerability has been the messy disclosure process. The CVE was initially confused with a separate Spring Cloud Function vulnerability (CVE-2022-22963), leading to widespread confusion in the first 24 hours. Proof-of-concept code was circulating on Chinese social media before the official advisory was published, and early reports mixed up the two issues.
This led to a situation where some organizations patched for the wrong vulnerability, while others dismissed the whole thing as overblown FUD. Neither response was correct.
The confusion was compounded by the fact that there was also a critical zero-day in Spring Cloud Gateway (CVE-2022-22947) disclosed around the same time. Three Spring-related CVEs in quick succession, all with similar numbering, all affecting different components. It’s been a rough week for anyone maintaining Spring-based infrastructure.
Practical Remediation Steps#
Here’s what I’d recommend, in order of priority:
1. Patch immediately. Upgrade to Spring Framework 5.3.18+ or 5.2.20+, or Spring Boot 2.6.6+ / 2.5.12+. This is the definitive fix.
2. If you can’t patch today, apply the workaround. Spring has documented a workaround using @ControllerAdvice to set DataBinder.setDisallowedFields() for class.*, Class.*, *.class.*, and *.Class.*. This prevents the property binding path that enables exploitation.
3. Check your JDK version. If you’re still on JDK 8 (and plenty of production systems are), you’re not affected by the known exploitation path. That said, don’t let this be a reason to delay patching — other exploitation paths may emerge.
4. Review your WAF rules. Many WAF vendors have already published rules to detect Spring4Shell exploitation attempts. Adding these as a defense-in-depth layer buys you time while patching works through your deployment pipeline.
5. Monitor for indicators of compromise. Look for unusual JSP files appearing in your web application directories, unexpected outbound connections from application servers, and web server access logs with suspicious parameter patterns targeting classloader properties.
The Bigger Picture: Framework Security Fatigue#
What concerns me most isn’t this specific vulnerability — it’s the pattern. Log4Shell in December, and now Spring4Shell in March. Two of the most fundamental pieces of the Java ecosystem, both with critical RCE vulnerabilities, discovered within four months of each other.
The Java ecosystem’s heavy reliance on reflection, dynamic class loading, and runtime binding has always been a double-edged sword. These features enable the powerful framework abstractions that make Spring so productive, but they also create attack surfaces that are difficult to reason about and easy to overlook.
I’ve been writing Java professionally since the late 1990s, and the framework surface area has grown enormously. A modern Spring Boot application pulls in dozens of auto-configured components, each with their own assumptions about data binding, serialization, and request handling. The total attack surface is vast, and much of it is invisible to application developers who just want to write business logic.
My Take#
Patch this, but don’t panic. Spring4Shell is serious, but it’s not the same class of catastrophe as Log4Shell. The exploitation conditions are more specific, the blast radius is more contained, and patches are already available.
What I hope comes out of this is a renewed focus on secure-by-default configurations in major frameworks. Spring’s data binding is powerful, but the ability to bind arbitrary request parameters to internal class properties should never have been accessible without explicit opt-in. The principle of least privilege should apply to framework features, not just user permissions.
In the meantime, update your dependencies and make sure your vulnerability scanning pipeline can detect this. And maybe pour one out for the Spring security team, who I imagine haven’t slept much this week.
