Apache Struts 2 has a history of critical vulnerabilities. The vulnerability allows attackers to manipulate file upload parameters, possibly leading to remote code execution.

While Struts version 6.4.0 introduced a new file upload mechanism ActionFileUploadInterceptor
to replace the legacy FileUploadInterceptor
, upgrading alone does not mitigate the risk. Applications must migrate to the new mechanism, as using the deprecated file upload mechanism leaves systems vulnerable. Complete mitigation is only guaranteed in Struts version 7.0.0 and later, where the legacy class is fully removed.
This blog post dissects the vulnerability, explains how Struts processes file uploads, details the exploit mechanics, and outlines mitigation strategies. Developers and security professionals should take immediate steps to ensure the security of their Struts-based applications.
Introduction
Apache Struts 2 is a widely used Java framework for web applications, valued for its flexibility and Model-View-Controller (MVC) architecture. However, its history is marked by critical security flaws leading to data breaches.
According to a 2017 article, attackers exploited an unpatched Apache Struts vulnerability (CVE-2017-5638) to expose the sensitive information of over 145 million people. It was reported that the breach resulted from delayed patching, proving how one unaddressed flaw can have detrimental consequences.
The latest vulnerability, CVE-2024-53677, was published in December 2024. It is a critical flaw in the file upload mechanism. This allows attackers to manipulate file upload parameters, leading to unauthorized file placement and potentially remote code execution (RCE).
Implementing file upload with Apache Struts 2
The Struts 2 framework simplifies file uploads by automatically storing uploaded files in a temporary location and passing the file data to the action class. This allows developers to easily access and process the file without handling the upload mechanics directly.
To implement file uploads, the developer would simply need to configure an action mapping, create a form with a file input field, and write an action class that accepts a file. When executed, the action class processes the file by either reading its content or moving it to an uploads folder for later access.
Here’s an example of what the action class should look like.
public class UploadAction extends ActionSupport {
private static final String UPLOAD_DIR = "/uploads";
private File file;
private String fileFileName;
private String fileContentType;
public String execute() {
if (fileFileName == null) return INPUT; // show file upload form page
try {
File destFile = new File(UPLOAD_DIR, fileFileName);
FileUtils.copyFile(file, destFile); // copy file to uploads folder
return SUCCESS; // show success page
} catch (Exception e) {return ERROR;} // file upload failed; show error page
}
// constructors, getters, setters, ...
}
In this scenario, the files are stored in the /uploads
folder, which is not accessible via the web server.
The corresponding file upload form for the action is as follows:
<s:form action="upload" method="post" enctype="multipart/form-data">
<s:file name="file"/>
<s:submit/>
</s:form>
Notice that the file form field’s name is “file”, and the corresponding attributes in the action class are file
, fileFileName
, and fileContentType
. The file prefix in these attributes corresponds to the form field name.
How does file upload work in Struts?
Before investigating the vulnerability, we need to understand the file upload mechanics and examine some key Struts concepts relevant to it.
Value stack
The value stack simplifies data access between the action, the view, and other components. Unlike a standard stack, it acts as an intermediary for the objects it contains. It also facilitates access to data in the view through OGNL expressions, enabling developers to retrieve stored data efficiently. Consider the following example, where a couple of objects are stored in the value stack.

