ofensiva
unrestricted file upload
file upload vulnerability
CWE-434

File Upload Vulnerability: Webshell, RCE and Defense

Unrestricted file upload (CWE-434): validation bypass, Content-Type spoofing, double extension, PHP/ASPX webshells to RCE and the defensive controls.

SecraJuly 6, 202611 min read

A file upload vulnerability is a web flaw in which an application accepts user supplied files without properly validating their type, their content or where they are stored, allowing an attacker to place executable code on the server. Catalogued as CWE-434 (Unrestricted Upload of File with Dangerous Type), it is often the first link in a chain that ends in remote code execution (RCE). The textbook case consists of slipping a webshell (a PHP, ASPX or JSP script capable of running commands) past the application's checks and then requesting the uploaded file's URL to take control of the server.

The essentials. An unrestricted file upload turns a seemingly harmless form (profile picture, attachment, data import) into an RCE vector. The attacker evades client and server validation through Content-Type spoofing, extension list evasion, double extension, null byte and polyglot files with valid magic bytes. The defense is not a single control but a chain: content based allowlisting, random rename, storage outside the webroot, disabled execution in the upload directory and AV/CDR scanning.

What an unrestricted file upload is (CWE-434)

Almost every web application receives files somewhere: avatar images, supporting documents, spreadsheets for import, resumes, signatures. The risk appears when the application trusts attributes that the client controls (the file name, the extension, the Content-Type header of the multipart) instead of inspecting the real content, and when it stores the file in a path that is both reachable and able to execute code.

The problem is not the upload itself, but the combination of two failures that must occur together: insufficient validation of the file, and a storage location that allows the uploaded content to be served or executed. If either breaks, the insecure upload escalates to RCE. That is why it is a recurring finding in audits, in the same family as the flaws described in the 5 most common web vulnerabilities in 2025.

Attack chain: from validation to RCE

From an offensive standpoint, exploiting an insecure upload is an exercise in progressive evasion. You test control after control until you find the gap that lets you place an executable file in a servable path.

Bypassing client side validation

The first barrier is usually JavaScript: the form checks the extension or type before submitting. That is a cosmetic defense. It is enough to disable JavaScript, edit the DOM, or intercept the already submitted request with a proxy such as Burp Suite and modify the multipart body after the browser has approved the file. The accept attribute of an <input type="file"> enforces nothing on the server side. Any validation that only happens in the browser is treated as nonexistent for security purposes.

Evading server side validation

This is where the real work concentrates. The usual techniques:

  • Content-Type spoofing. The server checks the multipart Content-Type header, which the client sends. You change application/x-php to image/png or image/jpeg while keeping the malicious payload. The server believes it received an image.
  • Allowlist and denylist evasion. Against a denylist that blocks .php, you try alternative extensions the interpreter still runs: .phtml, .php5, .php7, .pht, .phar. Plus case variation (.pHp), trailing characters (.php., .php%20) or NTFS alternate data stream suffixes on IIS (.php::$DATA). In the ASP.NET world, extensions like .aspx, .ashx, .asmx or a .config with embedded handlers; in Java, .jsp and .jspx.
  • Double extension. shell.php.jpg or shell.jpg.php exploit misconfigured Apache setups with mod_mime and AddHandler, where the server picks the handler by the first or the last recognised extension.
  • Null byte. In old PHP versions (before 5.3.4) and certain native layers, shell.php%00.jpg truncated the name at the null byte and the file was stored as shell.php. Historic, but still visible in legacy systems.
  • Magic bytes and polyglot files. When the server validates by signature (for example with getimagesize()), you prepend a valid header to the payload: a file starting with GIF89a; followed by <?php system($_GET['cmd']); ?> passes the check as a GIF and executes as PHP. Code is also injected into the EXIF metadata of a real image with exiftool, producing a polyglot that is both a legitimate image and code.
  • .htaccess upload. If the upload directory allows it, uploading your own .htaccess that adds a handler (AddType application/x-httpd-php .xyz) turns an arbitrary extension into an executable one.

From webshell to RCE

Once validation is bypassed, the goal is for the file to end up in a path served by the application server and with an extension the interpreter executes. A minimal PHP webshell such as <?php system($_GET['cmd']); ?> is enough to run commands via a GET parameter. In the real world more complete webshells are used (weevely, China Chopper, or obfuscated variants) offering file browsing, upload and pivoting. The IIS equivalent is an ASPX webshell, and on Java servers a JSP one.

The final step is to locate the uploaded file's URL (often predictable: /uploads/, /media/, /files/) and request it. If the server executes the script, the attacker has command execution with the privileges of the web process, from which they escalate to an interactive reverse shell and lateral movement. A persistent webshell installed this way behaves, from then on, like a backdoor: the difference lies in the origin, not the outcome.

Demonstration from the pentester's viewpoint (Burp)

In a web application audit the flow is methodical and reproducible. It relies on an interception proxy such as Burp Suite, a tool we cover in what Burp Suite is and how it is used in web pentesting:

  1. Locate every upload point through authenticated crawling and map which extensions and types each one accepts.
  2. Upload a benign reference file and observe the storage path, the resulting name and whether it is reachable by URL.
  3. Intercept the multipart request with Burp Proxy and send it to Repeater to iterate variants: change the Content-Type, alter the extension, apply a double extension, insert magic bytes.
  4. Automate the matrix of extensions and signatures with Intruder or with the lists in the OWASP Web Security Testing Guide.
  5. Confirm execution by requesting the uploaded file and checking the command output.

