July 6, 2026
From Testing File Uploads to Discovering Remote Code Execution (RCE)
Introduction
By Hussein Kteish
3 min read
Introduction
During my first professional web and mobile application penetration test, one of the areas I focused on was file upload functionality. Upload features are often overlooked during development, yet they remain one of the most common sources of critical vulnerabilities.
What initially looked like a well-secured application eventually led to a full Remote Code Execution (RCE). This write-up describes the methodology, observations, and investigative process that led to discovering the vulnerability.
Target Overview
The assessment included two applications that worked together:
- Web Application: An administrative portal used by employees to manage the platform.
- Mobile Application: A customer-facing application where users interacted with the services provided by the platform.
The administrators configured the platform through the web portal, while customers used the mobile application to access those features.
Starting with File Upload Testing
One of the first areas I decided to test was file upload functionality.
I systematically reviewed every upload feature I could find throughout the application, including:
- Profile photo uploads
- User avatar images
- Attachment uploads
- Other document upload functionalities
For each upload point, I attempted to upload various server-side files, including PHP scripts, while also testing different MIME types and extensions.
Every upload feature behaved as expected.
The application rejected executable files, validated file types correctly, and appeared to implement proper filtering mechanisms.
At this point, the upload functionality looked well protected.
Finding One More Upload Feature
Rather than assuming every upload endpoint was equally secure, I continued exploring the application.
After spending more time navigating both the mobile application and the administrator portal, I discovered another upload functionality that had a different purpose.
Users were able to upload a Proof of Payment Invoice after completing a payment from the mobile app.
Unlike the previous upload features, this endpoint had not yet been tested.
An Interesting Observation
I repeated the same tests I had already performed against the other upload endpoints.
To my surprise, the invoice upload accepted my PHP file without any validation error.
This immediately stood out because every previous upload functionality had rejected the exact same payload.
The inconsistent behavior suggested that this endpoint had been implemented separately from the others and was missing the security controls present elsewhere in the application.
However, accepting a PHP file alone does not necessarily result in Remote Code Execution.
The next challenge was determining what happened to the uploaded file.
Investigating the Upload
I intercepted the upload request using Burp Suite and carefully examined both the request and the server's response.
The application returned a file URL similar to:
https://gateway.target.com/uploads/rce.phphttps://gateway.target.com/uploads/rce.phpNaturally, I attempted to access the uploaded file.
Instead of executing, the URL returned an error.
At first glance, it appeared that the application had safely handled the upload.
However, something about the response seemed unusual.
The returned path did not appear to represent the application's actual storage location.
Rather than stopping there, I decided to investigate further.
Searching for the Real Storage Location
Based on the application's architecture, I suspected that the visible upload URL was simply a gateway or proxy rather than the real filesystem location.
I began enumerating directories and common upload paths using a directory fuzzing tool.
After several requests, I discovered another endpoint:
https://api.target.com/uploads/Original/https://api.target.com/uploads/Original/Unlike the previous URL, this location directly exposed the uploaded file.
Remote Code Execution
Opening the newly discovered path:
https://api.target.com/uploads/Original/rce.php
caused the PHP payload to execute successfully.
The server interpreted the uploaded file as executable PHP code rather than serving it as a static file.
At this stage, arbitrary PHP code execution was possible, resulting in full Remote Code Execution (RCE).
What initially appeared to be a harmless invoice upload feature had become a complete server-side code execution vector.
Root Cause
The vulnerability existed because several security controls were missing from this specific upload endpoint.
The application:
- Allowed executable file extensions.
- Stored uploaded files inside a web-accessible directory.
- Allowed PHP execution within that directory.
- Exposed a predictable storage path that could be discovered through enumeration.
Although other upload features had implemented proper validation, this endpoint lacked those protections, making it an exception that introduced a critical security risk.
Impact
Successful exploitation allowed an attacker to execute arbitrary PHP code on the server.
Depending on the server configuration, this could lead to:
- Reading sensitive application files.
- Accessing configuration files containing credentials.
- Database compromise.
- Establishing persistent access.
- Complete compromise of the affected server.
Lessons Learned
This assessment reinforced an important lesson that has stayed with me throughout penetration testing.
It is easy to stop testing after several secure implementations of the same functionality. In this case, every upload endpoint I tested initially enforced proper validation, which could have led to the assumption that the entire application handled uploads securely.
Instead, I continued exploring the application and testing every upload feature individually.
That persistence uncovered a single inconsistent implementation, which ultimately led to a critical Remote Code Execution vulnerability.
One insecure endpoint is all it takes.
Recommendations
To prevent this class of vulnerability:
- Apply the same upload validation logic across every upload endpoint.
- Restrict uploads to approved file extensions.
- Validate MIME type and file contents.
- Rename uploaded files using randomized names.
- Store uploaded files outside the web root whenever possible.
- Disable execution of server-side scripts within upload directories.
- Serve uploaded files through a download handler instead of exposing them directly.
Conclusion
This finding highlights why penetration testing should never rely on assumptions or previous results.
Even though multiple upload features were implemented securely, one overlooked endpoint lacked the same protections and ultimately allowed Remote Code Execution.
The most valuable part of this finding was not simply uploading a PHP file it was recognizing the inconsistency, investigating the application's architecture, and continuing until the true storage location was identified.