T09 · Insecure Skill Coding Practices
- Location
scripts/save.py:185- Finding
Save Slot Path Traversal Allows Writes Outside the Save Directory
- Content
View full analysis
|'): # Error reporting omitted; it does not impose additional path constraints. fail(..., 1) return os.path.join(SAVES_DIR, slot) def slot_paths(slot): d = slot_dir(slot) return { "dir": d, "state": os.path.join(d, "state.json"), "memory": os.path.join(d, "memory.md"), "rolls": os.path.join(d, "rolls.jsonl"), "world": os.path.join(d, "world.json"), "archives": os.path.join(d, "archives"), } def atomic_write(path, text): """Temporary file followed by an atomic replacement in the same directory.""" d = os.path.dirname(path) os.makedirs(d, exist_ok=True) fd, tmp = tempfile.mkstemp(dir=d, prefix=".tmp_", suffix=".json") try: with os.fdopen(fd, "w", encoding="utf-8", newline="\n") as f: f.write(text) os.replace(tmp, path) except BaseException: if os.path.exists(tmp): os.remove(tmp) raise ``` The resulting paths are used by commands including `init`, `update`, `world-init`, and `archive`. For example, `cmd_init()` writes to the paths without performing a containment check: ```python atomic_write(p["state"], json.dumps( ordered, ensure_ascii=False, separators=(",", ":") )) atomic_write(p["memory"], memory) os.makedirs(p["archives"], exist_ok=True) ``` ### Technical Analysis `slot_dir()` rejects conventional path separators and several platform-specific reserved characters, but it does not reject the special directory names `.` and `..`. It also does not canonicalize the resulting path or verify that the resolved path remains under `SAVES_DIR`. On POSIX systems, a slot value of `..` produces: ```text ...[truncated 2813 chars]- Remediation
View remediation
