CVE-2026-59314
This Vulnerability has been fixed in the Never-Ending Support (NES) version offered by HeroDevs.
Overview
Spring Framework is a widely used application framework for the Java platform that provides the core programming and configuration model for modern Java enterprise applications, including the Spring MVC servlet web stack, the Spring WebFlux reactive web stack, and the RestTemplate, RestClient and WebClient HTTP clients. All of these share the spring-web module, whose HttpHeaders class models HTTP request and response headers. Since Spring Framework 5.0, ContentDisposition is the value type behind the Content-Disposition header: applications build one with ContentDisposition.attachment(), ContentDisposition.inline() or ContentDisposition.formData(), give it a name and a filename, and HttpHeaders writes the result of ContentDisposition.toString() into the header, both for download responses and for each part of an outbound multipart/form-data request body.
An HTTP response splitting vulnerability (CVE-2026-59314) has been identified in ContentDisposition, which allows attackers who control the name or filename value placed in a Content-Disposition header to inject carriage return and line feed characters into that header. Because ContentDisposition.toString() writes the two values without stripping control characters, an attacker-supplied file name can terminate the header early and append headers or body content of the attacker's choosing. When the header is set on an HTTP response, this is classic HTTP response splitting, although it only succeeds when the underlying HTTP connector does not itself reject such characters: the connectors supported by Spring Framework (Tomcat, Reactor Netty, Jetty and Undertow) already do, so this case applies only to non-default or legacy connectors. When the header is written into a part of an outbound multipart request body, Spring Framework itself emits the bytes, so the injection corrupts the framing of the multipart body regardless of the connector in use.
Per OWASP, the HTTP splitting and smuggling family covers "two different attacks that target specific HTTP headers", and the one at issue here is splitting: "The first attack exploits a lack of input sanitization which allows an intruder to insert CR and LF characters into the headers of the application response and to 'split' that answer into two different HTTP messages. The goal of the attack can vary from a cache poisoning to cross site scripting."
The advisory rates this vulnerability Low severity with the CVSS v3.1 vector AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:L/A:N, which corresponds to a base score of 3.1. The attack vector is Network because the malicious file name arrives in an ordinary HTTP request, attack complexity is High because the application must pass untrusted input into a Content-Disposition value and, for the response case, must run on a connector that does not reject control characters in header values, no privileges are required, user interaction is Required because a victim must receive the split response or the corrupted multipart body, and the impact is Integrity-only and Low because the outcome is injected header or body content rather than access to data held by the application.
This issue affects Spring Framework <=5.2.25, >=5.3.0 <=5.3.49, >=6.0.0 <=6.0.30, >=6.1.0 <=6.1.28, >=6.2.0 <=6.2.19, and >=7.0.0 <=7.0.8, including the End-of-Life 4.3.x, 5.3.x, 6.1.x, and 6.2.x lines supported by NES for Spring Framework.
Details
Module Info
- Product: Spring Framework
- Affected packages:
org.springframework:spring-web - Affected versions: <=5.2.25, >=5.3.0 <=5.3.49, >=6.0.0 <=6.0.30, >=6.1.0 <=6.1.28, >=6.2.0 <=6.2.19, >=7.0.0 <=7.0.8
- GitHub repository: https://github.com/spring-projects/spring-framework
- Published packages: https://central.sonatype.com/artifact/org.springframework/spring-web
- Package manager: Maven
- Fixed in:
- NES for Spring Framework nes-v4.3.40, nes-v5.3.54, nes-v6.1.30, and nes-v6.2.21
- Spring Framework 7.0.9 (OSS)
Vulnerability Info
This Low-severity vulnerability is found in the spring-web package in multiple versions of Spring Framework. org.springframework.http.ContentDisposition is an immutable representation of a Content-Disposition header value as defined in RFC 6266. Application code obtains a builder from ContentDisposition.attachment(), ContentDisposition.inline() or ContentDisposition.formData(), sets the name and filename parameters, and calls build(). The resulting object is serialized to a header string by toString(), which concatenates each parameter into the header value:
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
if (this.type != null) {
sb.append(this.type);
}
if (this.name != null) {
sb.append("; name=\"");
sb.append(this.name).append('\"');
}
if (this.filename != null) {
if (this.charset == null || StandardCharsets.US_ASCII.equals(this.charset)) {
sb.append("; filename=\"");
sb.append(encodeQuotedPairs(this.filename)).append('\"');
}
else {
sb.append("; filename=\"");
sb.append(encodeQuotedPrintableFilename(this.filename, this.charset)).append('\"');
sb.append("; filename*=");
sb.append(encodeRfc5987Filename(this.filename, this.charset));
}
}
// size, creation-date, modification-date, read-date ...
return sb.toString();
}
The name value is appended verbatim. The filename value, when no charset or the US-ASCII charset is in effect, only has its double quotes and backslashes escaped; on the 5.3.x line the equivalent helper is escapeQuotationsInFilename, which likewise touches nothing but quotes. Neither path removes or encodes C0 control characters, so a name or filename containing \r\n is written into the header value as a raw line break. Whatever follows the line break is no longer part of the Content-Disposition parameter: it is interpreted as a new header line, and a second blank line starts a new body.
Two call paths make this reachable with attacker-controlled input. The first is the response header. HttpHeaders.setContentDisposition(ContentDisposition) stores contentDisposition.toString() directly as the Content-Disposition header value, so a download controller that builds the header from a user-supplied file name, for example headers.setContentDisposition(ContentDisposition.attachment().filename(requestedName).build()), hands the raw name to the HTTP connector. The connectors supported by Spring Framework reject CR and LF in header values, which is why the advisory limits this case to non-default or legacy connectors.
The second is the outbound multipart body, and it does not depend on the connector at all, because Spring Framework writes the part headers into the request body itself. FormHttpMessageConverter.writeParts (used by RestTemplate and RestClient), MultipartBodyBuilder, MultipartHttpMessageWriter and PartHttpMessageWriter (used by WebClient), and on the 6.x lines RequestPartArgumentResolver for HTTP interface clients all build a ContentDisposition.formData() value from the part name and file name they are given and call toString() on it while writing the part. A common pattern in file-upload proxies is to forward an uploaded file to a downstream service using the client's original file name, so an attacker who uploads a file whose name contains \r\n followed by text of their choosing ends the part's header block early and injects headers or body content into the multipart stream the application sends to the third party.
Before ContentDisposition existed, the same header string was produced directly by HttpHeaders.setContentDispositionFormData(String name, String filename), which the multipart writer of the 3.x and 4.x lines calls for every part. That method has the identical flaw, and it is still present on the 4.3.x line:
public void setContentDispositionFormData(String name, String filename) {
Assert.notNull(name, "'name' must not be null");
StringBuilder builder = new StringBuilder("form-data; name=\"");
builder.append(name).append('\"');
if (filename != null) {
builder.append("; filename=\"");
builder.append(escapeQuotationsInFilename(filename)).append('\"');
}
set(CONTENT_DISPOSITION, builder.toString());
}
Spring Framework 5.0 moved this formatting into the new ContentDisposition class and reimplemented setContentDispositionFormData on top of its builder, passing the same name and filename through to ContentDisposition.toString() and carrying the unsanitized concatenation along with it. On the 4.x lines there is no ContentDisposition builder, so the response-header case does not apply there, but the multipart case reaches setContentDispositionFormData through FormHttpMessageConverter in exactly the same way.
This vulnerability was introduced in 2010 with Spring Framework 3.0.2.RELEASE.
Mitigation
Only recent versions of Spring Framework receive community support. The 4.3.x, 5.3.x, 6.1.x, and 6.2.x lines are End-of-Life and will not receive public updates to address this issue, so there is no publicly available fix for those lines other than through a commercial support partner.
Applications that cannot upgrade immediately can reduce their exposure by never passing untrusted input straight into a Content-Disposition value: strip or reject carriage return, line feed and other control characters from user-supplied file names before calling ContentDisposition.Builder.filename or HttpHeaders.setContentDispositionFormData, and generate server-side names for parts when forwarding uploaded files to other services instead of reusing the client's original file name.
Users of the affected components should apply one of the following mitigations:
- Upgrade to a currently supported version of Spring Framework. The open-source fix ships in Spring Framework 7.0.9 on the 7.0.x line.
- Leverage a commercial support partner like HeroDevs for post-EOL security support, which provides the fix for the 4.3.x, 5.3.x, 6.1.x, and 6.2.x lines in nes-v4.3.40, nes-v5.3.54, nes-v6.1.30, and nes-v6.2.21.
Credits
- No public finder credit is listed in the advisory sources checked for this entry.