The auditor's judgement distinguishes between validation that only checks the extension (weak), one that checks the client Content-Type (weak), one that validates the signature but does not reprocess the file (bypassable with a polyglot) and one that reprocesses and stores outside the webroot (robust). This analysis is part of any serious web application penetration testing.

Insecure upload versus backdoor and versus SSRF

It is worth drawing the boundaries. A webshell uploaded through a vulnerable form is, technically, a backdoor once installed, but the relevant security finding is not the persistence but the vector: the validation flaw that allowed it to be placed. The backdoor article treats the webshell from the angle of persistence and detection; here the focus is the exploitation of the upload channel and the evasion of controls.

Nor should it be confused with other flaws in the same OWASP family. In SSRF the attacker abuses the server's outbound requests, and in CSRF the trust in browser cookies. The insecure upload is a vector for injecting code into the server's file system, with an impact that is usually RCE directly.

Defensive controls

No single control solves the problem. Effective defense combines content validation with storage hardening, following the OWASP File Upload Cheat Sheet.

Content based allowlisting

Reject denylists and work with strict allowlists of expected extensions and MIME types. Validate the real content, not the extension or the client Content-Type: inspect the signature with libmagic (the file command) and, for images, reprocess them with GD or ImageMagick, which strip any embedded payload from metadata when re encoding. For office documents and PDFs, use dedicated parsers and structure validation.

Random rename and storage outside the webroot

Generate a new, unpredictable name (a UUID, for example) and keep the original name only in the database. Store files outside the web server's root, ideally in object storage (S3 or equivalent) served through signed URLs, so that they are never served from the same context that runs application code.

Disable execution in the upload directory

If files must live inside the web tree, the upload directory must not execute scripts. In Apache, disable the engine (php_admin_flag engine off) or remove the handlers; in Nginx, do not route that location to fastcgi_pass; in IIS, remove the handler mappings. At the operating system level, mount the directory without execute permission. Add X-Content-Type-Options: nosniff and serve with Content-Disposition: attachment to prevent browser interpretation.

AV/CDR scanning, limits and sandbox

Scan every file with antivirus (ClamAV or another) and, for office formats and PDFs, apply CDR (Content Disarm and Reconstruction), which neutralises macros and active content by rebuilding the file. Enforce size and rate limits, guard against decompression bombs in archives and, in sensitive environments, detonate the file in a sandbox before accepting it. A WAF adds a perimeter layer, but it does not replace validation in the application.

Fit with OWASP and CWE

An unrestricted file upload maps to CWE-434. It does not occupy its own slot in the OWASP Top 10; instead it spreads across A04:2021 (Insecure Design) for the absence of controls by design and A05:2021 (Security Misconfiguration) for storage and server configuration, while the outcome, RCE, falls into injection categories. The concrete methodological reference is in the OWASP Web Security Testing Guide, in the tests for upload of unexpected file types and of malicious files, and in the File Upload Cheat Sheet.

Public cases illustrate the impact. CVE-2018-9206 affected the widely reused jQuery File Upload component (Blueimp), enabling unrestricted upload and code execution across thousands of derived projects. CVE-2021-22005, in VMware vCenter Server, combined an arbitrary file upload with unauthenticated remote execution. And the CVE-2019-18935 family in Telerik UI showed how an upload channel, coupled with insecure deserialization, leads to RCE exploited by advanced actors. The common pattern is always the same: bypassable validation and a destination able to execute.

Frequently asked questions

Is validating the Content-Type enough to prevent an insecure upload?

No. The multipart Content-Type header is set by the client and is trivially forged with a proxy such as Burp. Reliable validation inspects the real file content (signature with libmagic, image reprocessing) and is combined with a strict extension allowlist and with storage outside the webroot.

What is a webshell and why is it so dangerous?

It is a script (PHP, ASPX, JSP) that, hosted on the server, allows commands to be run through web requests. Once uploaded and reachable, it grants the attacker remote execution with the privileges of the web process, a starting point to escalate privileges, pivot into the internal network and establish persistence like a backdoor.

How does a polyglot file evade magic byte validation?

A polyglot is a file valid for two formats at once. By prepending a legitimate image header (for example GIF89a;) to the malicious code, it passes checks like getimagesize(), which only read the first bytes, while the interpreter executes the PHP code that follows. The defense is to reprocess the image, not just read its signature.

Is a WAF enough for protection?

No. A WAF filters known patterns and adds a useful perimeter layer, but it is evaded with obfuscation and variants. Real protection lives in the application: content based allowlisting, renaming, isolated storage and disabled execution in the upload directory. The WAF complements, it does not replace.

How does it differ from a backdoor?

The backdoor describes the persistence and remote access mechanism; the insecure upload describes the vector that installs it. The same webshell can be analysed as a backdoor (persistence and detection) or as the consequence of an insecure upload (bypassed validation). Offensive auditing focuses on the vector and on closing the validation flaw.

Auditing file uploads with Secra

Secra assesses the upload channels of your applications within audits aligned with the OWASP Top 10 and the OWASP Web Security Testing Guide. We test client and server validation bypasses, Content-Type spoofing, extension lists, double extension, polyglot files and webshell execution in a controlled environment, and we verify the server's storage and execution configuration.

We deliver prioritised findings, reproducible proofs of concept and specific hardening recommendations: content based allowlisting, renaming and storage isolation, disabled execution in upload directories and AV/CDR scanning. If you need a professional review of file uploads and the rest of the web catalogue, write to us through /en/contact/ or see our web and mobile audit service.

About the author

Secra Solutions team

Ethical hackers with OSCP, OSEP, OSWE, CRTO, CRTL and CARTE certifications, 7+ years of experience in offensive cybersecurity, and authors of CVE-2025-40652 and CVE-2023-3512.

Share article