scanrub
Unrestricted Upload of File with Dangerous Typemedium prioritypartial coverage

Unrestricted File Upload

3 min read 11 reports analyzed ScanRub Research
Share

Summary

File upload validation that only checks a file's extension is trivially bypassed a handful of well-documented ways: manipulating the Content-Type header sent alongside the file, since some validators trust that header instead of inspecting the file itself; uploading an HTML or SVG file that gets served back with a content type the browser will render, turning a simple upload into stored XSS; and, most severely, uploading a server-side scriptable file (PHP, JSP, ASP) that the web server will execute if it lands somewhere reachable. Common bypass techniques for extension-based filters include double extensions (shell.php.jpg), null-byte injection, and case-mixing (shell.PHP) against filters that only check for lowercase matches. A less obvious but real escalation path: uploading a file that isn't executable code at all, but is a malicious driver or plugin file (a crafted SQLite JDBC driver, for instance) that a downstream service loads and executes when it processes the upload.

◈ flow diagram
Malicious FileUpload Endpo…Insufficient…Server StorageFile ExecutionRCE
◈ chart
Critical
1
High
3
Medium
5
Low
3

Top Affected Components / Targets

  • Profile picture / avatar upload
  • Document attachment upload
  • Theme / template asset upload
  • Email-signature upload
  • Bug-report attachment upload

Common Attack Vectors

  • Upload .php with image Content-Type
  • Upload shell.php.png (double extension)
  • Upload shell.php%00.png (null byte)
  • Upload .phtml / .asp;.png / .aspx variants
  • Upload .html with embedded XSS
  • Upload .svg with embedded script
  • Upload SQLite database as JDBC driver source

Common Payloads

  • shell.php, shell.php.png, shell.php%00.png
  • shell.phtml, shell.asp;.png
  • <?php system($_GET['c']); ?>
  • <svg onload=alert(1)>
  • <html><script>alert(1)</script></html>
  • Content-Type: image/jpeg trick (Content-Type rejected but file extension allowed)
  • Content-Type: text/html; image/png (header trick)

Detection Strategy

Extension-bypass and content-type manipulation testing covers the code-execution path, while checking whether an uploaded HTML or SVG file gets served with a content type that lets the browser render it (rather than forcing a download) covers the stored-XSS variant of the same underlying bug: both trace back to the same missing content-type enforcement on upload.

Tip: Testing tools that run these checks in parallel across every discovered endpoint can cut the time required substantially compared to fully manual testing, as long as they confirm findings with more than one signal to keep the false-positive rate down.

False-Positive Notes

Same as the parent syntheses.

How to Test

Manual Testing Methodology

Here is a systematic approach to identifying Unrestricted File Upload vulnerabilities in a target application.

Step 1: Reconnaissance and Surface Mapping

Before testing, map all input vectors that could be affected. Identify parameters, headers, cookies, and request bodies that interact with the vulnerable component. A proxy such as Burp Suite or OWASP ZAP, paired with normal browsing of the target, is usually enough to build this list.

Step 2: Baseline Request

Send a legitimate request and record the normal response: status code, content length, response time, and any identifying tokens. This baseline matters because it's what you'll compare later responses against once payloads are involved.

Step 3: Payload Injection

Inject test payloads into each identified input vector one at a time. Start with benign detection payloads before escalating to anything that could actually trigger the vulnerability. For Unrestricted File Upload specifically, attempt to upload a file with a dangerous extension disguised via double extensions (shell.php.jpg), null bytes, case variation, or a mismatched declared Content-Type, and separately test whether an accepted file type (like SVG or HTML) can carry an embedded script.

Step 4: Response Analysis

Compare the response against your baseline, looking specifically for whether the uploaded file is reachable at a predictable or discoverable URL and executes as code (or renders as active content) rather than being served as inert data.

Step 5: Confirmation

Once a potential vulnerability is detected, confirm it with at least a few independent test cases to rule out coincidence. Document the exact request and response as proof. For Unrestricted File Upload, a confirmed finding typically means showing that attacker-controlled input changes the application's behavior in a way that matters for security, not just that a payload was reflected somewhere harmless.

Real-World Impact

Real-World Impact

Unrestricted file upload lets an attacker place a file of their choosing — most dangerously, an executable script — somewhere the application will later serve or execute it, which typically leads directly to remote code execution on the server. Even where execution isn't achieved, unrestricted uploads enable stored XSS (an uploaded HTML or SVG file rendered inline), storage exhaustion, and malware distribution through a trusted domain.

The most severe outcomes come from bypassing extension- or MIME-type-based validation, since both are attacker-controlled and easy to spoof; the actual file content is what matters, and a validation check that only inspects the declared extension or Content-Type header is trivially bypassed.

Web shells planted through an unrestricted upload are a common initial-access technique in real breaches specifically because they give the attacker an ongoing, interactive foothold rather than a one-time exploit.

Prevention & Remediation

Prevention and Secure Coding

Preventing Unrestricted File Upload takes a defense-in-depth approach — no single control below is sufficient alone, but together they close off both the primary path and the most common bypasses.

Validate by content, not extension or declared type. Check the actual file content (magic bytes, and where relevant, a full parse of the file structure) rather than trusting the client-supplied filename extension or Content-Type header, both of which are trivially attacker-controlled.

Store uploads outside the webroot or in non-executable storage. Uploaded files should live somewhere the web server won't execute as a script even if a malicious file gets through validation — object storage without execute permissions, or a directory the web server config explicitly won't interpret as code.

Regenerate filenames server-side. Never reuse a client-supplied filename directly; generate a new one server-side to eliminate path-traversal and extension-confusion tricks embedded in the original name.

Restrict by allowlist, not denylist. Accept only explicitly allowed file types for the feature in question rather than trying to block a list of dangerous extensions, which is easy to bypass with alternate extensions the denylist didn't anticipate.

Scan uploads where the risk profile warrants it. For applications handling uploads from untrusted or semi-trusted users at scale, malware scanning adds a meaningful additional layer.

Source reports

A sample of the disclosed HackerOne reports this playbook was synthesized from.

Frequently Asked Questions

What is Unrestricted File Upload?
File upload validation that only checks a file's extension is trivially bypassed a handful of well-documented ways: manipulating the Content-Type header sent alongside the file, since some validators trust that header instead of inspecting the file itself; uploading an HTML or SVG file that gets served back with a content type the browser will render, turning a simple upload into stored XSS; and, most severely, uploading a server-side scriptable file (PHP, JSP, ASP) that the web server will execute if it lands somewhere reachable.
How common is Unrestricted File Upload in bug bounty reports?
Scanrub's research corpus for this playbook is built from 11 disclosed HackerOne reports in this category, synthesized for detection and prevention guidance rather than reproduced verbatim.
How do I test for Unrestricted File Upload?
Map every input vector, record a baseline response, then inject targeted test payloads one field at a time and compare the response for timing, length, error, or reflection differences from that baseline. The "How to Test" section above walks through the full methodology for this specific vulnerability class.
What is the single most effective fix for Unrestricted File Upload?
Validate uploaded files by actual content (magic bytes), not extension or declared MIME type, and store them outside the webroot or in storage with no execute permission.
Weekly security research

New vulnerability playbooks, tool updates, and bug bounty insights - delivered to your inbox. No spam.

Unsubscribe anytime. We respect your inbox.
Press ⌘K to search×