The Spring4Shell vulnerability, tracked as CVE-2022-22965, was a remote code execution flaw in the Spring Framework's data-binding mechanism, disclosed and patched at the end of March 2022. It let an attacker manipulate class-loading properties through crafted HTTP request parameters, and under a specific set of conditions — Java 9 or later, Spring's parameter binding enabled on a class object, and deployment as a traditional WAR file on Apache Tomcat — an attacker could write a malicious file to the server and achieve code execution. It arrived less than four months after Log4Shell, which is a large part of why it got a "4Shell" nickname and an outsized amount of attention relative to how narrow its actual exploitation conditions were.
What made Spring4Shell exploitable in the first place?
The root cause was Spring MVC's data binder allowing user-supplied request parameters to set nested Java object properties, including properties reachable through a class's ClassLoader. On Java 9+, certain classloader-related properties became reachable through that binding mechanism in a way they weren't on Java 8, because of changes to how Module and ClassLoader objects were exposed. Combined with running on Tomcat as a WAR deployment, an attacker could manipulate logging configuration properties through this class-property injection path to write a JSP web shell into a location the server would then execute — giving remote code execution without needing any authenticated access.
Which applications were actually exposed?
Not every Spring application was vulnerable, despite the initial alarm. Confirmed exploitation required all of: Spring Framework versions before the patched releases, Java 9 or newer, Spring MVC or Spring WebFlux with parameter binding on a POJO (not purely JSON-body binding), and deployment as a traditional WAR on a servlet container like Tomcat rather than as an embedded, executable JAR. Applications built with Spring Boot's default embedded-Tomcat, executable-JAR packaging model were substantially less exposed than traditional WAR deployments, though Spring Boot applications weren't universally safe — the framework-level fix applied regardless of packaging, because the underlying binding behavior was the actual defect.
What did the actual patch change?
Spring Framework shipped fixed versions — 5.3.18 and 5.2.20 — that restricted which class properties the data binder would allow to be set through request parameter binding, closing off the ClassLoader/Module property path that made the exploit possible. Spring Boot followed with its own patched releases pinning the fixed Framework version. The fix addressed the binding mechanism itself rather than patching the Tomcat-specific exploitation path, which is why it closed the vulnerability regardless of deployment style rather than only protecting the specific WAR-on-Tomcat configuration researchers initially demonstrated.
What should teams have done if they couldn't patch immediately?
Several mitigations reduced exposure while a full framework upgrade was rolled out:
- Restricting the data binder's allowed fields explicitly via
WebDataBinder.setDisallowedFields, blocking the class-property patterns the exploit relied on. - Upgrading to Java 8 where feasible, since the specific classloader exposure required Java 9+ — though this was a stopgap, not a fix, and came with its own tradeoffs.
- Switching WAR deployments to Spring Boot's embedded-container model where practical, since it removed one of the required exploitation conditions.
- Applying WAF rules to block the known exploitation pattern in request parameters as a temporary compensating control.
None of these substituted for the framework patch — they bought time for teams running large deployments that couldn't upgrade same-day.
Why does Spring4Shell still show up in scans years later?
Because dependency graphs are sticky — a vulnerable Spring Framework version pinned by an old parent POM, an unmaintained internal library, or a vendored dependency can persist in a build long after the rest of the application has moved on, especially in large Java monoliths where a framework bump touches dozens of modules at once. Software composition analysis scanning catches this by flagging the specific vulnerable version range in your dependency tree, rather than relying on someone remembering to check a two-year-old CVE against a build that hasn't been re-audited since it last compiled cleanly.
FAQ
Is Spring4Shell the same as Log4Shell?
No, they're unrelated vulnerabilities in different projects that happened to be disclosed close together. Log4Shell (CVE-2021-44228) was a deserialization/JNDI lookup flaw in the Log4j logging library; Spring4Shell was a data-binding flaw in the Spring Framework.
Does upgrading Spring Boot alone fix Spring4Shell?
You need the patched Spring Framework version specifically — Spring Boot's patched releases pin that Framework version, so upgrading Spring Boot to a fixed release is the practical path, but the underlying fix lives in Framework, not Boot itself.
Were Spring WebFlux applications affected?
WebFlux applications could be affected under similar binding conditions, though the most widely demonstrated exploitation path targeted Spring MVC on Tomcat with WAR deployment. Patching addressed the binder behavior across both.
Is Spring4Shell still actively exploited?
Active internet-wide scanning for the pattern dropped off substantially after patches were widely adopted, but the vulnerability still surfaces in dependency scans of unpatched legacy applications, which remain a real target if internet-facing.