October 30, 2026
Spring4Shell Step by Step: How CVE 2022 22965 Turns Data Binding Into Remote Code Execution in a…
One nested property path in a request is enough to rewrite how the server logs, and then to write a web shell in a lab.

By Muhammad Asim Shahzad
5 min read
Spring applications bind request parameters onto Java objects automatically. That convenience is the feature. Spring4Shell is what happens when an attacker can keep walking past the intended object, through its class properties, and into the web server logging configuration itself. This article explains that chain in a lab only, with detection and a verified fix.
Disclosure: This article was researched and written with AI assistance, and it was checked for accuracy and originality before publishing.
Everything below is for an isolated lab you own, built from a deliberately vulnerable training application. Never run these steps against a system you do not own or have explicit written permission to test.
The vulnerability, explained simply
CVE 2022 22965, widely called Spring4Shell, is a remote code execution flaw in Spring MVC data binding. The official record is at https://nvd.nist.gov/vuln/detail/CVE-2022-22965
The flaw needs a specific combination. The application must use Spring MVC, run on JDK 9 or later, and be deployed as a WAR file on a standalone Tomcat server. A typical Spring Boot application packaged as an executable jar with embedded Tomcat does not follow the main exploit chain, and JDK 8 applications are not affected by this chain. Those conditions narrowed the real world population, even though the severity score is critical at 9.8.
Data binding normally sets fields the developer chose, such as a name or an age on a form object. Spring4Shell abuses nested property access. By naming properties that lead from the bound object to its class, then to the class loader, then to Tomcat resources and logging objects, an attacker changes the access log configuration of Tomcat itself. The log file name, location and pattern are rewritten so that a later request writes attacker controlled text into a file with a script extension inside the web application. Visiting that file executes it as a web shell.
A clear public analysis of this mechanism, including the property chain into the logging pipeline, is available at https://www.sentinelone.com/vulnerability-database/cve-2022-22965/ and a plain language explainer with exact patched versions is at https://dev.to/vulert_official/spring4shell-explained-is-your-spring-application-still-vulnerable-31m8
Lab setup
Build the lab on an isolated virtual network with no route to your real network or the internet beyond package downloads you control.
-
Create a virtual machine with JDK 11 and a standalone Tomcat 9 installation.
-
Deploy a known vulnerable Spring MVC training application as a WAR file, using Spring Framework 5.3.17 or another version below 5.3.18.
-
Take a snapshot before exploitation so you can reset cleanly.
-
Place a second virtual machine on the same isolated network as your attacker machine, with a browser, an intercepting proxy and a simple HTTP client.
-
Turn on Tomcat access logging and watch the web application directory, because the exploitation writes a new file there.
Confirm the lab answers normally first. Submit the training form once and check that binding works and that a normal access log line appears.
Exploitation, step by step
Step 1. Confirm binding. Send the normal form request through your proxy and note the parameter names the application binds. Your goal is to prove the endpoint binds request parameters onto an object without an allowlist.
Step 2. Walk the property path. In your lab request, replace a normal parameter with a nested property path that reaches the class loader logging chain described in the public analysis above. The path names the class property, the module, the class loader, the resources, the context, the parent and the logging pipeline. A vulnerable application accepts this path instead of rejecting it. An error or a changed behaviour is your first signal.
Step 3. Rewrite the log destination. Using that same property access, set the logging pipeline values so the access log is written inside the web application folder, with a script file extension, and with a log pattern made only of a value you control. Each property is set in its own request in most public lab walkthroughs.
Step 4. Plant the shell content. Send a request whose header or parameter value contains a small lab marker command, matching the pattern you set. Tomcat writes that value into the new log file, which is now a script file in the web root.
Step 5. Call the file. Browse to the new file in your lab application and pass your marker command. If the page returns your marker output, remote code execution is proved in the lab. Stop at the marker. There is no need to go further, and in a real assessment this point is where reporting begins.
Step 6. Reset and repeat once. Restore the snapshot, repeat the chain once to confirm your notes, and record the exact Spring and JDK versions, because version evidence is what makes a report credible.
What the attacker gains
Successful exploitation gives code execution with the permissions of the Tomcat service account. From there an attacker in a real incident could read application configuration and secrets, reach internal databases the application trusts, install persistence and move sideways. In the lab, the lesson is narrower and more useful. A binding feature became a file write, and a file write became code execution, all without any login.
How defenders detect it
-
Search web logs for requests containing class property paths, especially the class loader and logging pipeline property names from public detection rules.
-
Alert on new script files appearing in web application directories outside a deployment window.
-
Watch for Tomcat access log configuration changes and for Java processes spawning shells or unexpected child processes.
-
Scan for vulnerable versions. Public vendor guidance explains how to inventory Spring Beans jars inside WAR files and confirm framework versions, for example at https://ridgesecurity.ai/blog/spring4shell-vulnerability-detection-with-ridgebot/
Treat any confirmed exploitation attempt against a production server as an incident, not only a patching task, because a written shell may already exist.
How to fix it and verify the fix
Upgrade Spring Framework to 5.3.18 or later, or to 5.2.20 or later on the older branch. For Spring Boot, move to 2.6.6 or later, or to 2.5.12 or later on the older branch. Rebuild and redeploy the application.
As a temporary measure only, restrict data binding by disallowing the class property patterns in your binder configuration, as described in the public explainer linked above. A temporary binding rule is not a substitute for the upgrade.
Verify the fix in three ways. First, print the resolved dependency tree and confirm the patched Spring version is what actually deployed. Second, repeat the lab property path requests against the patched build and confirm they are rejected and create no file. Third, confirm the normal form still binds correctly, so the fix did not break the application.
Closing takeaways
Spring4Shell is a lesson in reachable objects. If user input can name properties beyond the form fields, binding becomes an attack surface.
Conditions decide real risk. JDK version, deployment style and framework version together decide whether this chain works at all, which is why accurate inventory matters more than headlines.
Patch, then prove the patch. Version checks plus a failed repeat of the lab chain are the evidence that closes the finding.
Sources credited in this article: the NVD record, the SentinelOne vulnerability analysis, the public Spring4Shell explainer and the Ridge Security detection guide, all linked in the body above. All research is based on publicly disclosed material only, and all exploitation steps are described for an isolated lab only.
Tags: Cybersecurity, Spring4Shell, CVE-2022–22965, Penetration Testing, Vulnerability Management
Written by Muhammad Asim Shahzad, SVP Head Application Security and VAPT at UBL, with thirteen plus years in offensive security, HackerOne Top 100 history, Synack Red Team experience and CVE 2021 31521 to his name. More writing and services at protector47.com. Connect with Asim on LinkedIn at https://www.linkedin.com/in/protector47 and find his public researcher history through HackerOne under the name protector47.