T09 · Insecure Skill Coding Practices
- Location
scripts/main.py:1077- Finding
Unrestricted Output Path Allows Arbitrary File Overwrite
- Content
View full analysis
Vulnerability Details
File Location:
scripts/main.py:1077-1082, 1143-1147
Vulnerability Type: Unrestricted filesystem write and arbitrary file overwrite
Risk Level: MediumVulnerable Code
python parser.add_argument( "--output", "-o", type=str, default=None, help="输出文件路径 (默认输出到 stdout)" )python if args.output: with open(args.output, "w", encoding="utf-8") as f: f.write(template_content) print(f"✓ 模板已生成: {args.output}") else: print(template_content)Technical Analysis
The user-controlled
--outputvalue is passed directly toopen()in write mode without canonicalization, directory-boundary validation, path-traversal rejection, symlink protection, or overwrite safeguards.Consequently, the program accepts absolute paths and relative paths containing traversal components such as
../. The"w"mode creates a destination that does not exist and truncates an existing destination before writing the generated Markdown. This behavior also conflicts with the security expectations inSKILL.md, which identify path validation and workspace-restricted output as required controls.Attack Path
- An attacker or untrusted caller gains influence over the script's command-line arguments.
- The attacker supplies an absolute path or a traversal path through
--output, for example:bash python scripts/main.py --type general --output ../../writable-target argparseaccepts the path as an unrestricted string.- The script passes it directly to
open(args.output, "w", encoding="utf-8"). - If the process has write permission, the target is created or its existing contents are truncated and replaced with generated Markdown.
A writable symlink supplied as the output path may similarly redirect the write to its target because the implementation does not reject or safely handle symlinks.
Impact Assess
...[truncated 585 chars]
- Remediation
View remediation
Remediation Suggestions
- Define an explicit trusted output root rather than accepting unrestricted destinations.
- Resolve both the trusted root and requested output path to canonical absolute paths and verify that the destination remains inside the trusted root:
python from pathlib import Path output_root = Path.cwd().resolve() destination = (output_root / args.output).resolve() if destination != output_root and output_root not in destination.parents: parser.error("Output path must remain inside the workspace") - Reject absolute user-supplied paths if only workspace-relative paths are required.
- Reject symlink destinations and inspect existing parent components for unsafe symlinks. Where supported, use operating-system flags that prevent symlink following.
- Avoid silent truncation. Use exclusive creation mode (
"x") by default or require an explicit--overwriteoption before replacing an existing file. - Restrict output file extensions if only Markdown output is expected.
- Handle filesystem exceptions gracefully without exposing unnecessary environment details.
- Add tests covering absolute paths,
../traversal, symlink targets, existing files, and paths outside the configured workspace. - Update
SKILL.mdso its security claims accurately reflect the controls implemented in code.
