T09 · Insecure Skill Coding Practices
- Location
scripts/create_word.py:87- Finding
Unrestricted Output Path Allows Arbitrary File Overwrite
- Content
View full analysis
Vulnerability Details
File Location:
scripts/create_word.py, lines 87-109
Vulnerability Type: CWE-73 — External Control of File Name or Path; CWE-59 — Improper Link Resolution
Risk Level: MediumVulnerable Code
The report-writing function saves directly to the supplied path without validating its location, extension, or symlink status:
python doc.save(output_path)The command-line entry point passes the caller-controlled argument directly to that function:
python customer_name = sys.argv[1] output_path = sys.argv[2] create_word_report(customer_name, results, output_path)Technical Analysis
The second command-line argument controls the destination passed to
python-docxwithout any containment check. Unlikescripts/create_scenario_ppt.py, this script does not resolve the path and verify that it is inside an approved workspace.Consequently, an absolute path or a path containing traversal components can target any location writable by the agent process. The save operation can create or truncate the selected file. It can also follow a symbolic link, allowing a path that appears to be inside an expected directory to overwrite a writable target elsewhere.
No shell execution or privilege escalation primitive is present. The vulnerability is limited by the operating-system permissions of the process running the skill.
Attack Path
- An attacker influences the output path passed to
create_word.py, directly or through an agent request that is converted into script arguments. - The attacker supplies an absolute path, traversal path, or symbolic-link path pointing to a writable target.
- The script accepts the path without validation.
doc.save(output_path)opens and truncates the target, replacing it with generated DOCX data.- The target file is corrupted or replaced, potentially disrupting other agent tasks or destroying user data.
Example invocation aga ...[truncated 1059 chars]
- An attacker influences the output path passed to
- Remediation
View remediation
Remediation Suggestions
-
Resolve all output paths and require them to remain beneath a dedicated report directory:
python from pathlib import Path def validate_output_path(raw_path, workspace): workspace = Path(workspace).resolve(strict=True) output_path = Path(raw_path).resolve(strict=False) try: output_path.relative_to(workspace) except ValueError: raise ValueError("Output path must remain inside the report workspace") if output_path.suffix.lower() != ".docx": raise ValueError("Output file must use the .docx extension") return output_path -
Use
Path.relative_to()rather than string-prefix comparisons, which do not enforce path-component boundaries. -
Generate the destination filename from the validated customer name instead of accepting an arbitrary destination from the caller.
-
Restrict customer names to a conservative character set and reject path separators, control characters, reserved names, and excessive lengths.
-
Defend against symbolic-link attacks. Reject an existing destination if it is a symlink and ensure every parent directory between the workspace root and destination is trusted and not symlinked.
-
Run the skill under a least-privileged account with access only to its dedicated output directory.
-
Use a temporary file in the destination directory followed by an atomic rename after successful document generation.
-
Apply the same centralized path-validation routine to every document-generation API so direct library calls cannot bypass command-line protections.
-
