You are correct.

You only need to use the secure_filename function if you are using the value of request.files['file'].filename to build a filepath destined for your filesystem - for example as an argument to os.path.join.

As you're using a UUID for the filename, the user input value is disregarded anyway.

Even without S3, it would also be safe NOT to use secure_filename if you used a UUID as the filename segment of the filepath on your local filesystem. For example:

uploaded_file = request.files['file']
if uploaded_file:
    file_uuid = uuid.uuid4()
    file.save(os.path.join(app.config['UPLOAD_FOLDER'], file_uuid))
    # Rest of code

In either scenario you'd then store the UUID somewhere in the database. Whether you store the originally provided request.files['file'].filename value alongside that is your choice.

This might make sense if you want the user to see the original name of the file when they uploaded it. In that case it's definitey wise to run the value through secure_filename anyway, so there's never a situation where the frontend displays a listing to a user which includes a file called ../../../../ohdear.txt


the secure_filename docstring also points out some other functionality:

Pass it a filename and it will return a secure version of it. This filename can then safely be stored on a regular file system and passed to :func:os.path.join. The filename returned is an ASCII only string for maximum portability. On windows systems the function also makes sure that the file is not named after one of the special device files.

>>> secure_filename("My cool movie.mov")
'My_cool_movie.mov'
>>> secure_filename("../../../etc/passwd")
'etc_passwd'
>>> secure_filename(u'i contain cool \xfcml\xe4uts.txt')
'i_contain_cool_umlauts.txt'
Answer from v25 on Stack Overflow
Top answer
1 of 1
7

You are correct.

You only need to use the secure_filename function if you are using the value of request.files['file'].filename to build a filepath destined for your filesystem - for example as an argument to os.path.join.

As you're using a UUID for the filename, the user input value is disregarded anyway.

Even without S3, it would also be safe NOT to use secure_filename if you used a UUID as the filename segment of the filepath on your local filesystem. For example:

uploaded_file = request.files['file']
if uploaded_file:
    file_uuid = uuid.uuid4()
    file.save(os.path.join(app.config['UPLOAD_FOLDER'], file_uuid))
    # Rest of code

In either scenario you'd then store the UUID somewhere in the database. Whether you store the originally provided request.files['file'].filename value alongside that is your choice.

This might make sense if you want the user to see the original name of the file when they uploaded it. In that case it's definitey wise to run the value through secure_filename anyway, so there's never a situation where the frontend displays a listing to a user which includes a file called ../../../../ohdear.txt


the secure_filename docstring also points out some other functionality:

Pass it a filename and it will return a secure version of it. This filename can then safely be stored on a regular file system and passed to :func:os.path.join. The filename returned is an ASCII only string for maximum portability. On windows systems the function also makes sure that the file is not named after one of the special device files.

>>> secure_filename("My cool movie.mov")
'My_cool_movie.mov'
>>> secure_filename("../../../etc/passwd")
'etc_passwd'
>>> secure_filename(u'i contain cool \xfcml\xe4uts.txt')
'i_contain_cool_umlauts.txt'
🌐
Medium
medium.com › @sujathamudadla1213 › what-is-the-use-of-secure-filename-in-flask-9eef4c71503b
What is the use of secure_filename in flask? | by Sujatha Mudadla | Medium
November 25, 2023 - secure_filename is a function provided by Flask's werkzeug.utils module that is used to sanitize and secure filenames before storing them on the server. This is important for security reasons.
Discussions

