From 9d65707f0e373007d68165081370c68be3329fee Mon Sep 17 00:00:00 2001 From: Bhavisha Dawada Date: Wed, 8 Oct 2025 18:48:16 -0400 Subject: [PATCH 1/5] Fix information exposure through exception --- src/backend/exceptions/handlers/exception_handlers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backend/exceptions/handlers/exception_handlers.py b/src/backend/exceptions/handlers/exception_handlers.py index 21d9e26..c0a7147 100644 --- a/src/backend/exceptions/handlers/exception_handlers.py +++ b/src/backend/exceptions/handlers/exception_handlers.py @@ -73,8 +73,8 @@ async def unhandled_exception_handler(request: Request, exc: Exception) -> JSONR exception_name = getattr(exception_type, "__name__", None) logger.error("Uncaught Exception", exc_info=(exception_type, exception_value, exception_traceback)) - - return JSONResponse({'message': f"Internal Server Error. Error: '{exception_name}: {exception_value}.'", 'request_id': get_request_id()}, status_code=500) + return JSONResponse({'message': "Internal Server Error. Please contact admin.", 'request_id': get_request_id()}, status_code=500) + #return JSONResponse({'message': f"Internal Server Error. Error: '{exception_name}: {exception_value}.'", 'request_id': get_request_id()}, status_code=500) def api_exception_logger(request: Request, exc): url = f"{request.url.path}?{request.query_params}" if request.query_params else request.url.path From d450881362a6f8ac77e6f5715a8e3d0f12dcef2e Mon Sep 17 00:00:00 2001 From: Bhavisha Dawada Date: Wed, 8 Oct 2025 19:11:16 -0400 Subject: [PATCH 2/5] Too few arguments to formatting function Can be removed. --- .../docs/samples/C++/MessageBroker/message_broker_sample.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/edgemlsdk/src/docs/samples/C++/MessageBroker/message_broker_sample.cpp b/src/edgemlsdk/src/docs/samples/C++/MessageBroker/message_broker_sample.cpp index 42ff98f..bf6bcb9 100644 --- a/src/edgemlsdk/src/docs/samples/C++/MessageBroker/message_broker_sample.cpp +++ b/src/edgemlsdk/src/docs/samples/C++/MessageBroker/message_broker_sample.cpp @@ -91,7 +91,7 @@ int main() // Will be invoked when mqtt topic 'broker-test-subscription' is published too CHECKHR(broker->Subscribe("test-subscription", [&](IPayload* payload) { - TraceInfo("Received message: %s", payload->SerializeAsString()); + TraceInfo("Received message: %s", payload->SerializeAsString()..c_str()); })); int32_t test_subscription_cancellation_token = hr; @@ -100,7 +100,7 @@ int main() // when a publish happens with message_id = `test_message` CHECKHR(broker->Subscribe("test_message", [&](IPayload* payload) { - TraceInfo("Received locally: %s", payload->SerializeAsString()); + TraceInfo("Received locally: %s", payload->SerializeAsString().c_str()); })); int32_t test_message_cancellation_token = hr; From d24238ed1b74eaacb3d1362ca88006396afc1730 Mon Sep 17 00:00:00 2001 From: Bhavisha Dawada Date: Wed, 8 Oct 2025 19:20:17 -0400 Subject: [PATCH 3/5] Fix path injection vulnerability in snapshot file download - Sanitize user-controlled fileName parameter to prevent directory traversal - Add os.path.basename() to remove path components from filename - Validate filename contains no '..' or path separators - Add directory boundary check to ensure resolved path stays within DDA_SYSTEM_FOLDER - Addresses CodeQL rule py/path-injection - Prevents attacks like '../../../etc/passwd' from accessing system files --- src/backend/endpoints/download_file.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/backend/endpoints/download_file.py b/src/backend/endpoints/download_file.py index 767dc37..e2cd96f 100644 --- a/src/backend/endpoints/download_file.py +++ b/src/backend/endpoints/download_file.py @@ -81,7 +81,24 @@ def get_snapshotfile( token: str = None ): validate_token_in_query_param(token) - file_path = os.path.join(DDA_SYSTEM_FOLDER, fileName) + + # Sanitize filename to prevent path traversal + safe_filename = os.path.basename(fileName) + if safe_filename != fileName or '..' in fileName: + raise HTTPException( + status_code=400, + detail="Invalid filename" + ) + + file_path = os.path.join(DDA_SYSTEM_FOLDER, safe_filename) + + # Ensure the resolved path is within the allowed directory + if not os.path.abspath(file_path).startswith(os.path.abspath(DDA_SYSTEM_FOLDER)): + raise HTTPException( + status_code=400, + detail="Access denied" + ) + if os.path.exists(file_path): return FileResponse(file_path) From b39778b93fc3bad3d6d51e78a25d537c39294df7 Mon Sep 17 00:00:00 2001 From: Bhavisha Dawada Date: Wed, 8 Oct 2025 19:24:23 -0400 Subject: [PATCH 4/5] security: fix path injection vulnerability in captureIdPath parameter - Add path sanitization using os.path.basename() - Validate against directory traversal patterns (.., path separators) - Enforce directory boundary checks within DDA_SYSTEM_FOLDER - Addresses CodeQL rule py/path-injection --- src/backend/endpoints/download_file.py | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/backend/endpoints/download_file.py b/src/backend/endpoints/download_file.py index e2cd96f..fa5cd70 100644 --- a/src/backend/endpoints/download_file.py +++ b/src/backend/endpoints/download_file.py @@ -201,12 +201,30 @@ def get_inference_result_data_for_retraining( # First, POST to /workflows/{workflow_id}/results/export, which writes out the data to a file on disk # Then, GET from /workflows/{workflow_id}/results/export (here), which loads the data from said file on disk if captureIdPath: - if not os.path.exists(captureIdPath): + # Sanitize path to prevent directory traversal + safe_path = os.path.basename(captureIdPath) + if safe_path != captureIdPath or '..' in captureIdPath or os.path.sep in safe_path: + raise HTTPException( + status_code=400, + detail="Invalid file path" + ) + + # Construct full path within allowed directory + full_path = os.path.join(DDA_SYSTEM_FOLDER, safe_path) + + # Ensure resolved path stays within DDA_SYSTEM_FOLDER + if not os.path.abspath(full_path).startswith(os.path.abspath(DDA_SYSTEM_FOLDER)): + raise HTTPException( + status_code=400, + detail="Access denied" + ) + + if not os.path.exists(full_path): raise HTTPException( status_code=HTTP_404_NOT_FOUND, - detail=f"The server can't get the capture id file. Error: 'The path {captureIdPath} couldn't be found'. Check the path and try again.", + detail="File not found", ) - with open(captureIdPath) as json_file: + with open(full_path) as json_file: inference_result_data_list = json.load(json_file) else: # Regular case, query the data ourselves From 1378432291beee40d74ecdda7279e800ceaee2db Mon Sep 17 00:00:00 2001 From: Bhavisha Dawada Date: Wed, 8 Oct 2025 19:26:12 -0400 Subject: [PATCH 5/5] security: fix path injection vulnerability in jsonl file path construction - Add sanitization for workflowId and captureId parameters - Validate against directory traversal patterns (.., path separators) - Use sanitized components in jsonl file path construction - Addresses CodeQL rule py/path-injection for line 108 --- src/backend/endpoints/download_file.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/backend/endpoints/download_file.py b/src/backend/endpoints/download_file.py index fa5cd70..47775ea 100644 --- a/src/backend/endpoints/download_file.py +++ b/src/backend/endpoints/download_file.py @@ -120,7 +120,18 @@ def load_input_image_from_worflow_by_capture_id(workflowId: str, captureId: str, capture_details = inference_result_accessor.get_inference_result(db, captureId) if capture_details is None: logger.info("Getting image from jsonl file") - jsonl_file = f"/aws_dda/inference-results/{workflowId}/{captureId}.jsonl" + # Sanitize path components to prevent directory traversal + safe_workflow_id = os.path.basename(workflowId) + safe_capture_id = os.path.basename(captureId) + if (safe_workflow_id != workflowId or safe_capture_id != captureId or + '..' in workflowId or '..' in captureId or + os.path.sep in safe_workflow_id or os.path.sep in safe_capture_id): + raise HTTPException( + status_code=400, + detail="Invalid workflow or capture ID" + ) + + jsonl_file = f"/aws_dda/inference-results/{safe_workflow_id}/{safe_capture_id}.jsonl" try: with open(jsonl_file, 'r') as f: json_str = f.read()