CVE-2025-61795
Description
Improper Resource Shutdown or Release vulnerability in Apache Tomcat.
If an error occurred (including exceeding limits) during the processing of a multipart upload, temporary copies of the uploaded parts written to disc were not cleaned up immediately but left for the garbage collection process to delete. Depending on JVM settings, application memory usage and application load, it was possible that space for the temporary copies of uploaded parts would be filled faster than GC cleared it, leading to a DoS.
This issue affects Apache Tomcat: from 11.0.0-M1 through 11.0.11, from 10.1.0-M1 through 10.1.46, from 9.0.0.M1 through 9.0.109.
The following versions were EOL at the time the CVE was created but are known to be affected: 8.5.0 though 8.5.100. Other, older, EOL versions may also be affected. Users are recommended to upgrade to version 11.0.12 or later, 10.1.47 or later or 9.0.110 or later which fixes the issue.
Affected products
2- Apache Software Foundation/Apache Tomcatv5Range: 11.0.0-M1
Patches
3af6e91816203Explicitly clean up after failed multi-part upload
3 files changed · +25 −1
java/org/apache/catalina/connector/LocalStrings.properties+1 −0 modified@@ -92,6 +92,7 @@ request.asyncNotSupported=A filter or servlet of the current chain does not supp request.fragmentInDispatchPath=The fragment in dispatch path [{0}] has been removed request.illegalWrap=The request wrapper must wrap the request obtained from getRequest() request.notAsync=It is illegal to call this method if the current request is not in asynchronous mode (i.e. isAsyncStarted() returns false) +request.partCleanup.failed=Unable to delete temporary file for uploaded part after multi-part processing failed request.session.failed=Failed to load session [{0}] due to [{1}] requestFacade.nullRequest=The request object has been recycled and is no longer associated with this facade
java/org/apache/catalina/connector/Request.java+20 −1 modified@@ -2670,8 +2670,9 @@ private void parseParts(boolean explicit) { upload.setFileCountMax(partLimit); parts = new ArrayList<>(); + List<FileItem> items = null; try { - List<FileItem> items = upload.parseRequest(new ServletRequestContext(this)); + items = upload.parseRequest(new ServletRequestContext(this)); int maxPostSize = getConnector().getMaxPostSize(); long postSize = 0; Charset charset = getCharset(); @@ -2724,6 +2725,24 @@ private void parseParts(boolean explicit) { // addParameters() will set parseFailedReason checkSwallowInput(); partsParseException = e; + } finally { + /* + * GC will delete any temporary copies of uploaded files left in the work directory but if we know that the + * upload has failed then explicitly clean up now. + */ + if (!success) { + parts.clear(); + if (items != null) { + for (FileItem item : items) { + try { + item.delete(); + } catch (Throwable t) { + ExceptionUtils.handleThrowable(t); + log.warn(sm.getString("request.partCleanup.failed"), t); + } + } + } + } } } finally { // This might look odd but is correct. setParseFailedReason() only
webapps/docs/changelog.xml+4 −0 modified@@ -125,6 +125,10 @@ <fix> Fix a case-sensitivity issue in the trailer header allow list. (markt) </fix> + <fix> + Be proactive in cleaning up temporary files after a failed multi-part + upload rather than waiting for GC to do it. (markt) + </fix> </changelog> </subsection> <subsection name="Coyote">
1cdf5f730edeExplicitly clean up after failed multi-part upload
3 files changed · +27 −1
java/org/apache/catalina/connector/LocalStrings.properties+1 −0 modified@@ -95,6 +95,7 @@ request.asyncNotSupported=A filter or servlet of the current chain does not supp request.fragmentInDispatchPath=The fragment in dispatch path [{0}] has been removed request.illegalWrap=The request wrapper must wrap the request obtained from getRequest() request.notAsync=It is illegal to call this method if the current request is not in asynchronous mode (i.e. isAsyncStarted() returns false) +request.partCleanup.failed=Unable to delete temporary file for uploaded part after multi-part processing failed request.session.failed=Failed to load session [{0}] due to [{1}] requestFacade.nullRequest=The request object has been recycled and is no longer associated with this facade
java/org/apache/catalina/connector/Request.java+22 −1 modified@@ -2570,8 +2570,10 @@ private void parseParts(boolean explicit) { upload.setFileCountMax(partLimit); parts = new ArrayList<>(); + List<FileItem> items = null; + boolean success = false; try { - List<FileItem> items = upload.parseRequest(new ServletRequestContext(this)); + items = upload.parseRequest(new ServletRequestContext(this)); int maxPostSize = getConnector().getMaxPostSize(); long postSize = 0; Charset charset = getCharset(); @@ -2607,6 +2609,7 @@ private void parseParts(boolean explicit) { } parts.add(part); } + success = true; } catch (InvalidContentTypeException e) { partsParseException = new ServletException(e); } catch (SizeException | FileCountLimitExceededException e) { @@ -2617,6 +2620,24 @@ private void parseParts(boolean explicit) { } catch (IllegalStateException e) { checkSwallowInput(); partsParseException = e; + } finally { + /* + * GC will delete any temporary copies of uploaded files left in the work directory but if we know that the + * upload has failed then explicitly clean up now. + */ + if (!success) { + parts.clear(); + if (items != null) { + for (FileItem item : items) { + try { + item.delete(); + } catch (Throwable t) { + ExceptionUtils.handleThrowable(t); + log.warn(sm.getString("request.partCleanup.failed"), t); + } + } + } + } } }
webapps/docs/changelog.xml+4 −0 modified@@ -131,6 +131,10 @@ <fix> Fix a case-sensitivity issue in the trailer header allow list. (markt) </fix> + <fix> + Be proactive in cleaning up temporary files after a failed multi-part + upload rather than waiting for GC to do it. (markt) + </fix> </changelog> </subsection> <subsection name="Coyote">
afa422bd7ca1Explicitly clean up after failed multi-part upload
3 files changed · +25 −1
java/org/apache/catalina/connector/LocalStrings.properties+1 −0 modified@@ -94,6 +94,7 @@ request.asyncNotSupported=A filter or servlet of the current chain does not supp request.fragmentInDispatchPath=The fragment in dispatch path [{0}] has been removed request.illegalWrap=The request wrapper must wrap the request obtained from getRequest() request.notAsync=It is illegal to call this method if the current request is not in asynchronous mode (i.e. isAsyncStarted() returns false) +request.partCleanup.failed=Unable to delete temporary file for uploaded part after multi-part processing failed request.session.failed=Failed to load session [{0}] due to [{1}] requestFacade.nullRequest=The request object has been recycled and is no longer associated with this facade
java/org/apache/catalina/connector/Request.java+20 −1 modified@@ -2711,8 +2711,9 @@ private void parseParts(boolean explicit) { upload.setFileCountMax(partLimit); parts = new ArrayList<>(); + List<FileItem> items = null; try { - List<FileItem> items = upload.parseRequest(new ServletRequestContext(this)); + items = upload.parseRequest(new ServletRequestContext(this)); int maxPostSize = getConnector().getMaxPostSize(); long postSize = 0; Charset charset = getCharset(); @@ -2765,6 +2766,24 @@ private void parseParts(boolean explicit) { // addParameters() will set parseFailedReason checkSwallowInput(); partsParseException = e; + } finally { + /* + * GC will delete any temporary copies of uploaded files left in the work directory but if we know that the + * upload has failed then explicitly clean up now. + */ + if (!success) { + parts.clear(); + if (items != null) { + for (FileItem item : items) { + try { + item.delete(); + } catch (Throwable t) { + ExceptionUtils.handleThrowable(t); + log.warn(sm.getString("request.partCleanup.failed"), t); + } + } + } + } } } finally { // This might look odd but is correct. setParseFailedReason() only
webapps/docs/changelog.xml+4 −0 modified@@ -131,6 +131,10 @@ <fix> Fix a case-sensitivity issue in the trailer header allow list. (markt) </fix> + <fix> + Be proactive in cleaning up temporary files after a failed multi-part + upload rather than waiting for GC to do it. (markt) + </fix> </changelog> </subsection> <subsection name="Coyote">
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
11- www.openwall.com/lists/oss-security/2025/10/27/6nvdMailing ListThird Party Advisory
- github.com/advisories/GHSA-hgrr-935x-pq79ghsaADVISORY
- lists.apache.org/thread/wm9mx8brmx9g4zpywm06ryrtvd3160ppnvdMailing ListVendor Advisory
- cert-portal.siemens.com/productcert/html/ssa-032379.htmlnvd
- github.com/apache/tomcat/commit/1cdf5f730ede75a0759492f179ac21ca4ff68e06ghsa
- github.com/apache/tomcat/commit/af6e9181620304c0d818121c29c074e1330610d0ghsa
- github.com/apache/tomcat/commit/afa422bd7ca1eef0f507259c682fd876494d9c3bghsa
- nvd.nist.gov/vuln/detail/CVE-2025-61795ghsa
- tomcat.apache.org/security-10.htmlghsa
- tomcat.apache.org/security-11.htmlghsa
- tomcat.apache.org/security-9.htmlghsa
News mentions
1- Siemens SIMATICCISA Alerts