python - Secure user-provided filename - Stack Overflow
Part of my app requires the client to request files. Now, a well-behaved client will only request files that are safe to give, but I don't want a user to go about supplying "../../../creditCardInfo... More on stackoverflow.com
🌐 stackoverflow.com
June 2, 2017
Import Error when importing secure_filename from Werkzeug.utils : Forums : PythonAnywhere
Thank you!! 2020-06-09 19:19:39,700: Error running WSGI application 2020-06-09 19:19:39,731: ImportError: cannot import name 'secure_filename' 2020-06-09 19:19:39,731: File "/var/www/virtualta_pythonanywhere_com_wsgi.py", line 16, in 2020-06-09 19:19:39,731: from flask_app import app ... More on pythonanywhere.com
🌐 pythonanywhere.com
'Secure' Filenames
An example: if the user supplied a file name of ../../../../../boot/vmlinuz and your app was running as root -bad practice but still common - you might write over your Linux kernel with the uploaded file if your didn't sanitize the input. More on reddit.com
🌐 r/Python
4
6
January 14, 2017
python - flask_uploads: ImportError: cannot import name 'secure_filename' - Stack Overflow
Traceback (most recent call last): File "app.py", line 10, in from flask_uploads import UploadSet, configure_uploads, IMAGES File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/flask_uploads.py", line 26, in from werkzeug import secure_filename, ... More on stackoverflow.com
🌐 stackoverflow.com
🌐
Beautiful Soup
tedboy.github.io › flask › generated › werkzeug.secure_filename.html
werkzeug.secure_filename — Flask API
Pass it a filename and it will return a secure version of it. This filename can then safely be stored on a regular file system and passed to os.path.join(). The filename returned is an ASCII only string for maximum portability · On windows systems the function also makes sure that the file ...
🌐
Lublin
matrix.umcs.lublin.pl › DOC › python-flask-doc › html › patterns › fileuploads.html
Uploading Files — Flask 0.12.1 documentation
All submitted form data can be forged, and filenames can be dangerous. For the moment just remember: always use that function to secure a filename before storing it directly on the filesystem. ... So you’re interested in what that secure_filename() function does and what the problem is if ...
🌐
PythonAnywhere
pythonanywhere.com › forums › topic › 27730
Import Error when importing secure_filename from Werkzeug.utils : Forums : PythonAnywhere
from werkzeug.utils import secure_filename from flask import Flask, redirect, render_template, request, url_for from flask_bootstrap import Bootstrap from .helper import upload_file_to_s3 app = Flask(__name__) Bootstrap(app) app.config["DEBUG"] = True app.config.from_object("mysite.config") comments = [] ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'} @app.route("/", methods=["GET", "POST"]) def main(): if request.method == "GET": return render_template("main_page.html", comments=comments) comments.append(request.form["contents"]) return redirect(url_for('main')) #https://www.
🌐
HackerOne
pullrequest.com › blog › secure-file-uploads-in-flask-filtering-and-validation-techniques
Secure File Uploads in Flask: Filtering and Validation Techniques | HackerOne
March 18, 2024 - This code snippet provides a basic framework for handling file uploads, including the use of secure_filename from Werkzeug to sanitize the file name. However, this alone does not fully secure your file upload feature.
🌐
Filestack
blog.filestack.com › home › why we love flask file uploads (and you should, too!)
Why We Love Flask File Uploads (And You Should, Too!)
July 8, 2025 - You can hard code or retrieve the destination file name using the filename field of the file] request.files object. To acquire a safe version of it, however, use the secure filename() function.
Find elsewhere
🌐
PyPI
pypi.org › project › filenames-secure
filenames-secure · PyPI
Simply $ filenames_secure to obscure and restore.
      » pip install filenames-secure
    
Published   Jan 04, 2021
Version   0.0.8
🌐
Reddit
reddit.com › r/python › 'secure' filenames
r/Python on Reddit: 'Secure' Filenames
January 14, 2017 -

Flask's WSGI library werkzeug has a utility function called secure_filename - you're intended to pass the filename of a user uploaded file to it but I'm having trouble understanding what exactly the concern is, and what securing a filename could possibly entail.

The Pooco site notes

what does that secure_filename() function actually do? Now the problem is that there is that principle called “never trust user input”. This is also true for the filename of an uploaded file. All submitted form data can be forged, and filenames can be dangerous. For the moment just remember: always use that function to secure a filename before storing it directly on the filesystem.

What's returned is the exact same filename except I guess sanitized in some way. What my concern is is that I don't really understand what this function accomplishes. I plan on changing the filename of any user submitted file anyways (random uuid string with a suffix of '-small', '-large', etc.). Does it do me any good to first run the filename through secure_filename() and then change the actual filename? Can I just initially change the filename?

