CVE-2026-22740
This Vulnerability has been fixed in the Never-Ending Support (NES) version offered by HeroDevs.
Overview
Spring Framework is the foundational framework of the Spring ecosystem, providing comprehensive support for developing Java enterprise applications. Its reactive web stack, Spring WebFlux, builds on Project Reactor to offer non-blocking request handling, including streaming codecs for HTTP multipart/form-data uploads.
A medium-severity vulnerability (CVE-2026-22740) has been identified in Spring WebFlux's multipart request processing. When a WebFlux application receives a multipart request, parts larger than 10 KB are spilled to temporary files on disk by DefaultPartHttpMessageReader. Under certain conditions, such as a client disconnect after the body is read but before the handler consumes it, or a downstream cancellation or error after the parts have been collected, the reactive pipeline in MultipartHttpMessageReader.readMono discards the collected parts without calling Part.delete(). The temp files remain on disk, and a remote attacker who can send multipart requests can repeatedly trigger this condition to exhaust available disk space and deny service to the application.
Per OWASP: "The Denial of Service (DoS) attack is focused on making a resource (site, application, server) unavailable for the purpose it was designed. There are many ways to make a service unavailable for legitimate users by manipulating network packets, programming, logical, or resources handling vulnerabilities, among others." In this case, the attacker exploits a resource-handling flaw in the reactive multipart codec to exhaust the disk resource of the target host.
The CVSS v3.1 base score for this vulnerability is 6.5 (Medium) with vector AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H. The attack is network-accessible and requires only low privileges and no user interaction, and its impact is confined to availability (no confidentiality or integrity loss).
The vulnerable code was introduced in Spring Framework 5.0.0 (September 2017) when MultipartHttpMessageReader was turned into a concrete WebFlux reader using collectMultimap(Part::name) without a doOnDiscard cleanup hook, and the same pattern remained in every subsequent release up to the listed fix versions. This issue affects versions 5.0.0 through 5.3.47, 6.0.0 through 6.0.23, 6.1.0 through 6.1.26, 6.2.0 through 6.2.17, and 7.0.0 through 7.0.6 of Spring Framework.
Details
Module Info
- Product: Spring Framework
- Affected packages: spring-web
- Affected versions: >=5.0.0 <=5.3.47, >=6.0.0 <=6.0.23, >=6.1.0 <=6.1.26, >=6.2.0 <=6.2.17, >=7.0.0 <=7.0.6
- 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:
- Spring Framework 6.2.18, 7.0.7 (OSS)
- Spring Framework 5.3.x, 6.1.x (NES)
Vulnerability Info
The vulnerability is in the MultipartHttpMessageReader class in the spring-web module, specifically in the readMono method that assembles a reactive pipeline for reading all multipart parts into a MultiValueMap.
DefaultPartHttpMessageReader streams each incoming part through an in-memory buffer up to maxInMemorySize (default 10 KB). Once a part exceeds that threshold, the reader falls back to Files.createTempFile and writes the remainder to disk. The resulting Part object holds a reference to the temp Path and exposes Part.delete() to remove the backing file when the consumer is done with it.
MultipartHttpMessageReader.readMono wraps that stream with Reactor operators to collect the parts into a Map<String, Collection<Part>> keyed by part name. Prior to the fix the pipeline did not install any cleanup hook for the discard path:
return this.partReader.read(elementType, inputMessage, allHints)
.collectMultimap(Part::name)
.doOnNext(map ->
LogFormatUtils.traceDebug(logger, traceOn -> Hints.getLogPrefix(hints) + "Parsed " +
(isEnableLoggingRequestDetails() ?
LogFormatUtils.formatValue(map, !traceOn) :
"parts " + map.keySet() + " (content masked)"))
)
.map(this::toMultiValueMap);
Reactor's contract for operators like collectMultimap is that if a downstream subscriber cancels, or if the sequence errors after the collection has been emitted but before the consumer takes ownership, the collected value is discarded. Because there was no doOnDiscard handler on the Mono<Map<String, Collection<Part>>>, nothing walked the map to call Part.delete() on the discard path. The temp files created for parts larger than 10 KB remained on disk after the request terminated.
Practical triggers include a client that closes the connection after the full body has been read, a downstream handler that throws or cancels while readMono is in flight, and any composition that drops the emitted map value after it is produced. The advisory's "under some circumstances" phrasing reflects this sensitivity to timing. The same underlying discard leak has been reported historically in gh-28740 (WebFlux multipart temporary file not deleted when the client disconnects early) and gh-31217 (WebFlux temporary file not always deleted with parallel uploads); CVE-2026-22740 is the formal security classification of that class of leak.
The fix inserts a doOnDiscard handler on the Mono<Map> so that any discarded collection triggers deletion of every contained part:
...
.doOnDiscard(Map.class, map ->
((Map<String, Collection<Part>>) map).values()
.forEach(parts -> parts.forEach(part -> part.delete().subscribe())))
...
On the success path the new handler is a no-op because the value flows through doOnNext and map to the downstream consumer. On the cancel or error path Reactor invokes the discard hook, which walks the collected parts and calls part.delete().subscribe() on each one, reliably removing the temp files.
Only the WebFlux reactive multipart codec is affected. Spring MVC relies on the Servlet container's Part implementation and its own cleanup path, which is not touched by this change.
Mitigation
Only recent versions of Spring Framework receive community support and updates. Older versions have no publicly available fixes for this vulnerability.
Users of the affected components should apply one of the following mitigations:
- Upgrade to a currently supported version of Spring Framework.
- Leverage a commercial support partner like HeroDevs for post-EOL security support through Never-Ending Support (NES) for Spring Framework.
Credits
- Xint Code (finder)
- Yuki Matsuhashi (finder)