T09 · Insecure Skill Coding Practices
- Location
scripts/config-sync.py:82- Finding
Repository-Controlled Symlinks Allow File Reads and Writes Outside the Target Repository
- Content
View full analysis
- Remediation
View remediation
Path: resolved_repo = repo.resolve(strict=True) resolved_path = path.resolve(strict=False) if not resolved_path.is_relative_to(resolved_repo): raise ValueError(f"Path escapes repository: {path}") return resolved_path ``` 2. Explicitly reject symbolic links for source files, output files, and each relevant parent directory. Do not rely only on lexical path checks. 3. For source files, use `lstat()` or equivalent no-follow checks before opening them. Recheck at open time where possible to reduce time-of-check/time-of-use race conditions. 4. For output files, use no-follow file-opening semantics such as `os.open()` with `O_NOFOLLOW` on platforms that support it. 5. Write output to a securely created temporary file inside the validated destination directory, flush and synchronize it, and then atomically replace the intended destination after repeating boundary and symlink checks. 6. Refuse to operate when `.claude`, `.claude/rules`, an output directory, or an existing output file is a symlink. 7. Add automated tests covering: - Symlinked `.claude/rules/*.md` files. - A symlinked `.claude/rules` directory. - Symlinked output files. - Symlinked output parent directories. - Paths that resolve outside the repository. ]]>