🌐
Medium
medium.com › @functionbasket › securing-file-upload-in-a-flask-application-and-preventing-path-traversal-attack-031fdd9e2e97
Securing file upload in a Flask Application and preventing path traversal attack | by Swadhin | Medium
January 23, 2025 - ... Assuming the path is correct, ... To mitigate this problem secure_filenamefunction can be used to sanitize and secure filenames before storing them on the server....
🌐
Debug Lab
debuglab.net › home › flask_uploads: importerror: cannot import name ‘secure_filename’
Flask_Uploads: Importerror: Cannot Import Name 'Secure_Filename' - Debug Lab
August 10, 2023 - “Fixing the ‘Flask_Uploads: ImportError: Cannot import name Secure_Filename’ error necessitates proper understanding of Flask_Uploads module, ensuring it’s correctly installed and that Secure_Filename is aptly imported to optimize SEO on your website.”I am using Flask_Uploads, a widely-used extension library for Flask.
🌐
OneUptime
oneuptime.com › home › blog › how to handle file uploads in flask
How to Handle File Uploads in Flask
February 2, 2026 - A production-ready file upload needs to validate the file type, sanitize the filename, and limit the file size. This example adds all three protections. # secure_upload.py # Secure Flask file upload with validation from flask import Flask, request, jsonify from werkzeug.utils import secure_filename import os import uuid app = Flask(__name__) # Configuration UPLOAD_FOLDER = '/var/uploads' MAX_CONTENT_LENGTH = 16 * 1024 * 1024 # 16 MB max file size ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif', 'pdf', 'doc', 'docx'} app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER app.config['MAX_CONTENT_LENGTH']
🌐
Stack Overflow
stackoverflow.com › questions › 70416975 › python-flask-deployed-on-heroku-importerror-cannot-import-name-secure-filen
Python Flask (deployed on Heroku): ImportError: cannot import name 'secure_filename' from 'werkzeug' when deploying on Heroku - Stack Overflow
Bring the best of human thought and AI automation together at your work. Explore Stack Internal ... Save this question. Show activity on this post. When deploying a flask application on heroku im getting the error above. The problem on heroku is that it installs dependencies and Iam not able to overwrite them then, or? On my local server i just went to flask_uploads.py and change the imports to: from werkzeug.utils import secure_filename from werkzeug.datastructures import FileStorage
🌐
Flask
flask.palletsprojects.com › en › stable › patterns › fileuploads
Uploading Files — Flask Documentation (3.1.x)
All submitted form data can be forged, and filenames can be dangerous. For the moment just remember: always use that function to secure a filename before storing it directly on the filesystem. ... So you’re interested in what that secure_filename() function does and what the problem is if ...
Top answer
1 of 13
105

Python:

"".join(c for c in filename if c.isalpha() or c.isdigit() or c==' ').rstrip()

this accepts Unicode characters but removes line breaks, etc.

example:

filename = u"ad\nbla'{-+\)(ç?"

gives: adblaç

edit str.isalnum() does alphanumeric on one step. – comment from queueoverflow below. danodonovan hinted on keeping a dot included.

keepcharacters = (' ','.','_')
"".join(c for c in filename if c.isalnum() or c in keepcharacters).rstrip()
2 of 13
16

I don't recommend using any of the other answers. They're bloated, use bad techniques, and replace tons of legal characters (some even removed all Unicode characters, which is nuts since they're legal in filenames). A few of them even import huge libraries just for this tiny, easy job... that's crazy.

Here's a regex one-liner which efficiently replaces every illegal filesystem character and nothing else. No libraries, no bloat, just a perfectly legal filename in one simple command.

Reference: https://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words

Regex:

clean = re.sub(r"[/\\?%*:|\"<>\x7F\x00-\x1F]", "-", dirty)

Usage:

import re

# Here's a dirty, illegal filename full of control-characters and illegal chars.
dirty = "".join(["\\[/\\?%*:|\"<>0x7F0x00-0x1F]", chr(0x1F) * 15])

# Clean it in one fell swoop.
clean = re.sub(r"[/\\?%*:|\"<>\x7F\x00-\x1F]", "-", dirty)

# Result: "-[----------0x7F0x00-0x1F]---------------"
print(clean)

This was an extreme example where almost every character is illegal, because we constructed the dirty string with the same list of characters that the regex removes, and we even padded with a bunch of "0x1F (ascii 31)" at the end just to show that it also removes illegal control-characters.

This is it. This regex is the only answer you need. It handles every illegal character on modern filesystems (Mac, Windows and Linux). Removing anything more beyond this would fall under the category of "beautifying" and has nothing to do with making legal disk filenames.


More work for Windows users:

After you've run this command, you could optionally also check the result against the list of "special device names" on Windows (a case-insensitive list of words such as "CON", "AUX", "COM0", etc).

The illegal words can be found at https://en.wikipedia.org/wiki/Filename#Comparison_of_filename_limitations in the "Reserved words" and "Comments" columns for the NTFS and FAT filesystems.

Filtering reserved words is only necessary if you plan to store the file on a NTFS or FAT-style disk. Because Windows reserves certain "magic filenames" for internal usage. It reserves them case-insensitively and without caring about the extension, meaning that for example aux.c is an illegal filename on Windows (very silly).

All Mac/Linux filesystems don't have silly limitations like that, so you don't have to do anything else if you're on a good filesystem. Heck, in fact, most of the "illegal characters" we filtered out in the regex are Windows-specific limitations. Mac/Linux filesystems can store most of them. But we filter them anyway since it makes the filenames portable to Windows machines.