🚨 Severity: CRITICAL 💡 Vulnerability: The generic file hashing utility `app/utils/file_operations.py:hash_file` was vulnerable to path traversal. An attacker controlling the `filepath` argument could read arbitrary files on the system by passing relative paths like `../../../etc/passwd` or providing absolute paths directly. 🎯 Impact: This could lead to Arbitrary File Read and potential information disclosure. 🔧 Fix: Used `pathlib.Path.resolve()` to resolve both the target file path and the allowed base directory (`settings.workdir`). Added a strict check to ensure the resolved target path is strictly within the allowed boundary using `filepath_obj.relative_to(workdir_obj)`, catching the `ValueError` raised when the path is out of bounds. This safely blocks both relative traversal attacks and arbitrary absolute paths, without breaking legitimate relative application paths. ✅ Verification: Ran the test suite `pytest tests/test_path_traversal_security.py -v` successfully, which explicitly checks for `FileNotFoundError` upon traversal attempts. Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
1.1 KiB
2026-03-20 - Safe Path Traversal Prevention in Low-Level Utilities
Vulnerability: The generic file utility hash_file in app/utils/file_operations.py accepted any file path and was vulnerable to reading arbitrary files via path traversal (e.g., ../../../etc/passwd) or absolute paths if an attacker could control the filepath argument.
Learning: Naively checking for ".." in path breaks legitimate relative paths used internally by the application. Blocking absolute paths entirely also breaks functionality. Input validation should occur at the API boundary, but for defense-in-depth, low-level utilities must enforce expected boundaries (e.g., the application's workdir).
Prevention: Use pathlib.Path.resolve() on both the target path and the allowed base directory (settings.workdir). Ensure the resolved target path is strictly within the allowed boundary using filepath_obj.relative_to(workdir_obj), catching the ValueError that is raised when the path is out of bounds. This safely blocks both relative traversal attacks and arbitrary absolute paths.