T09 · Insecure Skill Coding Practices
- Location
scripts/save_entry.py:151- Finding
Path Traversal Enables File Writes Outside the Daily Notes Directory
- Content
View full analysis
(str, str): daily_file = root / "daily" / f"{record['date']}.md" ensure_daily_file(daily_file) text = daily_file.read_text(encoding="utf-8") section = SECTION_TITLES[record["type"]] text = ensure_section(text, section) block = build_block(record) marker = f"### {record['id']}\n" if marker in text: start = text.index(marker) next_pos = text.find("\n### ", start + len(marker)) if next_pos == -1: next_pos = len(text) text = text[:start] + block + text[next_pos:] else: header = f"## {section}\n" insert_at = text.index(header) + len(header) text = text[:insert_at] + "\n" + block + text[insert_at:] daily_file.write_text(text, encoding="utf-8") return str(daily_file), block ``` ### Technical Analysis The `date` field is inserted directly into a filesystem path without schema validation, canonicalization, or a containment check: ```python daily_file = root / "daily" / f"{record['date']}.md" ``` The direct-save interface accepts records from standard input or a JSON file, so callers are not restricted to records produced by `parse_entries.py`. A value such as `../../outside` produces a path equivalent to: ```text /daily/../../outside.md ``` The path is then passed to `ensure_daily_file()`, `read_text()`, and `write_text()`. No resolved-path check verifies that the destination remains under `/daily`. The forced `.md` suffix limits the attack to filenames ending in `.md`, but it does not prevent creating or overwriting Markdown files elsewhere within the privileges of the executing user. ### Attack Path 1. An attacker supplies a crafted record through the documented `--stdin-json` o ...[truncated 972 chars]- Remediation
View remediation
