Receipt · 3a9ae97b-0
Path traversal in ProjectManager via unvalidated project_id
The finding
- backend/app/models/project.py:169-175
- backend/app/models/project.py:245-260
- backend/app/models/project.py:286-296
- backend/app/api/graph.py:39-53
ProjectManager methods (_get_project_dir, _get_project_meta_path, _get_project_files_dir, _get_project_text_path, delete_project, save_extracted_text, save_file_to_project) all build filesystem paths by os.path.join(PROJECTS_DIR, project_id) without any validation that project_id is a safe identifier. The route `GET /api/graph/project/<project_id>` and the POST body of `/api/graph/build` accept arbitrary project_id strings and forward them straight to ProjectManager.get_project. A caller passing `project_id='../../something'` (allowed because Flask's default `<string>` converter accepts dots and slashes? — actually `<string>` disallows `/`, but JSON bodies in `/build` have no such constraint, and `..` alone is allowed even by the URL converter) causes the server to read/write/shutil.rmtree files outside the projects directory. Unlike report.py and share.py which use `validate_simulation_id`, no analogous validate_project_id exists. delete_project is especially dangerous because it shutil.rmtree's a path derived from user input.
Fix
Add a `validate_project_id` helper (mirroring `utils.validation.validate_simulation_id`) that enforces a strict regex like `^proj_[a-z0-9]{12}$`, and call it at the entry of every API route that takes project_id and inside ProjectManager.get_project / delete_project / save_file_to_project as defense in depth.
Agent attribution
The agents that produced this receipt — both reviewer models had to flag this independently for the agreement gate to emit it.
anthropic
gpt-5
119.3s · error
openai
claude-opus-4-7
121.8s · error
Total
wall-clock review time · est. inference cost
121.8s · $0.40
Sweeper
closed at SHA
still open
internal review id · 3a9ae97b
Third-party witnesses
Everything below lives on GitHub's event log, not ours. Click any link to verify the SHA, the timestamp, and the surrounding context for yourself.
Original review comment
https://github.com/AntFleet/miroshark-bench/pull/1#issuecomment-4524519515