T07 · Tool Hijacking and Spoofing
Error
- Location
- main.py:16
- Finding
- Execution of Unverified Code from a Mutable External Checkout<![CDATA[ ## Vulnerability Details **File Location**: `main.py:16-44`; duplicate behavior in `server.py:17-45` **Vulnerability Type**: Local tool and runtime substitution **Risk Level**: High ### Vulnerable Code `main.py:16-44`: ```python def _repo_python() -> tuple[Path, Path]: repo_dir = Path('/Users/buddy/narrator').resolve() if not repo_dir.exists(): print(f"[narrator] Canonical repo not found: {repo_dir}", file=sys.stderr) sys.exit(1) venv_python = repo_dir / '.venv' / 'bin' / 'python' if not venv_python.exists(): print( f"[narrator] Python venv not found: {venv_python}\n" f"[narrator] Run: cd {repo_dir} && python3 -m venv .venv && source .venv/bin/activate && pip install -r requirements.txt", file=sys.stderr, ) sys.exit(1) return repo_dir, venv_python def main() -> None: repo_dir, python_bin = _repo_python() cmd = [str(python_bin), '-m', 'narrator'] cmd.extend(sys.argv[1:]) env = os.environ.copy() # Make sure package imports are resolved from repo checkout. env['PYTHONPATH'] = str(repo_dir) proc = subprocess.run(cmd, cwd=str(repo_dir), env=env) sys.exit(proc.returncode) ``` `server.py:17-45`: ```python def _repo_python() -> tuple[Path, Path]: repo_dir = Path('/Users/buddy/narrator').resolve() if not repo_dir.exists(): print(f"[narrator] Canonical repo not found: {repo_dir}", file=sys.stderr) sys.exit(1) venv_python = repo_dir / '.venv' / 'bin' / 'python' if not venv_python.exists(): print( f"[narrator] Python venv not found: {venv_python}\n" f"[narrator] Run: cd {repo_dir} && python3 -m venv .venv && source .venv/bin/activate && pip install -r requirements.txt", file=sys.stderr, ) sys.exit(1) return repo_dir, venv_python def main() -> None: repo_dir, python_bin = _repo_python() # Backward compatibility: if thi ...[truncated 2761 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Package the actual `narrator` implementation inside the audited skill rather than delegating to a mutable checkout outside the project. 2. If external delegation is unavoidable, pin the external implementation to an immutable revision and verify its cryptographic digest before every execution. 3. Validate that the repository and interpreter are owned by the expected account and are not writable by untrusted users or groups. 4. Use a trusted, explicitly configured Python interpreter rather than an interpreter located inside the external checkout. 5. Avoid assigning an unverified directory to `PYTHONPATH`; import only packaged and integrity-checked modules. 6. Replace `os.environ.copy()` with an allowlist containing only variables required by the subprocess. Do not forward unrelated credentials or tokens. 7. Run the narrator process in a restricted environment with least-privilege filesystem access, network access limited to required API hosts, and no access to unrelated user data. 8. Apply the same changes to both `main.py` and `server.py` so one compatibility launcher cannot bypass the protections added to the other. ]]>
