AntFleet

Anatomy · 3a9ae97b-0

Path traversal in ProjectManager via unvalidated project_id

highsecurity
repo 193af03f·PR #1·reviewed 1 week ago

The vulnerable code

backend/app/models/project.py:169-175

Code snippet unavailable.

The reasoning

Opus

Path traversal in ProjectManager via unvalidated project_id

highsecurityhigh
  • 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.

Recommendation

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.

GPT-5

Project ID not validated; path traversal risk in ProjectManager and GET /api/graph/project/<project_id>

highsecuritymedium
  • backend/app/models/project.py:118-125
  • backend/app/models/project.py:150-165
  • backend/app/api/graph.py:36-52
The project_id path parameter is used directly to construct filesystem paths via os.path.join without normalization or validation, allowing traversal outside the intended project root if a crafted project_id containing ".." is supplied. The GET endpoint accepts arbitrary project_id strings and attempts to read the derived path. Even if arbitrary read is constrained by the 'project.json' suffix, traversal attempts can still cause unexpected file access or 500s. The absence of a strict project_id validator (like the simulation_id validator used elsewhere) makes this attack surface reachable.

Recommendation

- Enforce a strict project_id format (e.g., regex r"^proj_[a-f0-9]{12}$") in the HTTP layer and in ProjectManager methods. Reject invalid IDs with 400. - In ProjectManager, normalize and verify the final path stays within PROJECTS_DIR (e.g., normpath and ensure it startswith the canonical projects root path). - Consider storing metadata in a keyed index rather than filesystem-derived paths to avoid traversal risks.

The agreement

Both frontier models flagged this within the same line range. AntFleet's unanimous gate fired — the finding posted on the PR.

Closure

Tweet thread template

tweet 1 of 8144 / 280

Two frontier models reviewed PR #1 on 193af03f. Both found this bug: high security: Path traversal in ProjectManager via unvalidated project_id

tweet 2 of 8123 / 280

The vulnerable code (backend/app/models/project.py:169-175): (full snippet at https://www.antfleet.dev/anatomy/3a9ae97b-0)

tweet 3 of 8280 / 280

What Opus saw: "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 validati…

tweet 4 of 8280 / 280

What GPT-5 saw: "The project_id path parameter is used directly to construct filesystem paths via os.path.join without normalization or validation, allowing traversal outside the intended project root if a crafted project_id containing ".." is supplied. The GET endpoint accepts…

tweet 5 of 897 / 280

Both flagged the same line range. AntFleet's unanimous gate fired — the finding posted on the PR.

tweet 6 of 893 / 280

The fix landed in commit pending: (view diff at https://www.antfleet.dev/anatomy/3a9ae97b-0)

tweet 7 of 881 / 280

AntFleet reviews every PR with two frontier models. Only unanimous findings post.

tweet 8 of 877 / 280

Full anatomy + reasoning + diffs: https://www.antfleet.dev/anatomy/3a9ae97b-0

Paste into X composer one tweet at a time. X has no multi-tweet intent API.