T09 · Insecure Skill Coding Practices
- Location
scripts/generate_structure.py:181- Finding
Unsanitized Project Name Enables Path Traversal and Generated-Code Injection
- Content
View full analysis
Vulnerability Details
File Location:
scripts/generate_structure.py, lines 181–222; user-controlled input originates fromsys.argv[1]
Vulnerability Type: Path traversal, arbitrary file overwrite, and template injection
Risk Level: HighVulnerable Code
python # Create directories for dir_path in tmpl["dirs"]: dir_path = dir_path.format(name=project_name) full_path = output / dir_path full_path.mkdir(parents=True, exist_ok=True) print(f"✅ Create directory: {dir_path}") # Create files file_templates = { "README.md": README_TEMPLATE, "pyproject.toml": PYPROJECT_TEMPLATE, ".gitignore": GITIGNORE_TEMPLATE, ".pre-commit-config.yaml": PRECOMMIT_TEMPLATE, "__init__.py": INIT_TEMPLATE, "main.py": MAIN_TEMPLATE, "conftest.py": CONFTES_TEMPLATE, } for file_path in tmpl["files"]: file_path = file_path.format(name=project_name) full_path = output / file_path # Determine the file content template content_tmpl = "" for key in file_templates: if file_path.endswith(key): content_tmpl = file_templates[key] break if content_tmpl: content = content_tmpl.format(name=project_name) else: content = "" full_path.write_text(content, encoding="utf-8") print(f"✅ Create file: {file_path}")The value is populated directly from a command-line argument:
python project_name = sys.argv[1]Technical Analysis
project_nameis treated simultaneously as a filesystem path component and as content embedded into Python, TOML, and Markdown templates. No validation restricts it to a safe Python package identifier, and generated paths are not resolved and checked against the intended output directory.A value containing traversal components such as
../can cause paths constructed throughoutput / file_pathto resolve outside the requested ...[truncated 2493 chars]- Remediation
View remediation
Remediation Suggestions
-
Restrict project names to valid Python identifiers before any filesystem or template operation. For example, require a pattern such as
^[A-Za-z_][A-Za-z0-9_]*$and reject all other values. -
Reject absolute paths, path separators,
.and..components, control characters, quotes, and newline characters in project names. -
Resolve the output root and every generated destination before writing, then enforce containment:
python output_root = Path(output_path).resolve() destination = (output_root / relative_path).resolve() if destination != output_root and output_root not in destination.parents: raise ValueError("Generated path escapes the output directory") -
Apply the containment check independently to every directory and file, including paths generated by all templates.
-
Avoid directly interpolating untrusted values into Python and TOML source. Validate values according to the target format and use a TOML serialization library for configuration generation.
-
Use exclusive file creation by default, such as mode
x, to prevent accidental overwrite. Require explicit, separately confirmed authorization before replacing each existing file. -
Add tests covering traversal strings, absolute-path-like input, path separators, quotes, newlines, braces, control characters, Unicode edge cases, and symlink-based output-directory escapes.
-
Recheck containment immediately before writing to reduce exposure to symlink or time-of-check/time-of-use path changes.
-
