T09 · Insecure Skill Coding Practices
- Location
scripts/setup.py:91- Finding
Unvalidated Folder Path Allows Writes Outside the Selected Vault
- Content
View full analysis
Vulnerability Details
File Location:
scripts/setup.py, lines 91–114
Vulnerability Type: Path traversal and unrestricted filesystem write
Risk Level: MediumVulnerable Code
python folder_path = os.path.join(vault, args.folder) os.makedirs(folder_path, exist_ok=True) columns = [c.strip() for c in args.columns.split(",")] # Relative path from vault root for Dataview queries tasks_folder = args.folder # Create Board.md board_path = os.path.join(folder_path, "Board.md") if os.path.exists(board_path): print(f"Board already exists: {board_path}") else: with open(board_path, "w") as f: f.write(create_board(folder_path, columns)) print(f"Created: {board_path}") # Create Dashboard.md dashboard_path = os.path.join(folder_path, "Dashboard.md") if os.path.exists(dashboard_path): print(f"Dashboard already exists: {dashboard_path}") else: with open(dashboard_path, "w") as f: f.write(create_dashboard(tasks_folder)) print(f"Created: {dashboard_path}")Technical Analysis
The user-controlled
--folderargument is joined to the vault path without validating that the resulting destination remains inside the vault.If
args.folderis an absolute path,os.path.join(vault, args.folder)discards the vault prefix. A relative value containing parent-directory components, such as../../target, can similarly resolve outside the vault. The implementation also does not resolve or check symlinks before creating directories and files.The script protects existing
Board.mdandDashboard.mdfiles from direct replacement, but it can still create these files and intermediate directories at an unintended filesystem location.Attack Path
- An attacker, untrusted automation, or an agent-controlled input supplies a malicious folder argument, for example:
bash python3 scripts/setup.py /home/user/vault --folder ../../tmp/target
...[truncated 1047 chars]
- An attacker, untrusted automation, or an agent-controlled input supplies a malicious folder argument, for example:
- Remediation
View remediation
Remediation Suggestions
- Reject absolute values for
--folder. - Resolve the vault and destination to canonical paths before creating directories.
- Verify that the resolved destination is a descendant of the resolved vault.
- Reject traversal through symlinks when the security model requires all writes to remain physically inside the vault.
- Return a clear error before performing any filesystem modification when validation fails.
A hardened implementation can use
pathlib:python from pathlib import Path vault = Path(args.vault_path).expanduser().resolve() folder = Path(args.folder) if folder.is_absolute(): parser.error("--folder must be relative to the vault") folder_path = (vault / folder).resolve() try: folder_path.relative_to(vault) except ValueError: parser.error("--folder must remain inside the vault") folder_path.mkdir(parents=True, exist_ok=True)Where supported, use
Path.is_relative_to(vault)instead of therelative_toexception pattern. Consider checking each existing path component for symlinks before writing if external symlink targets must be prohibited.- Reject absolute values for
