T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/manage_courses.py:15
- Finding
- Path Traversal Allows File Creation Outside the Intended Storage Directory## Vulnerability Details **File Location**: `scripts/manage_courses.py`, lines 15-18 **Vulnerability Type**: Unrestricted path construction using a caller-controlled course name **Risk Level**: Medium ```python filename = f"{name}_{timestamp}.md" filepath = os.path.join(STORAGE_DIR, filename) with open(filepath, 'w', encoding='utf-8') as f: ``` ### Technical Analysis The `name` parameter is incorporated directly into a filesystem path without validation or normalization. Although the intended destination is `/home/ubuntu/yanxue_courses`, `os.path.join()` does not guarantee that the resulting path remains beneath that directory. If `name` is absolute, the constructed `filename` is also absolute, causing `os.path.join()` to discard `STORAGE_DIR`. A name containing traversal components such as `../../` can similarly resolve outside the storage directory. The script then writes caller-controlled course content to the resulting location with the permissions of the process running the Skill. The timestamp and `.md` suffix limit the ability to overwrite a specifically named existing file, but they do not prevent creation of attacker-controlled files in other writable directories. ### Attack Path 1. An attacker supplies a course name containing an absolute path or directory traversal components. 2. The save operation is invoked through `manage_courses.py save <name> <content_path>`. 3. The script appends a timestamp and `.md` extension but does not remove path separators or traversal sequences. 4. `os.path.join(STORAGE_DIR, filename)` produces a path outside the intended storage directory. 5. The script creates a Markdown file containing attacker-controlled content in any existing directory writable by the running process. ### Impact Assessment Successful exploitation permits creation of timestamp-suffixed Markdown files outside `/home/ubuntu/yanxue_courses`. The attacker gains the same filesystem write ...[truncated 364 chars]
- Remediation
- ## Remediation Suggestions - Reject absolute paths and course names containing `/`, `\`, `..`, null bytes, or platform-specific path separators. - Convert the supplied course name to a safe filename using a strict allowlist of expected letters, digits, spaces, underscores, and hyphens. - Resolve both the storage directory and destination path before writing, then verify that the destination remains beneath the storage directory. - Use `pathlib.Path` for explicit and portable path validation. - Consider exclusive file creation mode to avoid unintended replacement under concurrent execution. - Return an error rather than silently rewriting an invalid name. Example hardening pattern: ```python import re from pathlib import Path STORAGE_DIR = Path("/home/ubuntu/yanxue_courses").resolve() def safe_destination(name, timestamp): safe_name = re.sub(r"[^A-Za-z0-9 _-]", "_", name).strip() if not safe_name: raise ValueError("Invalid course name") destination = (STORAGE_DIR / f"{safe_name}_{timestamp}.md").resolve() if not destination.is_relative_to(STORAGE_DIR): raise ValueError("Destination escapes the storage directory") return destination ```
