T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/main.py:66
- Finding
- Unrestricted Output Path Allows Arbitrary File Overwrite## Vulnerability Details **File Location**: `scripts/main.py`, lines 66–70 and 94–96 **Vulnerability Type**: Unrestricted file write / path traversal **Risk Level**: Medium ### Vulnerable Code ```python parser.add_argument( "--output", "-o", type=str, help="Output JSON file path (optional, prints to stdout if not specified)" ) ``` ```python if args.output: with open(args.output, 'w', encoding='utf-8') as f: f.write(output) print(f"Table saved to: {args.output}") ``` ### Technical Analysis The caller-controlled `--output` value is passed directly to `open()` in write mode. The implementation does not reject absolute paths or parent-directory traversal, canonicalize the path against an authorized workspace, check for symbolic links, or require exclusive file creation. Consequently, the process can create or truncate any file writable under its operating-system privileges. The `w` mode truncates an existing target before writing the generated JSON. Although the attacker cannot supply arbitrary file contents through this interface, destructive overwrite and configuration corruption remain possible. This behavior also conflicts with the security controls identified in `SKILL.md`, which state that output should be restricted to the workspace and paths should be validated against `../` traversal. ### Attack Path 1. An attacker gains influence over the skill's command-line arguments. 2. The attacker supplies an absolute path or traversal path, such as `--output ../../target-file`. 3. Python resolves the path without any application-level containment check. 4. `open(args.output, 'w')` creates the target or truncates an existing writable file. 5. The generated JSON replaces the previous contents, potentially corrupting data or configuration. ### Impact Assessment Exploitation is limited to the filesystem permissions of the account running the skill and does not itself provide ...[truncated 348 chars]
- Remediation
- ## Remediation Suggestions 1. Define a dedicated, trusted output directory beneath the project workspace. 2. Reject absolute paths and resolve the requested path with `pathlib.Path.resolve()`. 3. Verify that the resolved target remains beneath the trusted output directory using `Path.relative_to()` or an equivalent containment check. 4. Reject parent-directory traversal and symbolic-link targets. 5. Use exclusive creation mode (`x`) where overwriting is unnecessary, or require explicit authorization before replacing an existing file. 6. Create output directories with restrictive permissions and run the skill under a least-privileged account. 7. Return a sanitized error when path validation fails. Example containment pattern: ```python from pathlib import Path output_root = (Path.cwd() / "output").resolve() output_root.mkdir(parents=True, exist_ok=True) requested = Path(args.output) if requested.is_absolute(): raise ValueError("Absolute output paths are not allowed") target = (output_root / requested).resolve() try: target.relative_to(output_root) except ValueError: raise ValueError("Output path must remain within the output directory") if target.is_symlink(): raise ValueError("Symbolic-link output targets are not allowed") with target.open("x", encoding="utf-8") as f: f.write(output) ```
