Apache Commons FileUpload, Apache Tomcat: FileUpload DoS with excessive parts
Description
Apache Commons FileUpload before 1.5 does not limit the number of request parts to be processed resulting in the possibility of an attacker triggering a DoS with a malicious upload or series of uploads.
Note that, like all of the file upload limits, the new configuration option (FileUploadBase#setFileCountMax) is not enabled by default and must be explicitly configured.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Apache Commons FileUpload before 1.5 lacks a limit on the number of request parts, allowing an unauthenticated attacker to cause a denial-of-service via a malicious multi-part upload.
Vulnerability
Description
Apache Commons FileUpload versions prior to 1.5 do not enforce a maximum on the number of parts a multi-part request can contain. This oversight means an attacker can craft a request with an extremely large number of parts, consuming server resources during parsing and potentially leading to a denial-of-service (DoS) condition. The issue is tracked as CVE-2023-24998 and is documented in the Apache Tomcat security advisories [1][2][3][4].
Exploitation
Prerequisites
Exploitation requires the ability to send a crafted HTTP multi-part request to a server that uses Commons FileUpload to parse file uploads. No authentication is required; the attack can be performed over the network. The vulnerability is present in the default configuration of Commons FileUpload versions before 1.5, as the limit on file count (FileUploadBase#setFileCountMax) is not enabled by default and must be explicitly configured by the application [1][2][3][4].
Impact
A successful attack causes excessive CPU and memory consumption during the parsing of the multi-part request. This exhausts server resources, making the application unresponsive to legitimate requests. The impact is a denial-of-service of the affected service [1][2][3][4].
Mitigation
The vulnerability is fixed in Apache Commons FileUpload 1.5. Users should upgrade to this version or later. Additionally, administrators are advised to explicitly configure the fileCountMax property to a reasonable value to mitigate the risk. Apache Tomcat versions 9.0.x, 8.5.x, 10.1.x, and 11.0.x that incorporate the fixed Commons FileUpload version are also patched [1][2][3][4].
AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
commons-fileupload:commons-fileuploadMaven | < 1.5 | 1.5 |
org.apache.tomcat:tomcat-coyoteMaven | >= 10.1.0-M1, < 10.1.5 | 10.1.5 |
org.apache.tomcat:tomcat-coyoteMaven | >= 11.0.0-M2, < 11.0.0-M5 | 11.0.0-M5 |
org.apache.tomcat:tomcat-coyoteMaven | >= 8.5.85, < 8.5.88 | 8.5.88 |
org.apache.tomcat:tomcat-coyoteMaven | >= 9.0.0-M1, < 9.0.71 | 9.0.71 |
org.apache.tomcat.embed:tomcat-embed-coreMaven | >= 10.1.0-M1, < 10.1.5 | 10.1.5 |
org.apache.tomcat.embed:tomcat-embed-coreMaven | >= 11.0.0-M2, < 11.0.0-M5 | 11.0.0-M5 |
org.apache.tomcat.embed:tomcat-embed-coreMaven | >= 8.5.85, < 8.5.88 | 8.5.88 |
org.apache.tomcat.embed:tomcat-embed-coreMaven | >= 9.0.0-M1, < 9.0.71 | 9.0.71 |
Affected products
75- osv-coords73 versionspkg:apk/chainguard/jenkinspkg:apk/chainguard/jenkins-compatpkg:apk/chainguard/jenkins-remotingpkg:apk/wolfi/jenkinspkg:apk/wolfi/jenkins-compatpkg:apk/wolfi/jenkins-remotingpkg:maven/commons-fileupload/commons-fileuploadpkg:maven/org.apache.tomcat.embed/tomcat-embed-corepkg:maven/org.apache.tomcat/tomcat-coyotepkg:rpm/almalinux/tomcatpkg:rpm/almalinux/tomcat-admin-webappspkg:rpm/almalinux/tomcat-docs-webapppkg:rpm/almalinux/tomcat-el-3.0-apipkg:rpm/almalinux/tomcat-jsp-2.3-apipkg:rpm/almalinux/tomcat-libpkg:rpm/almalinux/tomcat-servlet-4.0-apipkg:rpm/almalinux/tomcat-webappspkg:rpm/opensuse/apache-commons-fileupload&distro=openSUSE%20Leap%2015.4pkg:rpm/opensuse/apache-commons-fileupload&distro=openSUSE%20Leap%2015.5pkg:rpm/opensuse/apache-commons-fileupload&distro=openSUSE%20Tumbleweedpkg:rpm/opensuse/jakarta-commons-fileupload&distro=openSUSE%20Leap%2015.4pkg:rpm/opensuse/tomcat10&distro=openSUSE%20Tumbleweedpkg:rpm/opensuse/tomcat&distro=openSUSE%20Leap%2015.4pkg:rpm/opensuse/tomcat&distro=openSUSE%20Leap%2015.5pkg:rpm/opensuse/tomcat&distro=openSUSE%20Tumbleweedpkg:rpm/suse/apache-commons-fileupload&distro=SUSE%20Enterprise%20Storage%207pkg:rpm/suse/apache-commons-fileupload&distro=SUSE%20Enterprise%20Storage%207.1pkg:rpm/suse/apache-commons-fileupload&distro=SUSE%20Linux%20Enterprise%20High%20Performance%20Computing%2015%20SP2-LTSSpkg:rpm/suse/apache-commons-fileupload&distro=SUSE%20Linux%20Enterprise%20High%20Performance%20Computing%2015%20SP3-ESPOSpkg:rpm/suse/apache-commons-fileupload&distro=SUSE%20Linux%20Enterprise%20High%20Performance%20Computing%2015%20SP3-LTSSpkg:rpm/suse/apache-commons-fileupload&distro=SUSE%20Linux%20Enterprise%20Module%20for%20Web%20and%20Scripting%2015%20SP4pkg:rpm/suse/apache-commons-fileupload&distro=SUSE%20Linux%20Enterprise%20Module%20for%20Web%20and%20Scripting%2015%20SP5pkg:rpm/suse/apache-commons-fileupload&distro=SUSE%20Linux%20Enterprise%20Server%2015%20SP2-LTSSpkg:rpm/suse/apache-commons-fileupload&distro=SUSE%20Linux%20Enterprise%20Server%2015%20SP3-LTSSpkg:rpm/suse/apache-commons-fileupload&distro=SUSE%20Linux%20Enterprise%20Server%20for%20SAP%20Applications%2015%20SP2pkg:rpm/suse/apache-commons-fileupload&distro=SUSE%20Linux%20Enterprise%20Server%20for%20SAP%20Applications%2015%20SP3pkg:rpm/suse/apache-commons-fileupload&distro=SUSE%20Manager%20Server%204.2pkg:rpm/suse/jakarta-commons-fileupload&distro=SUSE%20Linux%20Enterprise%20High%20Performance%20Computing%2015%20SP1-LTSSpkg:rpm/suse/jakarta-commons-fileupload&distro=SUSE%20Linux%20Enterprise%20Server%2012%20SP2-BCLpkg:rpm/suse/jakarta-commons-fileupload&distro=SUSE%20Linux%20Enterprise%20Server%2012%20SP4-ESPOSpkg:rpm/suse/jakarta-commons-fileupload&distro=SUSE%20Linux%20Enterprise%20Server%2012%20SP4-LTSSpkg:rpm/suse/jakarta-commons-fileupload&distro=SUSE%20Linux%20Enterprise%20Server%2012%20SP5pkg:rpm/suse/jakarta-commons-fileupload&distro=SUSE%20Linux%20Enterprise%20Server%2015%20SP1-LTSSpkg:rpm/suse/jakarta-commons-fileupload&distro=SUSE%20Linux%20Enterprise%20Server%20for%20SAP%20Applications%2012%20SP4pkg:rpm/suse/jakarta-commons-fileupload&distro=SUSE%20Linux%20Enterprise%20Server%20for%20SAP%20Applications%2012%20SP5pkg:rpm/suse/jakarta-commons-fileupload&distro=SUSE%20Linux%20Enterprise%20Server%20for%20SAP%20Applications%2015%20SP1pkg:rpm/suse/jakarta-commons-fileupload&distro=SUSE%20OpenStack%20Cloud%209pkg:rpm/suse/jakarta-commons-fileupload&distro=SUSE%20OpenStack%20Cloud%20Crowbar%209pkg:rpm/suse/tomcat&distro=SUSE%20Enterprise%20Storage%207pkg:rpm/suse/tomcat&distro=SUSE%20Enterprise%20Storage%207.1pkg:rpm/suse/tomcat&distro=SUSE%20Linux%20Enterprise%20High%20Performance%20Computing%2015%20SP1-LTSSpkg:rpm/suse/tomcat&distro=SUSE%20Linux%20Enterprise%20High%20Performance%20Computing%2015%20SP2-LTSSpkg:rpm/suse/tomcat&distro=SUSE%20Linux%20Enterprise%20High%20Performance%20Computing%2015%20SP3-ESPOSpkg:rpm/suse/tomcat&distro=SUSE%20Linux%20Enterprise%20High%20Performance%20Computing%2015%20SP3-LTSSpkg:rpm/suse/tomcat&distro=SUSE%20Linux%20Enterprise%20Module%20for%20Web%20and%20Scripting%2015%20SP4pkg:rpm/suse/tomcat&distro=SUSE%20Linux%20Enterprise%20Module%20for%20Web%20and%20Scripting%2015%20SP5pkg:rpm/suse/tomcat&distro=SUSE%20Linux%20Enterprise%20Server%2012%20SP2-BCLpkg:rpm/suse/tomcat&distro=SUSE%20Linux%20Enterprise%20Server%2012%20SP4-ESPOSpkg:rpm/suse/tomcat&distro=SUSE%20Linux%20Enterprise%20Server%2012%20SP4-LTSSpkg:rpm/suse/tomcat&distro=SUSE%20Linux%20Enterprise%20Server%2012%20SP5pkg:rpm/suse/tomcat&distro=SUSE%20Linux%20Enterprise%20Server%2012%20SP5-LTSSpkg:rpm/suse/tomcat&distro=SUSE%20Linux%20Enterprise%20Server%2015%20SP1-LTSSpkg:rpm/suse/tomcat&distro=SUSE%20Linux%20Enterprise%20Server%2015%20SP2-LTSSpkg:rpm/suse/tomcat&distro=SUSE%20Linux%20Enterprise%20Server%2015%20SP3-LTSSpkg:rpm/suse/tomcat&distro=SUSE%20Linux%20Enterprise%20Server%20for%20SAP%20Applications%2012%20SP4pkg:rpm/suse/tomcat&distro=SUSE%20Linux%20Enterprise%20Server%20for%20SAP%20Applications%2012%20SP5pkg:rpm/suse/tomcat&distro=SUSE%20Linux%20Enterprise%20Server%20for%20SAP%20Applications%2015%20SP1pkg:rpm/suse/tomcat&distro=SUSE%20Linux%20Enterprise%20Server%20for%20SAP%20Applications%2015%20SP2pkg:rpm/suse/tomcat&distro=SUSE%20Linux%20Enterprise%20Server%20for%20SAP%20Applications%2015%20SP3pkg:rpm/suse/tomcat&distro=SUSE%20Linux%20Enterprise%20Server%20LTSS%20Extended%20Security%2012%20SP5pkg:rpm/suse/tomcat&distro=SUSE%20Manager%20Server%204.2pkg:rpm/suse/tomcat&distro=SUSE%20OpenStack%20Cloud%209pkg:rpm/suse/tomcat&distro=SUSE%20OpenStack%20Cloud%20Crowbar%209
< 2.395-r0+ 72 more
- (no CPE)range: < 2.395-r0
- (no CPE)range: < 2.395-r0
- (no CPE)range: < 2.395-r0
- (no CPE)range: < 2.395-r0
- (no CPE)range: < 2.395-r0
- (no CPE)range: < 2.395-r0
- (no CPE)range: < 1.5
- (no CPE)range: >= 10.1.0-M1, < 10.1.5
- (no CPE)range: >= 10.1.0-M1, < 10.1.5
- (no CPE)range: < 1:9.0.62-37.el9_3
- (no CPE)range: < 1:9.0.62-37.el9_3
- (no CPE)range: < 1:9.0.62-37.el9_3
- (no CPE)range: < 1:9.0.62-37.el9_3
- (no CPE)range: < 1:9.0.62-37.el9_3
- (no CPE)range: < 1:9.0.62-37.el9_3
- (no CPE)range: < 1:9.0.62-37.el9_3
- (no CPE)range: < 1:9.0.62-37.el9_3
- (no CPE)range: < 1.5-150200.3.9.1
- (no CPE)range: < 1.5-150200.3.9.1
- (no CPE)range: < 1.5-1.1
- (no CPE)range: < 1.1.1-150000.4.8.1
- (no CPE)range: < 10.1.14-1.1
- (no CPE)range: < 9.0.43-150200.35.1
- (no CPE)range: < 9.0.75-150200.41.1
- (no CPE)range: < 9.0.43-14.1
- (no CPE)range: < 1.5-150200.3.9.1
- (no CPE)range: < 1.5-150200.3.9.1
- (no CPE)range: < 1.5-150200.3.9.1
- (no CPE)range: < 1.5-150200.3.9.1
- (no CPE)range: < 1.5-150200.3.9.1
- (no CPE)range: < 1.5-150200.3.9.1
- (no CPE)range: < 1.5-150200.3.9.1
- (no CPE)range: < 1.5-150200.3.9.1
- (no CPE)range: < 1.5-150200.3.9.1
- (no CPE)range: < 1.5-150200.3.9.1
- (no CPE)range: < 1.5-150200.3.9.1
- (no CPE)range: < 1.5-150200.3.9.1
- (no CPE)range: < 1.1.1-150000.4.8.1
- (no CPE)range: < 1.1.1-122.8.1
- (no CPE)range: < 1.1.1-122.8.1
- (no CPE)range: < 1.1.1-122.8.1
- (no CPE)range: < 1.1.1-122.8.1
- (no CPE)range: < 1.1.1-150000.4.8.1
- (no CPE)range: < 1.1.1-122.8.1
- (no CPE)range: < 1.1.1-122.8.1
- (no CPE)range: < 1.1.1-150000.4.8.1
- (no CPE)range: < 1.1.1-122.8.1
- (no CPE)range: < 1.1.1-122.8.1
- (no CPE)range: < 9.0.43-150200.35.1
- (no CPE)range: < 9.0.43-150200.35.1
- (no CPE)range: < 9.0.36-150100.4.87.1
- (no CPE)range: < 9.0.43-150200.35.1
- (no CPE)range: < 9.0.43-150200.35.1
- (no CPE)range: < 9.0.43-150200.35.1
- (no CPE)range: < 9.0.43-150200.35.1
- (no CPE)range: < 9.0.75-150200.41.1
- (no CPE)range: < 8.0.53-29.63.1
- (no CPE)range: < 9.0.36-3.99.1
- (no CPE)range: < 9.0.36-3.99.1
- (no CPE)range: < 9.0.36-3.99.1
- (no CPE)range: < 9.0.115-3.160.1
- (no CPE)range: < 9.0.36-150100.4.87.1
- (no CPE)range: < 9.0.43-150200.35.1
- (no CPE)range: < 9.0.43-150200.35.1
- (no CPE)range: < 9.0.36-3.99.1
- (no CPE)range: < 9.0.36-3.99.1
- (no CPE)range: < 9.0.36-150100.4.87.1
- (no CPE)range: < 9.0.43-150200.35.1
- (no CPE)range: < 9.0.43-150200.35.1
- (no CPE)range: < 9.0.115-3.160.1
- (no CPE)range: < 9.0.43-150200.35.1
- (no CPE)range: < 9.0.36-3.99.1
- (no CPE)range: < 9.0.36-3.99.1
- Apache Software Foundation/Apache Commons FileUploadv5Range: 0
- Apache Software Foundation/Apache Tomcatv5Range: 11.0.0-M1
Patches
5d53d8e7f7704Fix parameter counting logic
1 file changed · +2 −2
java/org/apache/tomcat/util/http/Parameters.java+2 −2 modified@@ -201,13 +201,13 @@ public void addParameter(String key, String value) throws IllegalStateException return; } - parameterCount++; - if (limit > -1 && parameterCount > limit) { + if (limit > -1 && parameterCount >= limit) { // Processing this parameter will push us over the limit. ISE is // what Request.parseParts() uses for requests that are too big setParseFailedReason(FailReason.TOO_MANY_PARAMETERS); throw new IllegalStateException(sm.getString("parameters.maxCountFail", Integer.valueOf(limit))); } + parameterCount++; paramHashValues.computeIfAbsent(key, k -> new ArrayList<>(1)).add(value); }
e20c04990f74Add a new limit for the number of files uploaded per request (#185)
3 files changed · +82 −1
src/changes/changes.xml+1 −0 modified@@ -45,6 +45,7 @@ The <action> type attribute can be add,update,fix,remove. <body> <release version="1.5" date="TBD" description="1.5 Release"> <action issue="FILEUPLOAD-293" dev="jochen" type="fix">DiskFileItem.write(File) had been changed to use FileUtils.moveFile internally, preventing an existing file as the target.</action> + <action dev="markt" type="add">Add a configurable limit (disabled by default) for the number of files to upload per request.</action> </release> <release version="1.4" date="2018-12-23" description="1.4 Release"> <action issue="FILEUPLOAD-292" dev="chtompki" type="update">Don't create un-needed resources in FileUploadBase.java</action>
src/main/java/org/apache/commons/fileupload/FileCountLimitExceededException.java+51 −0 added@@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.fileupload; + +/** + * This exception is thrown if a request contains more files than the specified + * limit. + */ +public class FileCountLimitExceededException extends FileUploadException { + + private static final long serialVersionUID = 6904179610227521789L; + + /** + * The limit that was exceeded. + */ + private final long limit; + + /** + * Creates a new instance. + * + * @param message The detail message + * @param limit The limit that was exceeded + */ + public FileCountLimitExceededException(final String message, final long limit) { + super(message); + this.limit = limit; + } + + /** + * Retrieves the limit that was exceeded. + * + * @return The limit that was exceeded by the request + */ + public long getLimit() { + return limit; + } +}
src/main/java/org/apache/commons/fileupload/FileUploadBase.java+30 −1 modified@@ -165,6 +165,12 @@ public static boolean isMultipartContent(HttpServletRequest req) { */ private long fileSizeMax = -1; + /** + * The maximum permitted number of files that may be uploaded in a single + * request. A value of -1 indicates no maximum. + */ + private long fileCountMax = -1; + /** * The content encoding to use when reading part headers. */ @@ -241,6 +247,25 @@ public void setFileSizeMax(long fileSizeMax) { this.fileSizeMax = fileSizeMax; } + /** + * Returns the maximum number of files allowed in a single request. + * + * @return The maximum number of files allowed in a single request. + */ + public long getFileCountMax() { + return fileCountMax; + } + + /** + * Sets the maximum number of files allowed per request. + * + * @param fileCountMax The new limit. {@code -1} means no limit. + */ + public void setFileCountMax(final long fileCountMax) { + this.fileCountMax = fileCountMax; + } + + /** * Retrieves the character encoding used when reading the headers of an * individual part. When not specified, or <code>null</code>, the request @@ -337,7 +362,11 @@ public List<FileItem> parseRequest(RequestContext ctx) throw new NullPointerException("No FileItemFactory has been set."); } while (iter.hasNext()) { - final FileItemStream item = iter.next(); + if (items.size() == fileCountMax) { + // The next item will exceed the limit. + throw new FileCountLimitExceededException(ATTACHMENT, getFileCountMax()); + } + final FileItemStream item = iter.next(); // Don't use getName() here to prevent an InvalidFileNameException. final String fileName = ((FileItemIteratorImpl.FileItemStreamImpl) item).name; FileItem fileItem = fac.createItem(item.getFieldName(), item.getContentType(),
8a2285f13affUpdate packaged renamed fork of Commons File Upload
8 files changed · +116 −14
java/org/apache/catalina/connector/Request.java+9 −1 modified@@ -2816,8 +2816,9 @@ private void parseParts(boolean explicit) { } } + int maxParameterCount = getConnector().getMaxParameterCount(); Parameters parameters = coyoteRequest.getParameters(); - parameters.setLimit(getConnector().getMaxParameterCount()); + parameters.setLimit(maxParameterCount); boolean success = false; try { @@ -2869,6 +2870,13 @@ private void parseParts(boolean explicit) { upload.setFileItemFactory(factory); upload.setFileSizeMax(mce.getMaxFileSize()); upload.setSizeMax(mce.getMaxRequestSize()); + if (maxParameterCount > -1) { + // There is a limit. The limit for parts needs to be reduced by + // the number of parameters we have already parsed. + // Must be under the limit else parsing parameters would have + // triggered an exception. + upload.setFileCountMax(maxParameterCount - parameters.size()); + } parts = new ArrayList<>(); try {
java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java+29 −0 modified@@ -24,6 +24,7 @@ import java.util.Map; import java.util.Objects; +import org.apache.tomcat.util.http.fileupload.impl.FileCountLimitExceededException; import org.apache.tomcat.util.http.fileupload.impl.FileItemIteratorImpl; import org.apache.tomcat.util.http.fileupload.impl.FileUploadIOException; import org.apache.tomcat.util.http.fileupload.impl.IOFileUploadException; @@ -103,6 +104,12 @@ public abstract class FileUploadBase { */ private long fileSizeMax = -1; + /** + * The maximum permitted number of files that may be uploaded in a single + * request. A value of -1 indicates no maximum. + */ + private long fileCountMax = -1; + /** * The content encoding to use when reading part headers. */ @@ -179,6 +186,24 @@ public void setFileSizeMax(final long fileSizeMax) { this.fileSizeMax = fileSizeMax; } + /** + * Returns the maximum number of files allowed in a single request. + * + * @return The maximum number of files allowed in a single request. + */ + public long getFileCountMax() { + return fileCountMax; + } + + /** + * Sets the maximum number of files allowed per request/ + * + * @param fileCountMax The new limit. {@code -1} means no limit. + */ + public void setFileCountMax(long fileCountMax) { + this.fileCountMax = fileCountMax; + } + /** * Retrieves the character encoding used when reading the headers of an * individual part. When not specified, or {@code null}, the request @@ -253,6 +278,10 @@ public List<FileItem> parseRequest(final RequestContext ctx) "No FileItemFactory has been set."); final byte[] buffer = new byte[Streams.DEFAULT_BUFFER_SIZE]; while (iter.hasNext()) { + if (items.size() == fileCountMax) { + // The next item will exceed the limit. + throw new FileCountLimitExceededException(ATTACHMENT, getFileCountMax()); + } final FileItemStream item = iter.next(); // Don't use getName() here to prevent an InvalidFileNameException. final String fileName = item.getName();
java/org/apache/tomcat/util/http/fileupload/impl/FileCountLimitExceededException.java+50 −0 added@@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tomcat.util.http.fileupload.impl; + +import org.apache.tomcat.util.http.fileupload.FileUploadException; + +/** + * This exception is thrown if a request contains more files than the specified + * limit. + */ +public class FileCountLimitExceededException extends FileUploadException { + + private static final long serialVersionUID = 2408766352570556046L; + + private final long limit; + + /** + * Creates a new instance. + * + * @param message The detail message + * @param limit The limit that was exceeded + */ + public FileCountLimitExceededException(final String message, final long limit) { + super(message); + this.limit = limit; + } + + /** + * Retrieves the limit that was exceeded. + * + * @return The limit that was exceeded by the request + */ + public long getLimit() { + return limit; + } +}
java/org/apache/tomcat/util/http/Parameters.java+5 −0 modified@@ -125,6 +125,11 @@ public void setParseFailedReason(FailReason failReason) { } + public int size() { + return parameterCount; + } + + public void recycle() { parameterCount = 0; paramHashValues.clear();
MERGE.txt+1 −1 modified@@ -54,7 +54,7 @@ Unused code is removed Sub-tree: src/main/java/org/apache/commons/fileupload2 The SHA1 ID / tag for the most recent commit to be merged to Tomcat is: -aa8eff6f04c939fd99834360415b1ddb2f637cb1 (2022-11-29) +34eb241c051b02eca3b0b1b04f67b3b4e6c3a24d (2023-02-03) Note: Tomcat's copy of fileupload also includes classes copied manually from Commons IO.
webapps/docs/changelog.xml+4 −0 modified@@ -146,6 +146,10 @@ Update the packaged version of the Apache Tomcat Migration Tool for Jakarta EE to 1.0.6. (markt) </update> + <update> + Update the internal fork of Apache Commons FileUpload to 34eb241 + (2023-01-03, 2.0-SNAPSHOT). (markt) + </update> </changelog> </subsection> </section>
webapps/docs/config/ajp.xml+9 −6 modified@@ -149,12 +149,15 @@ </attribute> <attribute name="maxParameterCount" required="false"> - <p>The maximum number of parameter and value pairs (GET plus POST) which - will be automatically parsed by the container. Parameter and value pairs - beyond this limit will be ignored. A value of less than 0 means no limit. - If not specified, a default of 10000 is used. Note that - <code>FailedRequestFilter</code> <a href="filter.html">filter</a> can be - used to reject requests that hit the limit.</p> + <p>The maximum total number of request parameters (including uploaded + files) obtained from the query string and, for POST requests, the request + body if the content type is + <code>application/x-www-form-urlencoded</code> or + <code>multipart/form-data</code>. Request parameters beyond this limit + will be ignored. A value of less than 0 means no limit. If not specified, + a default of 10000 is used. Note that <code>FailedRequestFilter</code> + <a href="filter.html">filter</a> can be used to reject requests that + exceed the limit.</p> </attribute> <attribute name="maxPostSize" required="false">
webapps/docs/config/http.xml+9 −6 modified@@ -145,12 +145,15 @@ </attribute> <attribute name="maxParameterCount" required="false"> - <p>The maximum number of parameter and value pairs (GET plus POST) which - will be automatically parsed by the container. Parameter and value pairs - beyond this limit will be ignored. A value of less than 0 means no limit. - If not specified, a default of 10000 is used. Note that - <code>FailedRequestFilter</code> <a href="filter.html">filter</a> can be - used to reject requests that hit the limit.</p> + <p>The maximum total number of request parameters (including uploaded + files) obtained from the query string and, for POST requests, the request + body if the content type is + <code>application/x-www-form-urlencoded</code> or + <code>multipart/form-data</code>. Request parameters beyond this limit + will be ignored. A value of less than 0 means no limit. If not specified, + a default of 10000 is used. Note that <code>FailedRequestFilter</code> + <a href="filter.html">filter</a> can be used to reject requests that + exceed the limit.</p> </attribute> <attribute name="maxPostSize" required="false">
9ca96c8c1ebaUpdate packaged renamed fork of Commons File Upload
8 files changed · +116 −18
java/org/apache/catalina/connector/Request.java+9 −1 modified@@ -2911,8 +2911,9 @@ private void parseParts(boolean explicit) { } } + int maxParameterCount = getConnector().getMaxParameterCount(); Parameters parameters = coyoteRequest.getParameters(); - parameters.setLimit(getConnector().getMaxParameterCount()); + parameters.setLimit(maxParameterCount); boolean success = false; try { @@ -2964,6 +2965,13 @@ private void parseParts(boolean explicit) { upload.setFileItemFactory(factory); upload.setFileSizeMax(mce.getMaxFileSize()); upload.setSizeMax(mce.getMaxRequestSize()); + if (maxParameterCount > -1) { + // There is a limit. The limit for parts needs to be reduced by + // the number of parameters we have already parsed. + // Must be under the limit else parsing parameters would have + // triggered an exception. + upload.setFileCountMax(maxParameterCount - parameters.size()); + } parts = new ArrayList<>(); try {
java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java+29 −0 modified@@ -25,6 +25,7 @@ import java.util.Map; import java.util.Objects; +import org.apache.tomcat.util.http.fileupload.impl.FileCountLimitExceededException; import org.apache.tomcat.util.http.fileupload.impl.FileItemIteratorImpl; import org.apache.tomcat.util.http.fileupload.impl.FileUploadIOException; import org.apache.tomcat.util.http.fileupload.impl.IOFileUploadException; @@ -128,6 +129,12 @@ public static final boolean isMultipartContent(final RequestContext ctx) { */ private long fileSizeMax = -1; + /** + * The maximum permitted number of files that may be uploaded in a single + * request. A value of -1 indicates no maximum. + */ + private long fileCountMax = -1; + /** * The content encoding to use when reading part headers. */ @@ -204,6 +211,24 @@ public void setFileSizeMax(final long fileSizeMax) { this.fileSizeMax = fileSizeMax; } + /** + * Returns the maximum number of files allowed in a single request. + * + * @return The maximum number of files allowed in a single request. + */ + public long getFileCountMax() { + return fileCountMax; + } + + /** + * Sets the maximum number of files allowed per request/ + * + * @param fileCountMax The new limit. {@code -1} means no limit. + */ + public void setFileCountMax(long fileCountMax) { + this.fileCountMax = fileCountMax; + } + /** * Retrieves the character encoding used when reading the headers of an * individual part. When not specified, or {@code null}, the request @@ -278,6 +303,10 @@ public List<FileItem> parseRequest(final RequestContext ctx) "No FileItemFactory has been set."); final byte[] buffer = new byte[Streams.DEFAULT_BUFFER_SIZE]; while (iter.hasNext()) { + if (items.size() == fileCountMax) { + // The next item will exceed the limit. + throw new FileCountLimitExceededException(ATTACHMENT, getFileCountMax()); + } final FileItemStream item = iter.next(); // Don't use getName() here to prevent an InvalidFileNameException. final String fileName = item.getName();
java/org/apache/tomcat/util/http/fileupload/impl/FileCountLimitExceededException.java+50 −0 added@@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tomcat.util.http.fileupload.impl; + +import org.apache.tomcat.util.http.fileupload.FileUploadException; + +/** + * This exception is thrown if a request contains more files than the specified + * limit. + */ +public class FileCountLimitExceededException extends FileUploadException { + + private static final long serialVersionUID = 2408766352570556046L; + + private final long limit; + + /** + * Creates a new instance. + * + * @param message The detail message + * @param limit The limit that was exceeded + */ + public FileCountLimitExceededException(final String message, final long limit) { + super(message); + this.limit = limit; + } + + /** + * Retrieves the limit that was exceeded. + * + * @return The limit that was exceeded by the request + */ + public long getLimit() { + return limit; + } +}
java/org/apache/tomcat/util/http/Parameters.java+5 −0 modified@@ -157,6 +157,11 @@ public void setParseFailedReason(FailReason failReason) { } + public int size() { + return parameterCount; + } + + public void recycle() { parameterCount = 0; paramHashValues.clear();
MERGE.txt+1 −1 modified@@ -51,7 +51,7 @@ FileUpload Sub-tree: src/main/java/org/apache/commons/fileupload2 The SHA1 ID / tag for the most recent commit to be merged to Tomcat is: -aa8eff6f04c939fd99834360415b1ddb2f637cb1 (2022-11-29) +34eb241c051b02eca3b0b1b04f67b3b4e6c3a24d (2023-01-03) Note: Tomcat's copy of fileupload also includes classes copied manually from Commons IO.
webapps/docs/changelog.xml+4 −4 modified@@ -180,14 +180,14 @@ <update> Update to Commons Daemon 1.3.3. (markt) </update> - <update> - Update the internal fork of Apache Commons FileUpload to aa8eff6 - (2022-11-29, 2.0-SNAPSHOT). (markt) - </update> <add> Improvements to Japanese translations. Contributed by Shirayuking and tak7iji. (markt) </add> + <update> + Update the internal fork of Apache Commons FileUpload to 34eb241 + (2023-01-03, 2.0-SNAPSHOT). (markt) + </update> </changelog> </subsection> </section>
webapps/docs/config/ajp.xml+9 −6 modified@@ -132,12 +132,15 @@ </attribute> <attribute name="maxParameterCount" required="false"> - <p>The maximum number of parameter and value pairs (GET plus POST) which - will be automatically parsed by the container. Parameter and value pairs - beyond this limit will be ignored. A value of less than 0 means no limit. - If not specified, a default of 10000 is used. Note that - <code>FailedRequestFilter</code> <a href="filter.html">filter</a> can be - used to reject requests that hit the limit.</p> + <p>The maximum total number of request parameters (including uploaded + files) obtained from the query string and, for POST requests, the request + body if the content type is + <code>application/x-www-form-urlencoded</code> or + <code>multipart/form-data</code>. Request parameters beyond this limit + will be ignored. A value of less than 0 means no limit. If not specified, + a default of 10000 is used. Note that <code>FailedRequestFilter</code> + <a href="filter.html">filter</a> can be used to reject requests that + exceed the limit.</p> </attribute> <attribute name="maxPostSize" required="false">
webapps/docs/config/http.xml+9 −6 modified@@ -130,12 +130,15 @@ </attribute> <attribute name="maxParameterCount" required="false"> - <p>The maximum number of parameter and value pairs (GET plus POST) which - will be automatically parsed by the container. Parameter and value pairs - beyond this limit will be ignored. A value of less than 0 means no limit. - If not specified, a default of 10000 is used. Note that - <code>FailedRequestFilter</code> <a href="filter.html">filter</a> can be - used to reject requests that hit the limit.</p> + <p>The maximum total number of request parameters (including uploaded + files) obtained from the query string and, for POST requests, the request + body if the content type is + <code>application/x-www-form-urlencoded</code> or + <code>multipart/form-data</code>. Request parameters beyond this limit + will be ignored. A value of less than 0 means no limit. If not specified, + a default of 10000 is used. Note that <code>FailedRequestFilter</code> + <a href="filter.html">filter</a> can be used to reject requests that + exceed the limit.</p> </attribute> <attribute name="maxPostSize" required="false">
cf77cc545de0Update packaged renamed fork of Commons File Upload
8 files changed · +120 −14
java/org/apache/catalina/connector/Request.java+9 −1 modified@@ -2872,8 +2872,9 @@ private void parseParts(boolean explicit) { } } + int maxParameterCount = getConnector().getMaxParameterCount(); Parameters parameters = coyoteRequest.getParameters(); - parameters.setLimit(getConnector().getMaxParameterCount()); + parameters.setLimit(maxParameterCount); boolean success = false; try { @@ -2925,6 +2926,13 @@ private void parseParts(boolean explicit) { upload.setFileItemFactory(factory); upload.setFileSizeMax(mce.getMaxFileSize()); upload.setSizeMax(mce.getMaxRequestSize()); + if (maxParameterCount > -1) { + // There is a limit. The limit for parts needs to be reduced by + // the number of parameters we have already parsed. + // Must be under the limit else parsing parameters would have + // triggered an exception. + upload.setFileCountMax(maxParameterCount - parameters.size()); + } parts = new ArrayList<>(); try {
java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java+29 −0 modified@@ -25,6 +25,7 @@ import java.util.Map; import java.util.Objects; +import org.apache.tomcat.util.http.fileupload.impl.FileCountLimitExceededException; import org.apache.tomcat.util.http.fileupload.impl.FileItemIteratorImpl; import org.apache.tomcat.util.http.fileupload.impl.FileUploadIOException; import org.apache.tomcat.util.http.fileupload.impl.IOFileUploadException; @@ -128,6 +129,12 @@ public static final boolean isMultipartContent(final RequestContext ctx) { */ private long fileSizeMax = -1; + /** + * The maximum permitted number of files that may be uploaded in a single + * request. A value of -1 indicates no maximum. + */ + private long fileCountMax = -1; + /** * The content encoding to use when reading part headers. */ @@ -204,6 +211,24 @@ public void setFileSizeMax(final long fileSizeMax) { this.fileSizeMax = fileSizeMax; } + /** + * Returns the maximum number of files allowed in a single request. + * + * @return The maximum number of files allowed in a single request. + */ + public long getFileCountMax() { + return fileCountMax; + } + + /** + * Sets the maximum number of files allowed per request/ + * + * @param fileCountMax The new limit. {@code -1} means no limit. + */ + public void setFileCountMax(long fileCountMax) { + this.fileCountMax = fileCountMax; + } + /** * Retrieves the character encoding used when reading the headers of an * individual part. When not specified, or {@code null}, the request @@ -278,6 +303,10 @@ public List<FileItem> parseRequest(final RequestContext ctx) "No FileItemFactory has been set."); final byte[] buffer = new byte[Streams.DEFAULT_BUFFER_SIZE]; while (iter.hasNext()) { + if (items.size() == fileCountMax) { + // The next item will exceed the limit. + throw new FileCountLimitExceededException(ATTACHMENT, getFileCountMax()); + } final FileItemStream item = iter.next(); // Don't use getName() here to prevent an InvalidFileNameException. final String fileName = item.getName();
java/org/apache/tomcat/util/http/fileupload/impl/FileCountLimitExceededException.java+50 −0 added@@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tomcat.util.http.fileupload.impl; + +import org.apache.tomcat.util.http.fileupload.FileUploadException; + +/** + * This exception is thrown if a request contains more files than the specified + * limit. + */ +public class FileCountLimitExceededException extends FileUploadException { + + private static final long serialVersionUID = 2408766352570556046L; + + private final long limit; + + /** + * Creates a new instance. + * + * @param message The detail message + * @param limit The limit that was exceeded + */ + public FileCountLimitExceededException(final String message, final long limit) { + super(message); + this.limit = limit; + } + + /** + * Retrieves the limit that was exceeded. + * + * @return The limit that was exceeded by the request + */ + public long getLimit() { + return limit; + } +}
java/org/apache/tomcat/util/http/Parameters.java+5 −0 modified@@ -125,6 +125,11 @@ public void setParseFailedReason(FailReason failReason) { } + public int size() { + return parameterCount; + } + + public void recycle() { parameterCount = 0; paramHashValues.clear();
MERGE.txt+1 −1 modified@@ -51,7 +51,7 @@ FileUpload Sub-tree: src/main/java/org/apache/commons/fileupload2 The SHA1 ID / tag for the most recent commit to be merged to Tomcat is: -aa8eff6f04c939fd99834360415b1ddb2f637cb1 (2022-11-29) +34eb241c051b02eca3b0b1b04f67b3b4e6c3a24d (2023-01-03) Note: Tomcat's copy of fileupload also includes classes copied manually from Commons IO.
webapps/docs/changelog.xml+8 −0 modified@@ -138,6 +138,14 @@ </fix> </changelog> </subsection> + <subsection name="Other"> + <changelog> + <update> + Update the internal fork of Apache Commons FileUpload to 34eb241 + (2023-01-03, 2.0-SNAPSHOT). (markt) + </update> + </changelog> + </subsection> </section> <section name="Tomcat 9.0.70 (remm)" rtext="2022-12-05"> <subsection name="Catalina">
webapps/docs/config/ajp.xml+9 −6 modified@@ -136,12 +136,15 @@ </attribute> <attribute name="maxParameterCount" required="false"> - <p>The maximum number of parameter and value pairs (GET plus POST) which - will be automatically parsed by the container. Parameter and value pairs - beyond this limit will be ignored. A value of less than 0 means no limit. - If not specified, a default of 10000 is used. Note that - <code>FailedRequestFilter</code> <a href="filter.html">filter</a> can be - used to reject requests that hit the limit.</p> + <p>The maximum total number of request parameters (including uploaded + files) obtained from the query string and, for POST requests, the request + body if the content type is + <code>application/x-www-form-urlencoded</code> or + <code>multipart/form-data</code>. Request parameters beyond this limit + will be ignored. A value of less than 0 means no limit. If not specified, + a default of 10000 is used. Note that <code>FailedRequestFilter</code> + <a href="filter.html">filter</a> can be used to reject requests that + exceed the limit.</p> </attribute> <attribute name="maxPostSize" required="false">
webapps/docs/config/http.xml+9 −6 modified@@ -134,12 +134,15 @@ </attribute> <attribute name="maxParameterCount" required="false"> - <p>The maximum number of parameter and value pairs (GET plus POST) which - will be automatically parsed by the container. Parameter and value pairs - beyond this limit will be ignored. A value of less than 0 means no limit. - If not specified, a default of 10000 is used. Note that - <code>FailedRequestFilter</code> <a href="filter.html">filter</a> can be - used to reject requests that hit the limit.</p> + <p>The maximum total number of request parameters (including uploaded + files) obtained from the query string and, for POST requests, the request + body if the content type is + <code>application/x-www-form-urlencoded</code> or + <code>multipart/form-data</code>. Request parameters beyond this limit + will be ignored. A value of less than 0 means no limit. If not specified, + a default of 10000 is used. Note that <code>FailedRequestFilter</code> + <a href="filter.html">filter</a> can be used to reject requests that + exceed the limit.</p> </attribute> <attribute name="maxPostSize" required="false">
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
20- github.com/advisories/GHSA-hfrx-6qgj-fp6cghsaADVISORY
- lists.apache.org/thread/4xl4l09mhwg4vgsk7dxqogcjrobrrdoyghsavendor-advisoryWEB
- nvd.nist.gov/vuln/detail/CVE-2023-24998ghsaADVISORY
- www.openwall.com/lists/oss-security/2023/05/22/1ghsaWEB
- commons.apache.org/proper/commons-fileupload/security-reports.htmlghsaWEB
- github.com/apache/commons-fileupload/commit/e20c04990f7420ca917e96a84cec58b13a1b3d17ghsaWEB
- github.com/apache/tomcat/commit/8a2285f13affa961cc65595aad999db5efae45ceghsaWEB
- github.com/apache/tomcat/commit/9ca96c8c1eba86c0aaa2e6be581ba2a7d4d4ae6eghsaWEB
- github.com/apache/tomcat/commit/cf77cc545de0488fb89e24294151504a7432df74ghsaWEB
- github.com/apache/tomcat/commit/d53d8e7f77042cc32a3b98f589496a1ef5088e38ghsaWEB
- lists.debian.org/debian-lts-announce/2023/10/msg00020.htmlghsaWEB
- lists.debian.org/debian-lts-announce/2025/07/msg00008.htmlghsaWEB
- security.gentoo.org/glsa/202305-37ghsaWEB
- security.netapp.com/advisory/ntap-20230302-0013ghsaWEB
- security.netapp.com/advisory/ntap-20241108-0002ghsaWEB
- tomcat.apache.org/security-10.htmlghsaWEB
- tomcat.apache.org/security-11.htmlghsaWEB
- tomcat.apache.org/security-8.htmlghsaWEB
- tomcat.apache.org/security-9.htmlghsaWEB
- www.debian.org/security/2023/dsa-5522ghsaWEB
News mentions
1- Jenkins Security Advisory 2023-03-08Jenkins Security Advisories · Mar 8, 2023