Skip to content

Commit 0fc83d0

Browse files
security: prevent path traversal in FRI /download endpoint (fixes #262)
1 parent b289c32 commit 0fc83d0

File tree

1 file changed

+23
-2
lines changed

1 file changed

+23
-2
lines changed

fri/server/main.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from flask import Flask, request, jsonify, send_file, send_from_directory
1+
from flask import Flask, request, jsonify, send_file, send_from_directory, abort
22
from werkzeug.utils import secure_filename
33
import xml.etree.ElementTree as ET
44
import os
@@ -330,14 +330,35 @@ def contribute():
330330
def download(dir):
331331
download_file = request.args.get('fetch')
332332
sub_folder = request.args.get('fetchDir')
333+
334+
if not download_file:
335+
abort(400, description="Missing file parameter")
336+
337+
# Normalize the requested file path
338+
safe_path = os.path.normpath(download_file)
339+
340+
# Prevent absolute paths
341+
if os.path.isabs(safe_path):
342+
abort(400, description="Invalid file path")
343+
344+
# Prevent directory traversal
345+
if ".." in safe_path.split(os.sep):
346+
abort(400, description="Directory traversal attempt detected")
347+
333348
dirname = secure_filename(dir) + "/" + secure_filename(sub_folder)
334349
directory_name = os.path.abspath(os.path.join(concore_path, dirname))
335350
if not os.path.exists(directory_name):
336351
resp = jsonify({'message': 'Directory not found'})
337352
resp.status_code = 400
338353
return resp
354+
355+
# Ensure final resolved path is within the intended directory
356+
full_path = os.path.abspath(os.path.join(directory_name, safe_path))
357+
if not full_path.startswith(os.path.abspath(directory_name) + os.sep):
358+
abort(403, description="Access denied")
359+
339360
try:
340-
return send_from_directory(directory_name, download_file, as_attachment=True)
361+
return send_from_directory(directory_name, safe_path, as_attachment=True)
341362
except:
342363
resp = jsonify({'message': 'file not found'})
343364
resp.status_code = 400

0 commit comments

Comments
 (0)