Don't Panic: The Thymeleaf Template Injection That Only Hurts If You Let It (CVE-2026-40478)
29. April 2026
0 Min. LesezeitThe Thymeleaf vulnerability with a CVSS score of 9.1 grabs your attention, as it should. But before you call the cavalry and claim this as the new Log4shell, read this first.
CVE-2026-40478 is a server-side template injection vulnerability in Thymeleaf. Thymeleaf is a templating engine in Java that is used for server-side webpage rendering. The sandbox that normally prevents arbitrary code execution got bypassed using a tab character. And yes, this can lead to a remote code execution if exploited.
But here is the part that matters most: this vulnerability only applies if your code is already doing something it shouldn't.
What the sandbox protects against
Thymeleaf has a security sandbox. It limits what SpEL (Spring Expression Language) expressions can do when they evaluate dynamic content. The sandbox exists for one specific situation: when user-controlled input somehow reaches Thymeleaf's expression engine.
If that never happens in your code, the sandbox is never involved, and this CVE never touches you. The correct way to use Thymeleaf is simple: user input goes into the data model. The template stays static most of the time in an HTML file
Java code:
Thymeleaf template:
Thymeleaf renders the value of name. It never parses it as an expression. An attacker can send whatever payload they want as name, and nothing interesting happens. This is the design. This is how Thymeleaf is supposed to work.
Abusing the templating engine
The vulnerability becomes exploitable when a developer allows user input to reach the expression engine directly. If this occurs, it indicates the developer is misusing the framework. Although possible, it is quite challenging to achieve this, especially when using Thymeleaf within Spring Boot.
As shown in the code above, I have to create a new instance of the templateEngine manually and set a resolver. Something that is normally provided by Spring.
Next to that, I need to set the variable in the context to make my normal, legitimate use case work.
However, in the case above, the user's input is passed to the expression engine. That's the precondition for this CVE to matter.
A similar misuse pattern is dynamic view resolution. Instead of building template strings directly, a developer might resolve views based on user input:
The use case is legitimate, with one endpoint serving multiple pages. But user input is now influencing what Thymeleaf parses. Same misuse pattern, with the same possible exploit. Notice again how much manual wiring is required just to get here. The safe version is still just three lines.
How the tab character breaks the Thymeleaf sandbox
After a misuse pattern is in place, the actual exploit is straightforward.
The sandbox checks for new (the keyword followed by a space) to block object instantiation. The bypass sends new[TAB] instead. The pre-check doesn't find new, so it passes. SpEL, however, treats the tab as valid whitespace and parses it correctly.
The payload looks like this:
After the keyword check, a type blocklist runs, blocking java.* classes. However, Spring classes weren't included in this list. As a result, the incomplete blocklist, combined with a weak filter for new, allowed classes like FileSystemResource to load. This led to a file being written to disk. In theory, this allows an attacker to drop a JSP file that calls the ProcessBuilder and executes an RCE.
Two defenses failed independently: a whitespace issue in the keyword check and a narrow blocklist. The bypass succeeded because the checks were incomplete on what was considered a separator. EndorLabs provided a more detailed analysis of the exploit if you're interested.
Check out the GitHub repository for the working examples of the safe and unsafe code
What you need to do
Patch first. Update to Thymeleaf 3.1.4 regardless of whether you think your code is affected. Don't wait for the audit results.
If you are using Thymeleaf via Spring Boot, simply update your Spring Boot starter parent to the latest version (currently 3.5.14 or 4.0.6). If it turns out that you are a few versions behind, you might want to take a look at the OpenRewrite recipes to migrate to the latest version of Spring Boot 3.5 or Spring Boot 4.0
After updating, examine your code to see whether template strings or page resolution are generated dynamically from user input by passing it directly to the template engine. If this occurs, it is a misuse pattern. Fix the code itself, not just the library version.
The CVSS score 9.1 is real, but conditional
A critical CVSS score assumes the precondition is met. If your code feeds user input into Thymeleaf's expression engine, a score of 9.1 is accurate, and the impact is severe. If it doesn't, you're not affected by the CVE itself. However, you should still patch!
The audit question to ask your team is not just "what version of Thymeleaf are we running?" It's "do we dynamically construct view names or template expressions from request data?"
Patch Thymeleaf to version 3.1.4 or beyond, then find out the answer to that second question. Regardless of the answer, keep scanning your dependencies in development and monitor them in production with Snyk Open Source. The best part is that you can start for free.
Start securing your Python apps
Find and fix Python vulnerabilities with Snyk for free.
No credit card required.
Or Sign up with Azure AD Docker ID Bitbucket
By using Snyk, you agree to abide by our policies, including our Terms of Service and Privacy Policy.
