Skip to content

Commit 1928186

Browse files
authored
🛡️ Sentinel: [CRITICAL] Fix Path Hijacking in GitIndexer (#151)
Resolved the full absolute path of the `git` executable using `shutil.which("git")` before executing `subprocess.run` to prevent local privilege escalation and malicious binary interception.
1 parent 392ef0d commit 1928186

2 files changed

Lines changed: 14 additions & 2 deletions

File tree

.jules/sentinel.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,7 @@
3939
**Vulnerability:** Arbitrary code execution risk due to `np.load(..., allow_pickle=True)` used for loading Python lists (`_doc_ids`).
4040
**Learning:** `np.load` with `allow_pickle=True` uses the `pickle` module under the hood, which is insecure and can execute arbitrary code if the `.npy` file is tampered with. This shouldn't be used for simple data structures like lists of strings.
4141
**Prevention:** Store metadata like string lists in safer formats like JSON (`vector_meta.json`). For numeric index files, explicitly set `allow_pickle=False` when using `np.load()` to prevent insecure deserialization.
42+
## 2025-05-30 - Fix Path Hijacking in GitIndexer
43+
**Vulnerability:** The `GitIndexer` class executed the `git` binary using a hardcoded string `git` in `subprocess.run`, which allowed for path hijacking where an attacker could put a malicious `git` binary in the PATH environment variable.
44+
**Learning:** Hardcoding binary paths creates a path hijacking risk. It's essential to retrieve the absolute path using `shutil.which` to ensure the correct executable is run.
45+
**Prevention:** Always use `shutil.which('git')` and gracefully handle the possibility that the binary doesn't exist before executing `subprocess.run`.

src/ledgermind/core/reasoning/git_indexer.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,14 @@ def get_recent_commits(
4444
) -> List[Dict[str, Any]]:
4545
"""Извлекает историю коммитов через git log."""
4646
try:
47+
import shutil
48+
git_path = shutil.which("git")
49+
if not git_path:
50+
return []
4751
# Формат: hash|author|date|subject|body
4852
# Используем --reverse чтобы идти от старых к новым при индексации
4953
format_str = "%H|%an|%ai|%s|%b%x00"
50-
cmd = ["git", "log", f"-n {limit}", f"--format={format_str}"]
54+
cmd = [git_path, "log", f"-n {limit}", f"--format={format_str}"]
5155

5256
if since_hash:
5357
# Security: Validate hash to prevent argument injection
@@ -119,8 +123,12 @@ def index_to_memory(self, memory_instance, limit: int = 20) -> int:
119123
for commit in reversed(new_commits): # От старых к новым
120124
# Дополнительно получаем список измененных файлов для контекста
121125
try:
126+
import shutil
127+
git_path = shutil.which("git")
128+
if not git_path:
129+
raise FileNotFoundError("git executable not found in PATH")
122130
diff_res = subprocess.run(
123-
["git", "show", "--name-only", "--format=", commit["hash"]],
131+
[git_path, "show", "--name-only", "--format=", commit["hash"]],
124132
cwd=self.repo_path,
125133
capture_output=True,
126134
text=True,

0 commit comments

Comments
 (0)