Skip to content

fix(interface): prevent path traversal and argument injection in clone_repository - #1157

Open
Gracy769 wants to merge 2 commits into
usestrix:mainfrom
Gracy769:fix/clone-path-traversal-and-arg-injection
Open

fix(interface): prevent path traversal and argument injection in clone_repository#1157
Gracy769 wants to merge 2 commits into
usestrix:mainfrom
Gracy769:fix/clone-path-traversal-and-arg-injection

Conversation

@Gracy769

Copy link
Copy Markdown

Summary

Fixes #1133 and #1134.

Two security bugs in clone_repository() (strix/interface/utils.py):

Bug 1 — Path traversal via crafted repo URL (#1133)

Before: The repo directory name was derived using Path(repo_url).stem / .name. A crafted target like ..git causes .stem to return ., making clone_path = temp_dir / "." resolve to temp_dir itself. The subsequent shutil.rmtree(clone_path) then deletes the entire parent temp directory and all sibling clone directories.

Fix:

  • Replaced the unsafe Path().stem/.name derivation with derive_repo_base_name(), which already exists in the codebase, strips .git suffixes properly, and sanitizes via regex.
  • Added a resolved-path containment check: clone_path.resolve() must start with temp_dir.resolve(), rejecting any traversal attempt with a clear error.

Bug 2 — Argument injection in git clone (#1134)

Before: repo_url was passed directly as a positional argument to git clone without a -- end-of-options separator. A target starting with - (e.g. --upload-pack="malicious command") would be interpreted as a git flag, potentially leading to remote code execution on the Strix host.

Fix:

  • Added -- separator before repo_url in the subprocess argument list, so git treats everything after it as positional arguments regardless of leading dashes.
  • Added explicit validation that rejects any repo_url starting with - before the subprocess is even invoked, with a clear error message.

Changes

  • strix/interface/utils.py: Modified clone_repository() function (+17 lines, -2 lines)

Testing

Both attack vectors can be verified:

# Path traversal (before fix: deletes temp_dir; after fix: raises ValueError)
strix --target "..git"

# Argument injection (before fix: interpreted as git flag; after fix: raises ValueError)
strix --target "--upload-pack=touch /tmp/pwned"

…e_repository

- Replace unsafe Path().stem/name derivation with derive_repo_base_name()
  which strips .git suffix and sanitizes via regex, preventing '..git' from
  resolving to '..' and causing rmtree to delete parent directories.

- Add resolved-path containment check: clone_path.resolve() must start
  with temp_dir.resolve(), rejecting any traversal attempt.

- Insert '--' end-of-options separator before repo_url in the git clone
  subprocess call, preventing targets starting with '-' from being
  interpreted as git flags (e.g. --upload-pack for RCE).

- Add explicit validation rejecting repo_url starting with '-' with a
  clear error message before any subprocess invocation.

Fixes usestrix#1133, fixes usestrix#1134.
@greptile-apps

greptile-apps Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR hardens repository cloning by deriving sanitized clone names, adding a destination-containment check, rejecting dash-prefixed targets, and terminating Git options. However, the containment check still accepts the temporary directory itself, leaving the reported ..git deletion vector reachable.

  • Replaces direct Path basename extraction with derive_repo_base_name.
  • Resolves and checks the clone destination before recursive deletion.
  • Adds Git option termination and explicit rejection of dash-prefixed targets.

Confidence Score: 3/5

This PR is not safe to merge until the clone destination is required to be a strict descendant of the per-run temporary directory.

A fresh scan targeting ..git derives ., resolves the clone destination to the temporary directory itself, and passes the new prefix check before recursive deletion.

Files Needing Attention: strix/interface/utils.py

Security Review

The path-traversal fix remains incomplete: ..git derives ., resolves to the per-run temporary directory, passes the equality-permitting prefix check, and can cause that directory and its sibling clones to be recursively deleted. How this was verified: The repository-name derivation and fresh-run caller were traced through the new containment branch to the existing shutil.rmtree sink.

Important Files Changed

Filename Overview
strix/interface/utils.py Adds clone-path and Git-argument hardening, but the new containment predicate accepts clone_path == temp_dir, preserving the ..git recursive-deletion vulnerability.
Prompt To Fix All With AI
### Issue 1
strix/interface/utils.py:1570-1571
**Containment check accepts temp root**

When a fresh scan targets `..git`, `derive_repo_base_name` produces `.`, so `clone_path.resolve()` equals `temp_dir.resolve()` and passes the new prefix check, causing `shutil.rmtree` to delete the per-run directory and its sibling clones. **How this was verified:** The repository-name derivation and fresh-run caller were traced through the containment branch to the recursive-deletion sink.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (1): Last reviewed commit: "fix(interface): prevent path traversal a..." | Re-trigger Greptile

Comment thread strix/interface/utils.py Outdated
…= temp_dir

The previous startswith check accepted clone_path equal to temp_dir
itself (a string starts with itself), so '..git' deriving '.' would
still resolve to temp_dir and pass through to shutil.rmtree.

Now requires clone_path to be a strict descendant: adds equality
rejection and uses os.sep-terminated prefix to also prevent sibling
directory prefix collisions.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Path traversal: repo base-name derivation lets a "..git" target resolve to "..", causing rmtree of a directory outside the scoped temp dir

2 participants