VYPR
High severityNVD Advisory· Published Dec 5, 2023· Updated Nov 4, 2025

Apache Struts: excessive disk usage

CVE-2023-41835

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.

PackageAffected versionsPatched versions
org.apache.struts:struts2-coreMaven
>= 6.2.0, < 6.3.0.16.3.0.1
org.apache.struts:struts2-coreMaven
>= 6.0.0, < 6.1.2.26.1.2.2
org.apache.struts:struts2-coreMaven
< 2.5.322.5.32

Affected products

2

Patches

3
4c044f12560e

Always delete uploaded file

https://github.com/apache/strutsLukasz LenartSep 5, 2023via ghsa
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;
    
3292152f8c0a

Always delete uploaded file

https://github.com/apache/strutsLukasz LenartSep 3, 2023via ghsa
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;
    
bf54436869c2

Always delete uploaded file

https://github.com/apache/strutsLukasz LenartSep 3, 2023via ghsa
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

News mentions

0

No linked articles in our index yet.