File upload handling must validate content, control storage paths and limit resource use. Saving the submitted filename directly can create a path or overwrite problem.
IN THIS ARTICLE
What you need before you begin
Decide which file types, maximum sizes and access levels the application actually needs. Identify persistent storage and the reverse proxy upload limit.
01 Upload files safely in a Flask application
Validate the incoming request and enforce a deliberate
MAX_CONTENT_LENGTH. Coordinate this with the proxy and server limits so the application can return a useful error.Generate a safe unique storage name. If retaining part of the submitted filename, use the framework-supported filename sanitization and handle empty or duplicate results.
Validate the allowed content and extension according to the feature. Keep executable content out of web-executable directories and do not treat a claimed MIME type as proof of safety.
Store private files outside direct public access and authorise downloads. Preserve uploaded files independently of application release replacement.
Test oversized, disallowed and duplicate uploads with harmless files, then verify normal uploads and cleanup of abandoned temporary data.
02 Example: test upload limits and filename sanitisation separately
In the Flask application factory, set a deliberate total request-size limit. The filename example below demonstrates a separate check; neither size control nor a cleaned filename establishes that the uploaded content is safe to process.
from werkzeug.utils import secure_filename
app.config['MAX_CONTENT_LENGTH'] = 5 * 1024 * 1024
safe_name = secure_filename('../../proposal.pdf')
# safe_name is 'proposal.pdf'
Test a harmless 3 MiB PDF and a 6 MiB file. Multipart overhead also counts toward the request limit, so do not promise that a file exactly at the threshold will fit. Validate the permitted content, generate a unique storage name, handle an empty sanitised name, and save private documents outside direct public access.
Expected result: The permitted small document follows the normal authorised workflow and the oversized request receives a controlled rejection. A filename containing directory traversal cannot choose the storage path, and another user cannot download the private document.
Confirm the expected result
Confirm files cannot escape the intended directory, replace unrelated files or be downloaded by another user without permission. Check that rejected uploads do not fill temporary storage.
Troubleshoot unexpected results
A 413 response may be generated by the proxy before Flask handles the request. Check both layers instead of only increasing the Python setting.
A common question
Does secure_filename guarantee the uploaded file is safe?
It helps create a safer filename. It does not validate the file’s content, decide who may download it or prevent every processing vulnerability.