T09 · Insecure Skill Coding Practices
Warning
- Location
- example.py:14
- Finding
- Execution of an Unverified Python Script Outside the Skill Directory## Vulnerability Details **File Location**: `example.py`, lines 14 and 31-38 **Vulnerability Type**: Execution across the packaged Skill trust boundary **Risk Level**: Medium **Vulnerable Code**: ```python # Skill root directory SKILL_ROOT = Path(__file__).resolve().parents[1] PRESETS_DIR = Path(__file__).resolve().parent / "presets" ``` ```python cmd = ["python", str(SKILL_ROOT / "scripts" / "main.py")] if day: cmd.extend(["--day", day]) elif start_date and end_date: cmd.extend(["--start-date", start_date, "--end-date", end_date]) result = subprocess.run(cmd, capture_output=True, text=True, cwd=SKILL_ROOT) ``` ### Technical Analysis `example.py` is located at the root of the supplied Skill. Consequently, `Path(__file__).resolve().parents[1]` resolves to the parent of the Skill directory rather than the Skill directory itself. The `fetch_papers()` function then attempts to execute `scripts/main.py` beneath that external directory. The audited package does not contain `scripts/main.py`. Therefore, the code delegates execution to a file that is outside the reviewed package and whose integrity is not established. Although command arguments are passed as an array and do not create direct shell injection, the executable script path crosses the Skill trust boundary. This behavior is not necessary for the declared functionality. A paper-fetching implementation should be packaged within the Skill and resolved relative to its verified root. ### Attack Path 1. An attacker obtains write access to the parent directory of the installed Skill or causes the Skill to be installed beneath an attacker-controlled directory. 2. The attacker creates `scripts/main.py` under that parent directory. 3. An Agent or user invokes `fetch_papers()`. 4. `SKILL_ROOT` resolves to the external parent directory. 5. `subprocess.run()` launches the attacker-controlled Python script. 6. The script executes with the same opera ...[truncated 672 chars]
- Remediation
- ## Remediation Suggestions 1. Resolve the Skill root to the directory containing `example.py`: ```python SKILL_ROOT = Path(__file__).resolve().parent ``` 2. Package `scripts/main.py` inside the Skill rather than depending on an external sibling or parent path. 3. Resolve and validate the target before execution: ```python script = (SKILL_ROOT / "scripts" / "main.py").resolve() if not script.is_relative_to(SKILL_ROOT.resolve()): raise ValueError("Script path escapes the Skill directory") if not script.is_file(): raise FileNotFoundError(script) ``` 4. Use `sys.executable` instead of the generic `python` command to ensure the intended Python interpreter is used: ```python import sys cmd = [sys.executable, str(script)] ``` 5. Verify the integrity or signature of executable packaged components before invocation where the deployment model permits package modification. 6. Run the Skill under a restricted operating-system account without access to unrelated credentials or sensitive files.
