diff --git a/.Jules/sentinel.md b/.Jules/sentinel.md new file mode 100644 index 00000000..da3742a6 --- /dev/null +++ b/.Jules/sentinel.md @@ -0,0 +1,4 @@ +## 2024-03-24 - [Information Leakage in Python Exception Handling] +**Vulnerability:** Raw exception strings containing internal file paths and system details were being serialized into JSON responses (e.g., `f"Failed to read job file: {e}"`). +**Learning:** Catch-all exception blocks (like `except Exception as e:`) can inadvertently expose sensitive system state to end users if the string representation of the exception is returned directly. +**Prevention:** Replace raw exception interpolations with generic, safe error messages intended for external consumption, logging the full stack trace internally if needed. diff --git a/services/analysis-engine/src/bandscope_analysis/api.py b/services/analysis-engine/src/bandscope_analysis/api.py index a193bce2..9e99521a 100644 --- a/services/analysis-engine/src/bandscope_analysis/api.py +++ b/services/analysis-engine/src/bandscope_analysis/api.py @@ -840,8 +840,8 @@ def _stem_separation_worker( result_queue.put(("value_error", str(error))) except RuntimeError as error: result_queue.put(("runtime_error", str(error))) - except Exception as error: - result_queue.put(("runtime_error", str(error))) + except Exception: + result_queue.put(("runtime_error", "An unexpected error occurred during stem separation.")) def _multiprocessing_context() -> mp.context.BaseContext: diff --git a/services/analysis-engine/src/bandscope_analysis/cli.py b/services/analysis-engine/src/bandscope_analysis/cli.py index c73f311d..390fe78f 100644 --- a/services/analysis-engine/src/bandscope_analysis/cli.py +++ b/services/analysis-engine/src/bandscope_analysis/cli.py @@ -46,8 +46,12 @@ def main() -> int: try: with open(input_data, "r", encoding="utf-8") as f: input_data = f.read() - except Exception as e: - json.dump(failed_cli_response(f"Failed to read job file: {e}"), sys.stdout) + except Exception: + msg = ( + "Failed to read job file. " + "Please ensure the file path is correct and accessible." + ) + json.dump(failed_cli_response(msg), sys.stdout) return 1 if not input_data: diff --git a/services/analysis-engine/tests/test_api.py b/services/analysis-engine/tests/test_api.py index ea55cba2..bfd6de56 100644 --- a/services/analysis-engine/tests/test_api.py +++ b/services/analysis-engine/tests/test_api.py @@ -848,18 +848,22 @@ def put(self, item: tuple[str, object]) -> None: self.items.append(item) cases = [ - (FileNotFoundError("missing"), "file_not_found"), - (ValueError("bad media"), "value_error"), - (RuntimeError("oom"), "runtime_error"), - (Exception("unexpected"), "runtime_error"), + (FileNotFoundError("missing"), "file_not_found", "missing"), + (ValueError("bad media"), "value_error", "bad media"), + (RuntimeError("oom"), "runtime_error", "oom"), + ( + Exception("unexpected"), + "runtime_error", + "An unexpected error occurred during stem separation.", + ), ] - for error, expected_kind in cases: + for error, expected_kind, expected_msg in cases: fake_queue = FakeQueue() with patch("bandscope_analysis.api.AudioStemSeparator") as separator_class: separator_class.return_value.separate.side_effect = error _stem_separation_worker("/tmp/audio.wav", fake_queue) - assert fake_queue.items == [(expected_kind, str(error))] + assert fake_queue.items == [(expected_kind, expected_msg)] fake_queue = FakeQueue() with patch("bandscope_analysis.api.AudioStemSeparator") as separator_class: