T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/design_system.py:508
- Finding
- Path Traversal Allows Files to Be Written Outside the Intended Design-System Directory<![CDATA[ ## Vulnerability Details **File Location**: `scripts/design_system.py`, lines 508-536 **Vulnerability Type**: Path traversal and arbitrary file overwrite **Risk Level**: High ### Vulnerable Code ```python base_dir = Path(output_dir) if output_dir else Path.cwd() # Use project name for project-specific folder project_name = design_system.get("project_name", "default") project_slug = project_name.lower().replace(' ', '-') design_system_dir = base_dir / "design-system" / project_slug pages_dir = design_system_dir / "pages" created_files = [] # Create directories design_system_dir.mkdir(parents=True, exist_ok=True) pages_dir.mkdir(parents=True, exist_ok=True) master_file = design_system_dir / "MASTER.md" # Generate and write MASTER.md master_content = format_master_md(design_system) with open(master_file, 'w', encoding='utf-8') as f: f.write(master_content) created_files.append(str(master_file)) # If page is specified, create page override file with intelligent content if page: page_file = pages_dir / f"{page.lower().replace(' ', '-')}.md" page_content = format_page_override_md(design_system, page, page_query) with open(page_file, 'w', encoding='utf-8') as f: f.write(page_content) created_files.append(str(page_file)) ``` ### Technical Analysis The `project_name` and `page` values are incorporated into filesystem paths after only replacing spaces with hyphens. This transformation does not remove or reject: - Parent-directory components such as `..` - Forward or backward path separators - Absolute paths - Platform-specific drive or UNC path syntax - Symbolic-link redirections The resulting paths are not resolved and checked against the intended `design-system` directory before directories are created and files are opened in write mode. Because `open(..., 'w')` truncates an existing file, traversal can overwrite accessible Markdown files outside the expected output tree. The `page` parameter is particularly dangerous ...[truncated 2237 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Convert project and page names using a strict allowlist: ```python import re def safe_slug(value: str) -> str: slug = value.strip().lower().replace(" ", "-") if not re.fullmatch(r"[a-z0-9][a-z0-9_-]{0,63}", slug): raise ValueError("Invalid project or page name") return slug ``` 2. Resolve the intended root and every destination before writing: ```python root = (base_dir / "design-system").resolve() project_dir = (root / safe_slug(project_name)).resolve() pages_dir = (project_dir / "pages").resolve() page_file = (pages_dir / f"{safe_slug(page)}.md").resolve() ``` 3. Verify containment with `Path.relative_to()`: ```python try: page_file.relative_to(pages_dir) except ValueError: raise ValueError("Output path escapes the pages directory") ``` 4. Reject absolute paths, path separators, `..`, drive prefixes, and empty names before constructing output paths. 5. Consider using exclusive creation mode (`'x'`) by default. Require an explicit overwrite option before truncating existing files. 6. Check for symbolic links in parent directories when operating in an untrusted workspace. Where practical, refuse to write through symlinked output directories. 7. Add tests covering Unix and Windows traversal forms, absolute paths, nested separators, symlink escapes, and overwrite attempts. ]]>
