From 6402a8480dea115f3aeccf798d2633950e02514c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 12 Nov 2025 21:48:44 +0000 Subject: [PATCH] Fix path injection and stack trace exposure vulnerabilities Co-authored-by: aiulian25 <17886483+aiulian25@users.noreply.github.com> --- backend/app.py | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/backend/app.py b/backend/app.py index cde4410..2c3e217 100644 --- a/backend/app.py +++ b/backend/app.py @@ -405,14 +405,23 @@ def download_attachment(): if not file_path: return jsonify({'error': 'No file path provided'}), 400 - full_path = os.path.join('/app/uploads', file_path) + # Normalize the file path to prevent directory traversal + file_path = os.path.normpath(file_path) - if not os.path.exists(full_path): - return jsonify({'error': 'File not found'}), 404 - - if not full_path.startswith('/app/uploads'): + # Ensure the path doesn't try to escape the uploads directory + if '..' in file_path or file_path.startswith('/'): return jsonify({'error': 'Invalid file path'}), 403 + full_path = os.path.normpath(os.path.join('/app/uploads', file_path)) + + # Double-check the resolved path is within the uploads directory + if not full_path.startswith('/app/uploads/'): + return jsonify({'error': 'Invalid file path'}), 403 + + # Check if the file exists and is actually a file (not a directory) + if not os.path.isfile(full_path): + return jsonify({'error': 'File not found'}), 404 + directory = os.path.dirname(full_path) filename = os.path.basename(full_path) @@ -427,19 +436,29 @@ def delete_attachment(): if not file_path: return jsonify({'error': 'No file path provided'}), 400 - full_path = os.path.join('/app/uploads', file_path) + # Normalize the file path to prevent directory traversal + file_path = os.path.normpath(file_path) - if not full_path.startswith('/app/uploads'): + # Ensure the path doesn't try to escape the uploads directory + if '..' in file_path or file_path.startswith('/'): return jsonify({'error': 'Invalid file path'}), 403 - if not os.path.exists(full_path): + full_path = os.path.normpath(os.path.join('/app/uploads', file_path)) + + # Double-check the resolved path is within the uploads directory + if not full_path.startswith('/app/uploads/'): + return jsonify({'error': 'Invalid file path'}), 403 + + # Check existence without revealing path details + if not os.path.isfile(full_path): return jsonify({'error': 'File not found'}), 404 try: os.remove(full_path) return jsonify({'message': 'Attachment deleted successfully'}), 200 - except Exception as e: - return jsonify({'error': f'Failed to delete attachment: {str(e)}'}), 500 + except OSError: + # Don't expose internal error details + return jsonify({'error': 'Failed to delete attachment'}), 500 @app.route('/api/vehicles/', methods=['GET', 'PUT', 'DELETE']) @login_required