T09 · Insecure Skill Coding Practices
- Location
scripts/scaffold_mcp_server.py:61- Finding
Unrestricted File Creation and Overwrite Through the Output Path
- Content
View full analysis
Vulnerability Details
File Location:
scripts/scaffold_mcp_server.py, lines 15-17, 61-91, and 156
Vulnerability Type: Unrestricted filesystem write
Risk Level: MediumVulnerable Code
python parser.add_argument("--output", required=True, help="Path to output artifact.")python def render(result: dict, output_path: Path, fmt: str) -> None: output_path.parent.mkdir(parents=True, exist_ok=True) if fmt == "json": output_path.write_text(json.dumps(result, indent=2), encoding="utf-8") return if fmt == "md": lines = [ f"# {result['summary']}", "", f"- status: {result['status']}", "", "## Planned Files", ] for item in result["details"]["file_map"]: lines.append(f"- {item}") lines.extend(["", "## Tools"]) for tool in result["details"]["tools"]: lines.append(f"- {tool['name']}: {tool['description']}") output_path.write_text("\n".join(lines) + "\n", encoding="utf-8") return with output_path.open("w", newline="", encoding="utf-8") as handle: writer = csv.writer(handle) writer.writerow(["name", "description"]) for tool in result["details"]["tools"]: writer.writerow([tool["name"], tool["description"]])python render(result, Path(args.output), args.format)Technical Analysis
The user-controlled
--outputvalue is converted directly into aPathand passed torender(). Unlikescaffold_root, this path is not resolved and checked against the current workspace. The function creates missing parent directories and then useswrite_text()oropen("w"), both of which create a new file or truncate an existing one.Consequently, an invocation can specify an absolute path or a relative path containing traversal components. The operation is lim ...[truncated 945 chars]
- Remediation
View remediation
Remediation Suggestions
- Resolve the output path before writing and verify that it remains beneath the approved workspace root.
- Reject absolute paths and traversal outside the workspace unless a separate, explicit external-write option is enabled.
- Refuse to overwrite existing output files by default.
- Add a clearly named
--forceoption if replacement is required. - Reject symbolic-link destinations and validate every path component before opening the file.
- Where practical, open new files using exclusive creation semantics to prevent accidental truncation.
- Add tests covering absolute paths,
..traversal, existing files, and symbolic links.
