RSTR-PTH-001 — Flask send_file(request.*)

Summary

A Flask handler calls send_file (or send_from_directory with the path on the wrong argument) using a path derived directly from request input. An attacker submits ../../etc/passwd and the server happily reads and returns that file.

Severity

High.

Languages

Python (Flask / Quart).

What rastray flags

@app.route('/download')
def download():
    return send_file(request.args['path'])         # ← flagged
@app.route('/file')
def file():
    return send_file(f'./uploads/{request.args["name"]}')   # ← flagged

What rastray deliberately does not flag

  • send_from_directory(safe_dir, secure_filename(name)) (the documented safe form).
  • send_file(...) with a constant path.

How to fix it

Use send_from_directory with werkzeug.utils.secure_filename:

from flask import send_from_directory
from werkzeug.utils import secure_filename

@app.route('/file/<name>')
def file(name):
    return send_from_directory(
        directory='./uploads',
        path=secure_filename(name),
    )

For multi-tenant uploads, also confirm the resolved path stays inside the intended base directory:

import os
base = os.path.realpath('./uploads')
target = os.path.realpath(os.path.join(base, secure_filename(name)))
if not target.startswith(base + os.sep):
    abort(404)

secure_filename only strips path separators and a handful of unsafe chars — the realpath check catches symlink shenanigans.

References