T09 · Insecure Skill Coding Practices
- Location
scripts/main.py:632- Finding
Unrestricted Output Path Allows Arbitrary File Overwrite
- Content
View full analysis
Vulnerability Details
File Location:
scripts/main.py, lines 632-635 and 681-684
Vulnerability Type: Arbitrary file overwrite through an unrestricted user-controlled path
Risk Level: MediumVulnerable Code
python parser.add_argument( "--save", type=str, help="Save output to file" )python if args.save: with open(args.save, 'w', encoding='utf-8') as f: f.write(output) print(f"\nOutput saved to: {args.save}")Technical Analysis
The
--saveargument accepts an arbitrary filesystem path. The supplied value is passed directly toopen()in write mode without path normalization, workspace-boundary enforcement, symlink validation, file-type validation, or overwrite confirmation.Opening a file with mode
wcreates it if it does not exist and truncates it if it does. Consequently, any file writable by the process can be replaced with generated report content. Absolute paths,../traversal sequences, and symlinks pointing outside the project are not rejected.This exceeds the minimum filesystem privileges required for the declared functionality. Report generation only requires writing to a controlled output directory. It also contradicts the security checklist in
SKILL.md, which states that output should be restricted to the workspace.Attack Path
- An attacker supplies task content or instructions that influence the Agent to save a report to a crafted path.
- The Agent invokes the Skill with an argument such as
--save ../../some-writable-file. - The script passes that path directly to
open()using truncating write mode. - If the process has permission to write the target, its existing content is destroyed and replaced by the generated report.
- The same path can be exploited through a symlink placed in an otherwise expected output location.
No privilege escalation beyond the operating-system permissions of the invoking process occurs. Exploitation is limited to fi ...[truncated 699 chars]
- Remediation
View remediation
Remediation Suggestions
- Define a dedicated output directory beneath the project workspace, such as
output/. - Resolve both the output directory and requested path with
Path.resolve(). - Reject any path whose resolved value is not a descendant of the approved output directory.
- Reject existing symlinks and verify parent path components before opening the file.
- Use exclusive creation mode (
x) by default to prevent silent overwrites. - Require an explicit, separate overwrite flag when replacement is intentional.
- Consider accepting only a filename rather than a complete path.
- Apply an allowlist of appropriate report extensions based on the selected output format.
Example hardening pattern:
python output_dir = (Path(__file__).parent.parent / "output").resolve() output_dir.mkdir(parents=True, exist_ok=True) requested = (output_dir / Path(args.save).name).resolve() if output_dir not in requested.parents: raise ValueError("Output path must remain inside the output directory") if requested.is_symlink(): raise ValueError("Symbolic-link output paths are not permitted") with requested.open("x", encoding="utf-8") as f: f.write(output)- Define a dedicated output directory beneath the project workspace, such as
