Skip to content

[Bug] Path traversal in case-run delete/download routes can escape selected case directory #430

@lil-aditya

Description

@lil-aditya

Summary

The DataFile case-run routes allowed path traversal payloads to escape the selected case/run directory while still remaining inside Config.DATA_STORAGE.

Examples:

  • POST /deleteCaseRun accepted a caserunname like ../../victim_case.
  • GET /downloadFile accepted a file value like ../../../victim_case/genData.json.

Because the previous guard validated against the broad DATA_STORAGE root, these payloads could still resolve inside storage but outside the intended selected case/run folder. Expected behavior is that traversal outside the selected case/run directory is rejected with 400 Invalid path. and no sibling case data is deleted or downloaded.

How can we reproduce it?

  1. Create two cases in data storage, for example source_case and victim_case.
  2. For delete behavior, send:
    POST /deleteCaseRun
    {
      "casename": "source_case",
      "caserunname": "../../victim_case",
      "resultsOnly": false
    }
  3. For download behavior, set the active session case to source_case and request:
    GET /downloadFile?file=../../../victim_case/genData.json
  4. Before the fix, the path could resolve to the sibling victim_case under DATA_STORAGE.
  5. After the fix, the route returns:
    {
    "message": "Invalid path.",
    "status_code": "error"
    }

Logs or screenshots (optional)

Validation command:

.\venv\Scripts\python.exe -m pytest tests\test_datafile_guards.py -q

Output:
platform win32 -- Python 3.11.9, pytest-9.0.2, pluggy-1.6.0
collected 3 items

tests\test_datafile_guards.py ... [100%]

3 passed, 1 warning in 0.63s
the warning was only a local pytest cache permission warning for .pytest_cache; the tests passed.

## Overlap assessment

- Classification: Partial thematic overlap, not duplicate.
- Overlapping items: Path traversal/path sanitization concerns.
- Why this is not duplicate/superseded: This PR fixes a different route and attack surface: `deleteCaseRun`, `downloadDataFile`, `downloadFile`, `downloadCSVFile`, and `downloadResultsFile` in `DataFileRoute.py`. The related PRs focus on ZIP extraction or backup archive generation in `UploadRoute.py`, so they do not cover sibling case traversal through case-run/download parameters.



Validate untrusted path segments relative to the narrow intended parent directory instead of only validating against `Config.DATA_STORAGE`.

The proposed patch:
- Adds `_safe_child_path(...)` for nested path validation.
- Validates case-run names relative to `<DATA_STORAGE>/<case>/res`.
- Validates CSV/download filenames relative to the specific `csv` or case-run directory.
- Returns `400 Invalid path.` on `PermissionError`.
- Adds regression tests proving valid delete still works and traversal attempts are blocked.

Metadata

Metadata

Assignees

No one assigned

    Labels

    DeferredNot prioritized for now; revisit laterSecuritySecurity hardening or vulnerability fixbugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status
    In progress

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions