Skip to content

Secure Filenames

Never trust a user-provided filename.

Attackers can try things like:

  • ../../etc/passwd
  • special characters that break file systems

Flask/Werkzeug provides secure_filename().

diagram what a user-supplied filename can do, and what secure_filename leaves mermaid
A filename arrives as a string the attacker chose. If it is joined onto an upload directory unchecked, path segments in it escape that directory and the write lands somewhere else. secure_filename strips the path, normalises the characters and leaves a flat name -- which is necessary, and on its own not sufficient.
python
import os
from werkzeug.utils import secure_filename
from flask import Flask, request
 
app = Flask(__name__)
 
UPLOAD_FOLDER = "uploads"
 
 
@app.route("/upload", methods=["POST"])
def upload():
    file = request.files.get("photo")
    if not file:
        return "No file", 400
 
    filename = secure_filename(file.filename)
    os.makedirs(UPLOAD_FOLDER, exist_ok=True)
    save_path = os.path.join(UPLOAD_FOLDER, filename)
    file.save(save_path)
 
    return {"saved_as": filename}, 201
  • Rename uploaded files (UUID) instead of using original name
  • Store metadata in DB (who uploaded, when, original name)
  • Set an upload size limit (MAX_CONTENT_LENGTH)
  • Validate extensions and MIME type
  • Consider storing files in object storage (S3) rather than the app server

pch.coffeeTagline

pch.coffeeCta

pch.feedbackHeading

pch.feedbackSubheading