HIGH zip slipflask
Zip Slip in Flask
Flask-Specific Remediation
Securing Flask against Zip Slip requires proper archive validation and safe extraction practices. The key is validating both the archive structure and the extraction target before writing any files.
Here's a secure Flask implementation using multiple defense layers:
from flask import Flask, request, jsonify
import zipfile
import os
from pathlib import Path
app = Flask(__name__)
UPLOAD_DIR = Path('/var/www/uploads')
MAX_ARCHIVE_SIZE = 10 * 1024 * 1024 # 10MB
# Allowlist of safe file extensions
SAFE_EXTENSIONS = {'.txt', '.pdf', '.jpg', '.png', '.csv', '.json'}
def is_safe_path(base_dir: Path, target_path: Path) -> bool:
"""Validate that target_path is within base_dir"""
try:
# Resolve both paths and check if target is within base
return str(target_path.resolve()).startswith(str(base_dir.resolve()))
except (OSError, RuntimeError):
return False
def validate_archive_entry(entry: zipfile.ZipInfo) -> bool:
"""Validate a single archive entry"""
# Check for path traversal
if '..' in entry.filename or entry.filename.startswith('/'):
return False
# Check for Windows path traversal
if '\' in entry.filename:
return False
# Check file extension against allowlist
ext = os.path.splitext(entry.filename)[1].lower()
if ext not in SAFE_EXTENSIONS:
return False
return True
@app.route('/secure-upload', methods=['POST'])
def secure_upload():
if 'file' not in request.files:
return jsonify(error='No file provided'), 400
file = request.files['file']
if file.content_length > MAX_ARCHIVE_SIZE:
return jsonify(error='File too large'), 413
if not file.filename.endswith('.zip'):
return jsonify(error='Only ZIP files allowed'), 400
# Create a temporary file for the upload
temp_path = UPLOAD_DIR / 'temp_upload.zip'
file.save(temp_path)
try:
with zipfile.ZipFile(temp_path, 'r') as zip_ref:
# First pass: validate all entries
for entry in zip_ref.infolist():
if not validate_archive_entry(entry):
return jsonify(error=f'Unsafe file in archive: {entry.filename}'), 400
# Check extraction path
target_path = UPLOAD_DIR / entry.filename
if not is_safe_path(UPLOAD_DIR, target_path):
return jsonify(error=f'Path traversal detected: {entry.filename}'), 400
# Second pass: safe extraction
for entry in zip_ref.infolist():
target_path = UPLOAD_DIR / entry.filename
target_path.parent.mkdir(parents=True, exist_ok=True)
with zip_ref.open(entry) as source, target_path.open('wb') as dest:
dest.write(source.read())
except zipfile.BadZipFile:
return jsonify(error='Invalid ZIP file'), 400
finally:
# Clean up temporary file
if temp_path.exists():
temp_path.unlink()
return jsonify(success=True, message='File uploaded securely'), 200
Key security improvements in this Flask-specific remediation:
- Path validation:
is_safe_path()ensures extracted files stay within the intended directory usingPath.resolve() - Entry validation:
validate_archive_entry()checks for traversal sequences and allows only safe file types - Two-pass extraction: First validates all entries, then extracts—prevents partial extraction of malicious files
- Safe file handling: Uses context managers and proper binary file operations
- Size limits: Prevents large archive attacks with
MAX_ARCHIVE_SIZE
For production Flask applications, consider using the zipfile.ZipFile.extract() method with explicit path validation instead of extractall(), and implement rate limiting on upload endpoints to prevent abuse.
Frequently Asked Questions
How does Zip Slip differ from other directory traversal attacks in Flask?
Zip Slip specifically exploits archive extraction where malicious paths are embedded within ZIP files. Unlike simple directory traversal via URL parameters, Zip Slip hides traversal sequences inside archives, making them harder to detect. In Flask, this is particularly dangerous because extracted Python files can be automatically reloaded, and template files in
templates/ directories are automatically discovered.Can middleBrick detect Zip Slip vulnerabilities in my Flask application?
Yes, middleBrick specifically tests for Zip Slip by uploading crafted ZIP archives containing path traversal sequences and verifying if files are written outside the intended directory. The scanner runs 12 security checks including Input Validation and Authentication bypass testing, and provides detailed findings with severity ratings and remediation guidance specific to your Flask application's implementation.