File Upload Validation Guide

Learn how file upload validation fails, how attackers bypass protections, and what real exploits look like.

๐ŸŽฏ Why File Upload is Dangerous

File upload is one of the highest-risk features in web applications. If not properly validated, attackers can upload:

  • Malicious executables: .exe, .sh, .rb, .py โ†’ Remote Code Execution
  • Web shells: .php, .jsp, .asp โ†’ Execute arbitrary code on server
  • Malware: Serve malicious files to users downloading them
  • Files exploiting parsers: ZIP bombs, XXE-enabled XML, ImageMagick exploits
  • Phishing content: Fake login pages, fake documents to social engineer users
๐Ÿ’ฅ Common File Upload Validation Flaws
1. Extension Blacklist (Incomplete)

Block only common dangerous extensions but miss others:

Blacklist: ['.exe', '.sh', '.bat']
Bypass: Upload .php, .jsp, .phtml, .php3, .php4, .php5
Result: PHP file executes as code
2. Incorrect Extension Check

Validate extension incorrectly via regex or string matching:

Check: if filename doesn't end with '.php'
Bypass: shell.php.jpg โ€” some servers execute as PHP
Or: shell.jpg.php โ€” only .php is checked, not primary extension
3. MIME Type Validation (Client-Side or Weak)

Trusting Content-Type header (controlled by attacker):

Check: Accept only Content-Type: image/jpeg
Bypass: Upload .php file but set Content-Type: image/jpeg
Result: Server accepts and stores as executable PHP
4. Double Extension

Servers handle multiple extensions differently:

Intended: .jpg accepted
Upload: shell.php.jpg
Server: Apache .php.jpg โ†’ executes as PHP (most specific extension)
Result: Remote code execution
5. Null Byte Injection (Legacy)
Filename: shell.php%00.jpg
After null-byte truncation: shell.php
Result: File saved as PHP, not JPG (mostly patched in modern PHP/Python)
6. Polyglot / Polymorph Files

Create files valid in multiple formats:

A JPEG file can contain PHP code in metadata or unused JPEG sections
Server executes it as PHP โ†’ Remote code execution
๐Ÿ”ง Advanced Bypass Techniques
  • SVG with embedded script: SVG is text (XML); can contain JavaScript in <script> tags. Served as image but browser executes JS.
  • htaccess upload: Upload .htaccess to change handler; e.g., treat .jpg as PHP
  • Case sensitivity bypass: .PHP, .PhP, .pHp instead of .php (if system is case-insensitive)
  • Archive extraction: ZIP/TAR extraction without validation; path traversal via filenames like "../../shell.php"
  • .phtml, .phar, .php7, .shtml: Alternative executable extensions
โš ๏ธ Real Attack Scenarios

Scenario 1: Avatar Upload RCE โ€” User uploads profile avatar expecting image validation. Attacker uploads PHP web shell. Visits avatar URL โ†’ PHP executes โ†’ shell commands run.

Scenario 2: Resume Upload Malware โ€” Job site accepts resume uploads. Attacker uploads .exe disguised as PDF. Job seekers download it โ†’ malware installed.

Scenario 3: CSV Import Injection โ€” Admin imports user CSV. Attacker crafts CSV with formula like =cmd|'/c calc'!A1. Excel opens CSV โ†’ formula executes โ†’ RCE.

๐Ÿ›ก๏ธ How to Validate File Uploads Securely
  • โœ… Whitelist extensions (not blacklist): Only allow .jpg, .png, .gif; reject everything else
  • โœ… Validate by content, not extension: Use file magic bytes (e.g., JPEG starts with 0xFFD8FF)
  • โœ… Use dedicated library: python-magic, file command, libmagic
  • โœ… Strip metadata: Re-encode images (convert, ImageMagick) to remove embedded payloads
  • โœ… Store outside webroot: Save uploads outside /var/www; serve via download handler without execution
  • โœ… Rename files: Don't use original filename; rename to random hash (prevents .php.jpg tricks)
  • โœ… Disable execution in upload directory: Add .htaccess or nginx config to forbid script execution
  • โœ… Set restrictive permissions: chmod 644 on uploaded files; never 777 or 755
  • โœ… Limit file size: Prevent disk exhaustion attacks
  • โœ… Validate on server: Never rely on client-side validation alone
๐Ÿ“š Real-World Examples

Equifax (2017): File upload RCE (Apache Struts) led to breach of 147M records

WordPress (2019): Multiple plugin file upload vulnerabilities allowed RCE

GitLab (2021): File upload vulnerability in GitLab CI could lead to RCE

๐Ÿงช Lab Progression

Lab 00 - Blacklist Bypass: Exploit incomplete extension blacklist to upload executable code

Lab 10 - MIME Type Spoofing: Upload dangerous file while spoofing MIME type

Lab 20 - SVG Active Content: Upload SVG with embedded scripts; bypass image validation