What Is a File Upload Vulnerability
A file upload vulnerability exists when a web application accepts file uploads without adequately validating what is being uploaded. At its most dangerous, this allows an attacker to upload a web shell — a malicious script that executes arbitrary commands on the server — effectively giving them full control over the underlying machine.
File upload functionality is extremely common. Profile pictures, document submissions, portfolio uploads, invoice attachments, product images — almost every business application that accepts user input eventually needs to accept files. Each upload form is a potential entry point if the validation is insufficient.
The risk is not theoretical. File upload vulnerabilities consistently appear in the [OWASP Top 10](/blog/owasp-top-10-explained-uk-businesses) under the injection and security misconfiguration categories. They are regularly exploited in the wild and are one of the more reliable paths to full server compromise when they exist.
How File Upload Attacks Work
Web shell upload
The most severe outcome of a file upload vulnerability is the ability to upload a web shell. A web shell is a script — typically PHP, ASP, JSP, or Python — that, once uploaded to the server and accessed via a URL, allows the attacker to execute commands as the web server user.
A minimal PHP web shell is just a few lines:
```php <?php system($_GET['cmd']); ?> ```
If an attacker can upload this file as `shell.php` to a location served by the web server, they can then navigate to `https://yoursite.com/uploads/shell.php?cmd=whoami` and receive the output of the `whoami` command running on your server. From there, privilege escalation, data exfiltration, and persistence are all achievable.
Bypassing client-side validation
Many upload forms check the file type using JavaScript in the browser. This check is entirely under the attacker's control — they can disable JavaScript, intercept the request with a proxy like Burp Suite, or simply craft a raw HTTP request. Client-side validation provides zero security against a motivated attacker; it is only a user experience convenience.
MIME type and extension bypass
Server-side validation that checks only the file extension or the MIME type declared in the HTTP request is also bypassable. An attacker can rename a PHP file to `shell.php.jpg`, or change the `Content-Type` header of their request to `image/jpeg` while the file content remains a PHP script. If the server accepts the upload based on these checks alone without inspecting the actual file content, the malicious file is stored on the server.
Double extension attacks
Some servers are configured to execute files based on the first recognised extension. A file named `shell.php.gif` may be served and executed as PHP by a misconfigured Apache server, even though the extension appears to end in `.gif`.
Polyglot files
A polyglot is a file that is simultaneously valid in two formats. An attacker can craft a file that is a valid JPEG image — passing any image content check — but also contains valid PHP code in its metadata or comments. When the server stores and serves this file, and the PHP interpreter processes it, the embedded code executes.
What Attackers Do After Uploading a Shell
A web shell is a foothold. Once an attacker has one, they typically:
**Enumerate the server** — Read `/etc/passwd`, check running processes, identify the operating system version, and map the directory structure to understand what they are working with.
**Read environment variables** — Web server processes often have access to environment variables containing database credentials, API keys, and other secrets. `printenv` via the shell dumps everything.
**Access the database** — With database credentials from the environment or configuration files, the attacker can read or exfiltrate the entire customer database.
**Move laterally** — If the server has network access to other internal systems — a database server, a cache, an internal API — the attacker can pivot from the web server to other infrastructure.
**Install persistent access** — A web shell can be difficult to find and remove. Attackers often install additional backdoors, cron jobs, or modified system binaries to maintain access after the initial shell is discovered and removed.
How to Prevent File Upload Vulnerabilities
Validate file content, not just extension
The only reliable way to verify a file is what it claims to be is to read its content and verify the magic bytes — the first few bytes of the file that identify its format. A JPEG always starts with `FF D8 FF`. A PNG starts with `89 50 4E 47`. A PDF starts with `25 50 44 46`. Validate that the content matches the expected format, not just that the filename ends in the right extension.
For images specifically, re-encode the image through an image processing library. If the file cannot be decoded and re-encoded as a valid image, reject it. This also strips any malicious payload hidden in image metadata.
Store uploads outside the web root
Files uploaded by users should never be stored in a directory that is directly served by the web server. Store them in a directory that is not accessible via HTTP. Serve them through a script that reads the file from the secure location and streams it to the user with appropriate headers — never by constructing a URL that points directly to the file.
If an attacker uploads a web shell to a directory that is not served by the web server, the shell cannot be accessed or executed via HTTP.
Randomise filenames
Replace the user-supplied filename entirely with a random, server-generated identifier. A file named `shell.php` uploaded by an attacker becomes `a7f3c9d2e1b4.jpg` in your storage. This prevents the attacker from knowing the URL of their uploaded file even if the storage location is web-accessible.
Set correct content-type headers on serving
When serving uploaded files, set the `Content-Type` header explicitly to match the expected type, and set `Content-Disposition: attachment` to force download rather than browser rendering. This prevents the browser from rendering an uploaded HTML file as a page or executing embedded scripts.
Use a CDN or object storage
Storing uploads in a dedicated object storage service like AWS S3, Cloudflare R2, or Google Cloud Storage, served via a CDN, separates upload storage from your application server entirely. Even if a malicious file is stored, it cannot execute on your application server.
What Yrzo AI Tests
A Yrzo AI scan specifically tests all discovered file upload endpoints for:
- Malicious extension bypass attempts (PHP, ASP, JSP, and other executable extensions with modified filenames) - MIME type spoofing - Double extension handling - Upload destination accessibility (whether uploaded files are served from a web-accessible path) - Content-Disposition header on file serving responses
The [Professional scan (£399)](/checkout/standard) and [Advanced scan (£799)](/checkout/pro) include authenticated testing, which is required to reach upload functionality that sits behind a login. [Start with a free scan](/free) to see what upload endpoints are discoverable without authentication.
Related reading: [What Is a Supply Chain Attack?](/blog/what-is-supply-chain-attack-website) · [What Is Server-Side Template Injection?](/blog/what-is-server-side-template-injection) · [Web Application Security Testing UK](/blog/web-application-security-testing-uk)
Find out if your website has these vulnerabilities
Yrzo AI runs 44 automated security checks and delivers a full report in under 20 minutes. Starting from £149.
Scan your website →