T09 · Insecure Skill Coding Practices
Error
- Location
- workspace-template/scripts/write_memory_entry.py:30
- Finding
- Path Traversal Allows Modification of Persistent Agent Instruction Files<![CDATA[ ## Vulnerability Details **File Location**: `workspace-template/scripts/write_memory_entry.py`, lines 30-59 **Vulnerability Type**: User-controlled path traversal in persistent file writing **Risk Level**: High ### Vulnerable Code ```python parser.add_argument("--input") parser.add_argument("--date") args = parser.parse_args() payload = load_payload(args.input) date_str = args.date or datetime.now().strftime("%Y-%m-%d") MEMORY_DIR.mkdir(parents=True, exist_ok=True) path = MEMORY_DIR / f"{date_str}.md" titles = normalize_list(payload.get("titles")) reasons = normalize_list(payload.get("reasons")) preferences = normalize_list(payload.get("preferences")) notes = normalize_list(payload.get("notes")) lines = [] if not path.exists(): lines.extend([f"# {date_str}", ""]) lines.extend([f"## {datetime.now().strftime('%H:%M')}", ""]) for heading, items in [ ("Titles", titles), ("Why", reasons), ("Preferences", preferences), ("Notes", notes), ]: if items: lines.append(f"### {heading}") lines.extend(f"- {item}" for item in items) lines.append("") if len(lines) <= 2: raise SystemExit("Nothing to write.") with path.open("a", encoding="utf-8") as f: f.write("\n".join(lines).rstrip() + "\n\n") ``` ### Technical Analysis The `--date` argument is directly interpolated into a relative filesystem path without validating that it represents a date or checking that the resulting path remains inside the intended `memory` directory. `pathlib.Path` resolves traversal components such as `..` during filesystem access. For example, the argument `--date ../AGENTS` produces the effective destination: ```text memory/../AGENTS.md ``` This resolves to `AGENTS.md` in the current workspace. The script opens the destination in append mode and writes values from the input JSON without sanitization. An attacker who can influence the script arguments and payload can therefore append content to Markdown files outside the int ...[truncated 1600 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Require `--date` to use a strict date format: ```python import re if not re.fullmatch(r"\d{4}-\d{2}-\d{2}", date_str): raise SystemExit("Date must use YYYY-MM-DD format.") ``` 2. Parse and validate the date semantically: ```python from datetime import datetime try: datetime.strptime(date_str, "%Y-%m-%d") except ValueError: raise SystemExit("Invalid calendar date.") ``` 3. Resolve the destination and enforce directory containment: ```python memory_root = MEMORY_DIR.resolve() path = (memory_root / f"{date_str}.md").resolve() if path.parent != memory_root: raise SystemExit("Output path escapes the memory directory.") ``` 4. Reject path separators, `..`, absolute paths, null bytes, and alternate separator forms before constructing the path. 5. Run the script with filesystem permissions that prevent it from modifying agent instruction files. 6. Add tests covering values such as `../AGENTS`, `../../SOUL`, absolute paths, encoded traversal forms, and malformed dates. ]]>
