unrestricted-file-upload-anti-pattern
Unrestricted File Upload Anti-Pattern
Severity: Critical
Summary
Applications accept user-uploaded files without validating type, content, or size, enabling attackers to upload malicious scripts or executables. Leads to remote code execution (web shells), server compromise, or denial-of-service (disk exhaustion).
The Anti-Pattern
The anti-pattern is accepting uploaded files without validating type, content, and size.
BAD Code Example
# VULNERABLE: No validation of file type, content, or size.
from flask import Flask, request
import os
UPLOAD_FOLDER = '/var/www/uploads' # This directory might be accessible by the web server.
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
@app.route('/upload', methods=['POST'])
def upload_file():
if 'file' not in request.files:
return 'No file part', 400
file = request.files['file']
if file.filename == '':
return 'No selected file', 400
# CRITICAL FLAW: The application takes the filename as is and saves the file.
# An attacker can upload a file named `shell.php` with PHP code.
# If the `UPLOAD_FOLDER` is web-accessible and PHP is executed,
# the attacker achieves Remote Code Execution.
filename = file.filename
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
return f'File {filename} uploaded successfully', 200
# Attack Scenario:
# 1. Attacker crafts a PHP file named `shell.php` containing `<?php system($_GET['cmd']); ?>`.
# 2. Attacker uploads `shell.php` via this endpoint.
# 3. Attacker accesses `http://your-app.com/uploads/shell.php?cmd=ls%20-la`
# and can now execute arbitrary commands on the server.
GOOD Code Example
# SECURE: Implement a multi-layered validation approach for file uploads.
from flask import Flask, request, jsonify
import os
import uuid # For generating unique filenames
from magic import from_buffer # `python-magic` for magic byte detection
UPLOAD_FOLDER = '/var/www/safe_uploads' # Store files outside the web root.
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif', 'pdf'}
MAX_FILE_SIZE = 5 * 1024 * 1024 # 5 MB
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
@app.route('/upload/secure', methods=['POST'])
def upload_file_secure():
if 'file' not in request.files:
return jsonify({'error': 'No file part'}), 400
file = request.files['file']
if file.filename == '':
return jsonify({'error': 'No selected file'}), 400
if file:
# 1. Validate file extension (allowlist approach).
if not allowed_file(file.filename):
return jsonify({'error': 'File type not allowed'}), 400
# 2. Validate file size.
file.seek(0, os.SEEK_END)
file_length = file.tell()
file.seek(0)
if file_length > MAX_FILE_SIZE:
return jsonify({'error': 'File too large'}), 400
# 3. Validate actual MIME type using magic bytes (more reliable than Content-Type header).
file_buffer = file.read(1024) # Read a chunk for magic byte detection
file.seek(0) # Reset file pointer
actual_mime = from_buffer(file_buffer, mime=True)
if actual_mime not in ['image/png', 'image/jpeg', 'image/gif', 'application/pdf']:
return jsonify({'error': f'Invalid file content type: {actual_mime}'}), 400
# 4. Generate a unique and safe filename. Never use the original filename directly.
original_extension = file.filename.rsplit('.', 1)[1].lower()
safe_filename = str(uuid.uuid4()) + '.' + original_extension
# 5. Store the file in a secure location, preferably outside the web root.
file.save(os.path.join(app.config['UPLOAD_FOLDER'], safe_filename))
return jsonify({'message': f'File {safe_filename} uploaded successfully'}), 200
Detection
- Review file upload handlers: Identify all endpoints that allow users to upload files.
- Check validation logic: Examine how filenames, file types, and file contents are validated. Look for:
- Missing extension checks or using blocklists instead of allowlists.
- Relying solely on the
Content-TypeHTTP header, which is easily spoofed. - Not checking the actual content of the file (magic bytes).
- Missing size limits.
- Inspect storage location: Determine where uploaded files are stored. Are they in a web-accessible directory? Can executables be run from there?
Prevention
- Strict allowlist for file extensions: Allow only specific safe extensions (
.png,.jpg,.pdf). Never use blocklists. - Verify file content (magic bytes): Inspect first bytes to determine true file type. Never trust client-provided
Content-Typeheader. - Enforce file size limits: Set maximum file size to prevent DoS and resource exhaustion.
- Generate unique, random filenames: Use cryptographically secure random filenames. Never use user-provided filenames (prevents path traversal and overwrites).
- Store files outside web root: Store uploads in non-web-accessible directories. Serve through controlled handlers.
- Set no-execute permissions: Configure upload directory with no-execute permissions to block web shell execution.
- Scan for malware: Integrate antivirus/malware scanner for all uploads.
Related Security Patterns & Anti-Patterns
- Path Traversal Anti-Pattern: Attackers can try to use directory traversal sequences (
../) in the filename to write files to unintended locations. - Command Injection Anti-Pattern: If an uploaded file is later processed by a system command, it can lead to command injection.
- Cross-Site Scripting (XSS) Anti-Pattern: Malicious HTML or SVG files can be uploaded to perform XSS attacks.
References
- OWASP Top 10 A06:2025 - Insecure Design
- OWASP GenAI LLM10:2025 - Unbounded Consumption
- OWASP API Security API4:2023 - Unrestricted Resource Consumption
- OWASP File Upload Cheat Sheet
- CWE-434: Unrestricted Upload of File with Dangerous Type
- CAPEC-1: Accessing Functionality Not Properly Constrained by ACLs
- PortSwigger: File Upload
- Source: sec-context
More from igbuend/grimbard
tikz
LaTeX TikZ/PGF package for programmatic vector graphics and diagrams. Use when helping users draw flowcharts, trees, graphs, automata, circuits, geometric figures, or any custom diagram in LaTeX.
91latex
Comprehensive LaTeX reference for document creation, formatting, mathematics, tables, figures, bibliographies, and compilation. Use when helping users write, edit, debug, or compile LaTeX documents.
37pgfplots
LaTeX pgfplots package for data visualization and plotting. Use when helping users create line plots, bar charts, scatter plots, histograms, 3D surfaces, or any scientific/data plot in LaTeX.
31ethical-hacking-ethics
Legal and ethical guidelines for bug bounties, pentesting, and security research. Use when conducting authorized security testing.
12codebase-discovery
Generate security-focused DISCOVERY.md for code review and threat modeling. Use when assessing unfamiliar codebases.
11weak-encryption-anti-pattern
Security anti-pattern for weak encryption (CWE-326, CWE-327). Use when generating or reviewing code that encrypts data, handles encryption keys, or uses cryptographic modes. Detects DES, ECB mode, static IVs, and custom crypto implementations.
11