T09 · Insecure Skill Coding Practices
- Location
scripts/scaffold_deep_module.py:28- Finding
Repository Root Escape Through Unvalidated Scaffold Paths
- Content
View full analysis
None: path.parent.mkdir(parents=True, exist_ok=True) if path.exists(): # Don't clobber existing work. return path.write_text(content, encoding="utf-8") ``` ```python def main(argv: list[str]) -> int: parser = argparse.ArgumentParser() parser.add_argument("--name", required=True, help="Module name (kebab-case recommended).") parser.add_argument("--lang", choices=["ts", "py"], required=True, help="Language template to use.") parser.add_argument("--base-dir", default="src", help="Base directory inside repo (default: src).") parser.add_argument("--root", default=".", help="Repo root (default: current directory).") args = parser.parse_args(argv) root = Path(args.root).resolve() base_dir = root / args.base_dir if args.lang == "py": # Python packages must be valid identifiers; normalise kebab-case to snake_case. package_name = args.name.replace("-", "_") module_dir = base_dir / package_name created = scaffold_py(module_dir, package_name=package_name, display_name=args.name) else: module_dir = base_dir / args.name created = scaffold_ts(module_dir, args.name) ``` ### Technical Analysis The user-controlled `--base-dir` and `--name` arguments are combined with the repository root without validating that the resulting path remains inside that root. `Path` accepts traversal components such as `..`; additionally, joining an absolute path can discard the preceding base path. The resulting destinations are passed to `_write()`, which recursively creates parent directories and writes generated source files. No resolved-path containment check is performed before these filesystem oper ...[truncated 1387 chars]- Remediation
View remediation
Path: root = root.resolve() destination = destination.resolve() if not destination.is_relative_to(root): raise ValueError(f"Destination escapes repository root: {destination}") return destination ``` 5. Apply the containment check to `base_dir`, `module_dir`, and every path passed to `_write()`. 6. Consider requiring `--base-dir` to be selected from known repository-relative locations such as `src` or `packages`. 7. Preserve the existing no-overwrite behavior and report skipped files separately from newly created files. 8. Add regression tests covering absolute paths, nested `../` traversal, traversal through `--name`, and valid repository-relative destinations. ]]>
