| name | unrestricted-file-upload-anti-pattern |
| description | Security anti-pattern for unrestricted file upload vulnerabilities (CWE-434). Use when generating or reviewing code that handles file uploads, processes user-submitted files, or stores uploaded content. Detects missing extension, MIME type, and size validation. |
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
from flask import Flask, request
import os
UPLOAD_FOLDER = '/var/www/uploads'
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
filename = file.filename
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
return f'File {filename} uploaded successfully', 200
GOOD Code Example
from flask import Flask, request, jsonify
import os
import uuid
from magic import from_buffer
UPLOAD_FOLDER = '/var/www/safe_uploads'
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif', 'pdf'}
MAX_FILE_SIZE = 5 * 1024 * 1024
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 == '':
jsonify({: }),
file:
allowed_file(file.filename):
jsonify({: }),
file.seek(, os.SEEK_END)
file_length = file.tell()
file.seek()
file_length > MAX_FILE_SIZE:
jsonify({: }),
file_buffer = file.read()
file.seek()
actual_mime = from_buffer(file_buffer, mime=)
actual_mime [, , , ]:
jsonify({: }),
original_extension = file.filename.rsplit(, )[].lower()
safe_filename = (uuid.uuid4()) + + original_extension
file.save(os.path.join(app.config[], safe_filename))
jsonify({: }),
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-Type HTTP 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
Related Security Patterns & Anti-Patterns
References