Apache Struts: excessive disk usage
Description
When a Multipart request is performed but some of the fields exceed the maxStringLength limit, the upload files will remain in struts.multipart.saveDir even if the request has been denied. Users are recommended to upgrade to versions Struts 2.5.32 or 6.1.2.2 or Struts 6.3.0.1 or greater, which fixe this issue.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
In Apache Struts, when a multipart request has fields exceeding maxStringLength, temporary uploaded files are not deleted, leading to disk space exhaustion.
Vulnerability
CVE-2023-41835 describes an issue in Apache Struts where multipart file uploads are not properly cleaned up when normal form fields exceed the maxStringLength limit. When processing a multipart request, Struts stores uploaded files in a temporary directory defined by struts.multipart.saveDir. If a form field exceeds maxStringLength, the request is rejected, but the uploaded file remains on disk. [1]
Exploitation
An attacker can exploit this by submitting a multipart request that includes a file upload and a form field whose value exceeds the configured maxStringLength. The request will be denied, but the uploaded file persists in the temporary directory. Repeated submissions can accumulate files, leading to disk space exhaustion. No authentication is required for this attack. [1][3]
Impact
The primary impact is a denial of service (DoS) condition due to disk space exhaustion. This can disrupt the availability of the affected application and potentially other services sharing the same disk. [1]
Mitigation
Apache Struts has addressed this issue in versions 2.5.32, 6.1.2.2, and 6.3.0.1 and later. Users should upgrade to these versions. The fix ensures that uploaded files are always deleted, even when the request is rejected due to field size violations. [1][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 |
|---|---|---|
org.apache.struts:struts2-coreMaven | >= 6.2.0, < 6.3.0.1 | 6.3.0.1 |
org.apache.struts:struts2-coreMaven | >= 6.0.0, < 6.1.2.2 | 6.1.2.2 |
org.apache.struts:struts2-coreMaven | < 2.5.32 | 2.5.32 |
Affected products
2- Apache Software Foundation/Apache Strutsv5Range: 2.0.0
Patches
34c044f12560eAlways delete uploaded file
1 file changed · +41 −38
core/src/main/java/org/apache/struts2/dispatcher/multipart/JakartaMultiPartRequest.java+41 −38 modified@@ -114,7 +114,7 @@ protected void processFileField(FileItem item) { LOG.debug("Item is a file upload"); // Skip file uploads that don't have a file name - meaning that no file was selected. - if (item.getName() == null || item.getName().trim().length() < 1) { + if (item.getName() == null || item.getName().trim().isEmpty()) { LOG.debug("No file has been uploaded for the field: {}", item.getFieldName()); return; } @@ -131,39 +131,42 @@ protected void processFileField(FileItem item) { } protected void processNormalFormField(FileItem item, String charset) throws UnsupportedEncodingException { - LOG.debug("Item is a normal form field"); + try { + LOG.debug("Item is a normal form field"); - List<String> values; - if (params.get(item.getFieldName()) != null) { - values = params.get(item.getFieldName()); - } else { - values = new ArrayList<>(); - } + List<String> values; + if (params.get(item.getFieldName()) != null) { + values = params.get(item.getFieldName()); + } else { + values = new ArrayList<>(); + } - long size = item.getSize(); - if (size == 0) { - values.add(StringUtils.EMPTY); - } else if (size > maxStringLength) { - String errorKey = "struts.messages.upload.error.parameter.too.long"; - LocalizedMessage localizedMessage = new LocalizedMessage(this.getClass(), errorKey, null, - new Object[] { item.getFieldName(), maxStringLength, size }); - - if (!errors.contains(localizedMessage)) { - errors.add(localizedMessage); - } - return; - - } else if (charset != null) { - values.add(item.getString(charset)); - } else { - // note: see https://issues.apache.org/jira/browse/WW-633 - // basically, in some cases the charset may be null, so - // we're just going to try to "other" method (no idea if this - // will work) - values.add(item.getString()); + long size = item.getSize(); + if (size == 0) { + values.add(StringUtils.EMPTY); + } else if (size > maxStringLength) { + String errorKey = "struts.messages.upload.error.parameter.too.long"; + LocalizedMessage localizedMessage = new LocalizedMessage(this.getClass(), errorKey, null, + new Object[]{item.getFieldName(), maxStringLength, size}); + + if (!errors.contains(localizedMessage)) { + errors.add(localizedMessage); + } + return; + + } else if (charset != null) { + values.add(item.getString(charset)); + } else { + // note: see https://issues.apache.org/jira/browse/WW-633 + // basically, in some cases the charset may be null, so + // we're just going to try to "other" method (no idea if this + // will work) + values.add(item.getString()); + } + params.put(item.getFieldName(), values); + } finally { + item.delete(); } - params.put(item.getFieldName(), values); - item.delete(); } protected List<FileItem> parseRequest(HttpServletRequest servletRequest, String saveDir) throws FileUploadException { @@ -218,7 +221,7 @@ public String[] getContentType(String fieldName) { contentTypes.add(fileItem.getContentType()); } - return contentTypes.toArray(new String[contentTypes.size()]); + return contentTypes.toArray(new String[0]); } /* (non-Javadoc) @@ -247,7 +250,7 @@ public UploadedFile[] getFile(String fieldName) { fileList.add(new StrutsUploadedFile(storeLocation)); } - return fileList.toArray(new UploadedFile[fileList.size()]); + return fileList.toArray(new UploadedFile[0]); } /* (non-Javadoc) @@ -265,7 +268,7 @@ public String[] getFileNames(String fieldName) { fileNames.add(getCanonicalName(fileItem.getName())); } - return fileNames.toArray(new String[fileNames.size()]); + return fileNames.toArray(new String[0]); } /* (non-Javadoc) @@ -283,15 +286,15 @@ public String[] getFilesystemName(String fieldName) { fileNames.add(((DiskFileItem) fileItem).getStoreLocation().getName()); } - return fileNames.toArray(new String[fileNames.size()]); + return fileNames.toArray(new String[0]); } /* (non-Javadoc) * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getParameter(java.lang.String) */ public String getParameter(String name) { List<String> v = params.get(name); - if (v != null && v.size() > 0) { + if (v != null && !v.isEmpty()) { return v.get(0); } @@ -310,8 +313,8 @@ public Enumeration<String> getParameterNames() { */ public String[] getParameterValues(String name) { List<String> v = params.get(name); - if (v != null && v.size() > 0) { - return v.toArray(new String[v.size()]); + if (v != null && !v.isEmpty()) { + return v.toArray(new String[0]); } return null;
3292152f8c0aAlways delete uploaded file
1 file changed · +41 −38
core/src/main/java/org/apache/struts2/dispatcher/multipart/JakartaMultiPartRequest.java+41 −38 modified@@ -111,7 +111,7 @@ protected void processFileField(FileItem item) { LOG.debug("Item is a file upload"); // Skip file uploads that don't have a file name - meaning that no file was selected. - if (item.getName() == null || item.getName().trim().length() < 1) { + if (item.getName() == null || item.getName().trim().isEmpty()) { LOG.debug("No file has been uploaded for the field: {}", item.getFieldName()); return; } @@ -128,39 +128,42 @@ protected void processFileField(FileItem item) { } protected void processNormalFormField(FileItem item, String charset) throws UnsupportedEncodingException { - LOG.debug("Item is a normal form field"); + try { + LOG.debug("Item is a normal form field"); - List<String> values; - if (params.get(item.getFieldName()) != null) { - values = params.get(item.getFieldName()); - } else { - values = new ArrayList<>(); - } + List<String> values; + if (params.get(item.getFieldName()) != null) { + values = params.get(item.getFieldName()); + } else { + values = new ArrayList<>(); + } - long size = item.getSize(); - if (size == 0) { - values.add(StringUtils.EMPTY); - } else if (size > maxStringLength) { - String errorKey = "struts.messages.upload.error.parameter.too.long"; - LocalizedMessage localizedMessage = new LocalizedMessage(this.getClass(), errorKey, null, - new Object[] { item.getFieldName(), maxStringLength, size }); - - if (!errors.contains(localizedMessage)) { - errors.add(localizedMessage); - } - return; - - } else if (charset != null) { - values.add(item.getString(charset)); - } else { - // note: see https://issues.apache.org/jira/browse/WW-633 - // basically, in some cases the charset may be null, so - // we're just going to try to "other" method (no idea if this - // will work) - values.add(item.getString()); + long size = item.getSize(); + if (size == 0) { + values.add(StringUtils.EMPTY); + } else if (size > maxStringLength) { + String errorKey = "struts.messages.upload.error.parameter.too.long"; + LocalizedMessage localizedMessage = new LocalizedMessage(this.getClass(), errorKey, null, + new Object[]{item.getFieldName(), maxStringLength, size}); + + if (!errors.contains(localizedMessage)) { + errors.add(localizedMessage); + } + return; + + } else if (charset != null) { + values.add(item.getString(charset)); + } else { + // note: see https://issues.apache.org/jira/browse/WW-633 + // basically, in some cases the charset may be null, so + // we're just going to try to "other" method (no idea if this + // will work) + values.add(item.getString()); + } + params.put(item.getFieldName(), values); + } finally { + item.delete(); } - params.put(item.getFieldName(), values); - item.delete(); } protected List<FileItem> parseRequest(HttpServletRequest servletRequest, String saveDir) throws FileUploadException { @@ -212,7 +215,7 @@ public String[] getContentType(String fieldName) { contentTypes.add(fileItem.getContentType()); } - return contentTypes.toArray(new String[contentTypes.size()]); + return contentTypes.toArray(new String[0]); } /* (non-Javadoc) @@ -241,7 +244,7 @@ public UploadedFile[] getFile(String fieldName) { fileList.add(new StrutsUploadedFile(storeLocation)); } - return fileList.toArray(new UploadedFile[fileList.size()]); + return fileList.toArray(new UploadedFile[0]); } /* (non-Javadoc) @@ -259,7 +262,7 @@ public String[] getFileNames(String fieldName) { fileNames.add(getCanonicalName(fileItem.getName())); } - return fileNames.toArray(new String[fileNames.size()]); + return fileNames.toArray(new String[0]); } /* (non-Javadoc) @@ -277,15 +280,15 @@ public String[] getFilesystemName(String fieldName) { fileNames.add(((DiskFileItem) fileItem).getStoreLocation().getName()); } - return fileNames.toArray(new String[fileNames.size()]); + return fileNames.toArray(new String[0]); } /* (non-Javadoc) * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getParameter(java.lang.String) */ public String getParameter(String name) { List<String> v = params.get(name); - if (v != null && v.size() > 0) { + if (v != null && !v.isEmpty()) { return v.get(0); } @@ -304,8 +307,8 @@ public Enumeration<String> getParameterNames() { */ public String[] getParameterValues(String name) { List<String> v = params.get(name); - if (v != null && v.size() > 0) { - return v.toArray(new String[v.size()]); + if (v != null && !v.isEmpty()) { + return v.toArray(new String[0]); } return null;
bf54436869c2Always delete uploaded file
1 file changed · +43 −34
core/src/main/java/org/apache/struts2/dispatcher/multipart/JakartaMultiPartRequest.java+43 −34 modified@@ -35,7 +35,13 @@ import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; /** * Multipart form data request adapter for Jakarta Commons Fileupload package. @@ -64,7 +70,7 @@ public void parse(HttpServletRequest request, String saveDir) { } catch (FileUploadException e) { LOG.warn("Request exceeded size limit!", e); LocalizedMessage errorMessage; - if(e instanceof FileUploadBase.SizeLimitExceededException) { + if (e instanceof FileUploadBase.SizeLimitExceededException) { FileUploadBase.SizeLimitExceededException ex = (FileUploadBase.SizeLimitExceededException) e; errorMessage = buildErrorMessage(e, new Object[]{ex.getPermittedSize(), ex.getActualSize()}); } else { @@ -100,7 +106,7 @@ protected void processFileField(FileItem item) { LOG.debug("Item is a file upload"); // Skip file uploads that don't have a file name - meaning that no file was selected. - if (item.getName() == null || item.getName().trim().length() < 1) { + if (item.getName() == null || item.getName().trim().isEmpty()) { LOG.debug("No file has been uploaded for the field: {}", item.getFieldName()); return; } @@ -117,39 +123,42 @@ protected void processFileField(FileItem item) { } protected void processNormalFormField(FileItem item, String charset) throws UnsupportedEncodingException { - LOG.debug("Item is a normal form field"); + try { + LOG.debug("Item is a normal form field"); - List<String> values; - if (params.get(item.getFieldName()) != null) { - values = params.get(item.getFieldName()); - } else { - values = new ArrayList<>(); - } + List<String> values; + if (params.get(item.getFieldName()) != null) { + values = params.get(item.getFieldName()); + } else { + values = new ArrayList<>(); + } - long size = item.getSize(); - if (size == 0) { - values.add(StringUtils.EMPTY); - } else if (size > maxStringLength) { - String errorKey = "struts.messages.upload.error.parameter.too.long"; - LocalizedMessage localizedMessage = new LocalizedMessage(this.getClass(), errorKey, null, - new Object[] { item.getFieldName(), maxStringLength, size }); + long size = item.getSize(); + if (size == 0) { + values.add(StringUtils.EMPTY); + } else if (size > maxStringLength) { + String errorKey = "struts.messages.upload.error.parameter.too.long"; + LocalizedMessage localizedMessage = new LocalizedMessage(this.getClass(), errorKey, null, + new Object[]{item.getFieldName(), maxStringLength, size}); - if (!errors.contains(localizedMessage)) { - errors.add(localizedMessage); - } - return; + if (!errors.contains(localizedMessage)) { + errors.add(localizedMessage); + } + return; - } else if (charset != null) { - values.add(item.getString(charset)); - } else { - // note: see http://jira.opensymphony.com/browse/WW-633 - // basically, in some cases the charset may be null, so - // we're just going to try to "other" method (no idea if this - // will work) - values.add(item.getString()); + } else if (charset != null) { + values.add(item.getString(charset)); + } else { + // note: see https://issues.apache.org/jira/browse/WW-633 + // basically, in some cases the charset may be null, so + // we're just going to try to "other" method (no idea if this + // will work) + values.add(item.getString()); + } + params.put(item.getFieldName(), values); + } finally { + item.delete(); } - params.put(item.getFieldName(), values); - item.delete(); } protected List<FileItem> parseRequest(HttpServletRequest servletRequest, String saveDir) throws FileUploadException { @@ -323,14 +332,14 @@ public InputStream getInputStream() throws IOException { } /* (non-Javadoc) - * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#cleanUp() - */ + * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#cleanUp() + */ public void cleanUp() { Set<String> names = files.keySet(); for (String name : names) { List<FileItem> items = files.get(name); for (FileItem item : items) { - LOG.debug("Removing file {} {}", name, item ); + LOG.debug("Removing file {} {}", name, item); if (!item.isInMemory()) { item.delete(); }
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
9- github.com/advisories/GHSA-729q-fcgp-r5xhghsaADVISORY
- lists.apache.org/thread/6wj530kh3ono8phr642y9sqkl67ys2ftghsamailing-listvendor-advisoryWEB
- nvd.nist.gov/vuln/detail/CVE-2023-41835ghsaADVISORY
- www.openwall.com/lists/oss-security/2023/12/09/1ghsaWEB
- github.com/apache/struts/commit/3292152f8c0a77ee4827beede82b6580478a2c2aghsaWEB
- github.com/apache/struts/commit/4c044f12560e22e00520595412830f9582d6dac7ghsaWEB
- github.com/apache/struts/commit/bf54436869c264941dd192c752a4abfaa65d3711ghsaWEB
- security.netapp.com/advisory/ntap-20231013-0001ghsaWEB
- www.openwall.com/lists/oss-security/2023/12/09/1ghsaWEB
News mentions
0No linked articles in our index yet.