|
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,15 +330,39 @@ 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 | | - directory_name = os.path.abspath(os.path.join(concore_path, dirname)) |
| 349 | + concore_real = os.path.realpath(concore_path) |
| 350 | + directory_name = os.path.realpath(os.path.join(concore_real, dirname)) |
| 351 | + if not directory_name.startswith(concore_real + os.sep): |
| 352 | + abort(403, description="Access denied") |
335 | 353 | if not os.path.exists(directory_name): |
336 | 354 | resp = jsonify({'message': 'Directory not found'}) |
337 | 355 | resp.status_code = 400 |
338 | 356 | return resp |
| 357 | + |
| 358 | + # Ensure final resolved path is within the intended directory, resolving symlinks |
| 359 | + full_path = os.path.realpath(os.path.join(directory_name, safe_path)) |
| 360 | + if not full_path.startswith(directory_name + os.sep): |
| 361 | + abort(403, description="Access denied") |
| 362 | + |
339 | 363 | try: |
340 | | - return send_from_directory(directory_name, download_file, as_attachment=True) |
341 | | - except: |
| 364 | + return send_from_directory(directory_name, safe_path, as_attachment=True) |
| 365 | + except Exception: |
342 | 366 | resp = jsonify({'message': 'file not found'}) |
343 | 367 | resp.status_code = 400 |
344 | 368 | return resp |
|
0 commit comments