T09 · Insecure Skill Coding Practices
- Location
scripts/distill.py:541- Finding
Arbitrary File Overwrite Outside the Configured Obsidian Vault
- Content
View full analysis
None: """Write content to filepath, creating parent dirs as needed.""" os.makedirs(os.path.dirname(filepath), exist_ok=True) with open(filepath, "w", encoding="utf-8") as f: f.write(content) logging.info(f"Saved → {filepath}") ``` ```python rel_path = args.path # ... out_path = os.path.join(vault_dir, rel_path) write_note(out_path, full_content) print(f"Persisted → {out_path}") ``` ### Technical Analysis The `persist` subcommand accepts `args.path` and joins it directly with the configured vault directory. The code does not reject absolute paths, normalize traversal components, resolve symbolic links, or verify that the resulting destination remains within the vault. Two bypass patterns are possible: 1. A traversal path such as `../../.bashrc` escapes the vault after filesystem path resolution. 2. An absolute `--path` causes `os.path.join(vault_dir, rel_path)` to discard `vault_dir` entirely. The resulting path is passed to `write_note`, which creates missing parent directories and opens the destination in `"w"` mode. This silently truncates and replaces an existing file. ### Attack Path 1. An attacker supplies or influences a request that causes the Agent to invoke the `persist` subcommand. 2. The attacker provides a path such as: ```text ../../home/user/.bashrc ``` or an absolute path such as: ```text /home/user/.config/example/config ``` 3. `os.path.join` constructs a destination that is outside the configured vault. 4. `write_note` creates parent directories where necessary. 5. The target file is opened in write mode and overwritten with attacker-influenced Markdown and frontmatter. 6. If the sel ...[truncated 1073 chars]- Remediation
View remediation