When retrieving the value of the expression “x,” the value stack searches for an object with a property named x, starting from the top. The first occurrence is returned, which is the rectangle’s x value in our example. To get the circle’s x value, the indexing syntax [1]
can be used to select the second object.
Interceptors
Interceptors are components that process the request before and after an action is executed. They handle tasks such as data validation, logging, and exception handling. In this blog post, we will focus exclusively on the file upload and the parameters interceptors, which are used by default. The ParametersInterceptor assigns HTTP parameters to the corresponding attributes in the action object if it exists. The parameter interceptor uses the OGNL expressions and the value stack to set the value of the action attributes. Likewise, the FileUploadInterceptor class is responsible for preparing the file upload data, by setting the following attributes: the temporary file location, the original file name, and its content type. It relies on the parameters interceptor to set the attributes, by inserting the values into the existing parameters
map.
File upload process
The Struts2 file upload process works as follows:
- A
parameters
map is created and populated with non-file HTTP parameters. - The
FileUploadInterceptor
inserts file details into the parameters map. - The
ParametersInterceptor
sets action class attributes using the value stack. - The action class is executed, and the file is moved to the
/uploads
directory.
Understanding the Apache Struts 2 vulnerability
First, let’s examine the example exploit below. A POST request is sent to upload a benign-looking text file named user_file.txt
. In our previous file upload example, this file would be uploaded and saved as /uploads/user_file.txt
.
However, notice the suspicious path../usr/local/tomcat/webapps/ROOT/shell.jsp
in the additional HTTP parameter top.fileFileName
. As a result of this path traversal attack, the file will be stored in /usr/local/tomcat/webapps/ROOT/
as shell.jsp
instead. This not only makes the uploaded file accessible via the web server but it also makes it executable because of the .jsp
extension.
requests.post(
f"http://localhost:8080/upload.action",
files={"file": ("user_file.txt", open("user_file.txt").read(), "text/plain")}
data={"top.fileFileName": "../usr/local/tomcat/webapps/ROOT/shell.jsp"}
)
To understand how the vulnerability works, we need to figure out how the attacker uses the top.fileFileName
parameter to alter the file upload location. At first glance, the fileFileName
part is the attribute name of our example action class. This attribute should be set by the FileUploadInterceptor
. However, an attacker can overwrite it using the top.fileFileName
HTTP parameter as part of a mass assignment attack, where they can infer the attribute’s name in the action class. Subsequently, when the action is executed, the temporary uploaded file is copied to a location provided by the attacker.
// UPLOAD_DIR = "/uploads"
// fileFileName = "../usr/local/tomcat/webapps/ROOT/shell.jsp")
File destFile = new File(UPLOAD_DIR, fileFileName);
// file = File("TEMP_FILE_LOCATION")
// destFile = File("/usr/local/tomcat/webapss/ROOT/shell.jsp")
FileUtils.copyFile(file, destFile);
So, how does the top.
part of the added parameter affects the file upload flow and allows overwriting the file name attribute? Looking at the framework’s documentation, we’re unable to find any reference to such a keyword. However, we do find string references in the source code and a comment in OgnlUtil.java#L503 hinting that top
is a special keyword in OGNL.
//special keyword, they must be cutting the stack
if ("top".equals(property)) {
return root;
}
Another reference to the keyword in CompoundRootAccessor.java#L129 shows that the keyword can be used to retrieve the first element of root
, which is an object that holds the elements of the value stack.
if ("top".equals(name)) {
if (root.size() > 0) {
return root.get(0);
//...
We also notice a reference to the top
keyword in DefaultExcludedPatternsChecker.java#L39, which is used across different interceptors to check if a given string matches one of the excluded patterns, according to the documentation. This was added to address an earlier vulnerability CVE-2015-5209.
The top
is an undocumented keyword intended for exclusive internal use. As mentioned in an earlier version of the security bulletin S2-026, it was also considered for removal.
“Support for expression using top will be dropped in upcoming Struts version 2.5!”
Selecting the first element of the stack is crucial for the exploit to function correctly. This is because, during the execution of an action, the top of the value stack is the action object itself. Additionally, directly using the field name as an expression does not add it to the parameters list, as the same key is used by the FileUploadInterceptor
class to insert the file name.
We have seen how the special top
keyword allows access to the first element in the value stack. The equivalent indexing syntax ([0]
) could also have been used; however, we find that it does not match the accepted patterns defined in DefaultAcceptedPatternsChecker.java#L39.
To summarize, the following illustration demonstrates how the action attributes were set during the request interception before executing the action.

For file fields that accept multiple files, the corresponding action attribute should be of type List<String>
.
private List fileFileName;
In this scenario, the exploit can be adapted for this type. The indexing syntax ([0]
) can be used to select an element from the list. For example, using a parameter named fileFileName[0]
. The accepted parameter patterns mentioned above would allow such a name, and the usage of the top
keyword is no longer necessary.
Detecting and patching the Apache Struts 2 vulnerability
This vulnerability affects Apache Struts versions from 2.0.0 up to, but not including, 7.0.0. Although the vulnerable FileUploadInterceptor
class was deprecated in version 6.4.0 with a vendor recommendation to migrate to the newly introduced ActionFileUploadInterceptor
mechanism, the old vulnerable file upload class is completely removed only starting from version 7.0.0. Upgrading to version 6.4.0 is not enough to fully mitigate the risk.
To mitigate this vulnerability, we recommend taking one of the following actions:
- Upgrade to version 7.0.0 or higher and migrate your file upload actions to use the new
ActionFileUploadInterceptor
. - When upgrading to version 6.4.0 or higher, developers must ensure that all file upload implementations have been refactored to the new
ActionFileUploadInterceptor
. - Exclude certain parameters containing
FileName
orContentType
patterns from being processed. The following example adds a regular expression to the Parameters interceptor exclusion pattern:
<interceptor-ref name="defaultStack">
<param name="params.excludeParams">^(?:top\.\w+(?:FileName|ContentType))|(?:\w+(?:FileName|ContentType)\[\d+\])$</param>
</interceptor-ref>
- Modifying the WAF configuration to block requests that include parameters matching the following regular expression:
^(?:top\.\w+(?:FileName|ContentType))|(?:\w+(?:FileName|ContentType)\[\d+\])$.
Runtime Vulnerability Analytics
Organizations still running Apache Struts versions before 7.0.0
are potentially at risk and should discontinue using the legacy file upload mechanism. Dynatrace Runtime Vulnerability Analytics can help detect if the vulnerable method is actively being used within your applications. This allows you to prioritize alerts and strategically address the most critical issues. We’re continuously expanding our vulnerability insights enabling you to stay ahead of potential risks.

Looking for answers?
Start a new discussion or ask for help in our Q&A forum.
Go to forum