|
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 |
2 | 2 | from werkzeug.utils import secure_filename |
3 | 3 | import xml.etree.ElementTree as ET |
4 | 4 | import os |
@@ -330,14 +330,35 @@ def contribute(): |
330 | 330 | def download(dir): |
331 | 331 | download_file = request.args.get('fetch') |
332 | 332 | 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 | + |
333 | 348 | dirname = secure_filename(dir) + "/" + secure_filename(sub_folder) |
334 | 349 | directory_name = os.path.abspath(os.path.join(concore_path, dirname)) |
335 | 350 | if not os.path.exists(directory_name): |
336 | 351 | resp = jsonify({'message': 'Directory not found'}) |
337 | 352 | resp.status_code = 400 |
338 | 353 | 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 | + |
339 | 360 | 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) |
341 | 362 | except: |
342 | 363 | resp = jsonify({'message': 'file not found'}) |
343 | 364 | resp.status_code = 400 |
|
0 commit comments