T09 · Insecure Skill Coding Practices
- Location
scripts/scaffold_x_growth_project.py:59- Finding
Unchecked Overwrite of Files in an Arbitrary Target Directory
- Content
View full analysis
Vulnerability Details
File Location:
scripts/scaffold_x_growth_project.py, lines 59–61 and 78–89
Vulnerability Type: Unrestricted destination path with silent file overwrite
Risk Level: MediumVulnerable Code
python def write(path: Path, content: str): path.parent.mkdir(parents=True, exist_ok=True) path.write_text(content)python root = Path(args.path) root.mkdir(parents=True, exist_ok=True) write(root / "README.md", README) write( root / ".env.example", ENV_EXAMPLE .replace( "XGROWTH_DRY_RUN=true", f"XGROWTH_DRY_RUN={str(not profile.get('live_publish', False)).lower()}" ) .replace( "XGROWTH_PUBLISH_ENABLED=false", f"XGROWTH_PUBLISH_ENABLED={str(profile.get('live_publish', False)).lower()}" ) ) write(root / "prompts" / "llm-drafting.md", PROMPT) write(root / "config" / "style-rules.md", STYLE) write( root / "docs" / "operator-notes.md", "Fill in operator decisions, niche choices, language rules, community integration, rollout notes, and reply-lane safety rules here.\n\nSuggested live-mode notes:\n- preferred reply sources (mentions only vs broader)\n- what counts as a permanent reply failure\n- whether failed replies should skip or fallback\n- where publish results are logged\n- anti-repetition window (for example last 48h similarity threshold)\n- idempotent slot-key design (stable fields only; never draft text)\n" ) write(root / "scripts" / "doctor.py", DOCTOR)Technical Analysis
The script accepts a caller-controlled
--pathand creates that directory withexist_ok=True. It does not verify that the destination is new, empty, within an approved workspace, or free of symbolic links.The helper then uses
Path.write_text(), which opens existing files for writing and truncates their previous contents. Consequently, running the scaffold against an existing project can silently replace files such asREADME.md, ` ...[truncated 1827 chars]- Remediation
View remediation
Remediation Suggestions
-
Reject existing or non-empty destinations by default
- Fail if the target already exists and contains files.
- Require an explicit
--forceoption for intentional replacement.
-
Validate and constrain the destination
- Resolve the target with
Path.resolve(). - Reject filesystem roots, home directories, and other sensitive locations.
- When used by an Agent, require the resolved path to remain under an approved workspace root.
- Resolve the target with
-
Reject symbolic links
- Check the destination and relevant parent components for symbolic links before writing.
- Revalidate immediately before file creation to reduce time-of-check/time-of-use risk.
-
Use exclusive creation
- Create files using exclusive mode, such as
open("x"), when overwrite behavior is not explicitly requested. - If forced overwrite is supported, list affected files and request confirmation first.
- Create files using exclusive mode, such as
-
Provide backup and preview controls
- Add a
--dry-runoption that reports all files that would be created or replaced. - Back up existing files before an explicitly authorized overwrite.
- Add a
-
Validate profile input and fail safely
- Catch malformed JSON and invalid field types.
- Validate cadence values and caps before creating any files.
- Perform all validation before the first filesystem mutation.
-
