T09 · Insecure Skill Coding Practices
- Location
scripts/pipeline_deployment.py:63- Finding
Deployment Operations Can Escape the Target Directory Through Symbolic Links
- Content
View full analysis
Vulnerability Details
File Location:
scripts/pipeline_deployment.py, lines 63–71 and 108–116
Vulnerability Type: Unvalidated symbolic-link traversal during deployment and rollback
Risk Level: HighVulnerable Code
python for source_file in self.source.rglob('*'): if source_file.is_file(): relative_path = source_file.relative_to(self.source) target_file = self.target / relative_path try: target_file.parent.mkdir(parents=True, exist_ok=True) shutil.copy2(source_file, target_file) self.deployed.append(str(relative_path)) print(f" ✓ Deployed: {relative_path}")python for deployed_file in self.deployed: file_path = self.target / deployed_file if file_path.exists(): file_path.unlink() print(f" ✓ Removed: {deployed_file}") # Remove empty directories for dir_path in sorted(self.target.rglob('*'), reverse=True): if dir_path.is_dir() and not any(dir_path.iterdir()): dir_path.rmdir()Technical Analysis
The deployment utility constructs destination paths by joining an unvalidated relative source path to the target directory. It does not resolve the resulting path and verify that it remains under the intended deployment root.
Path.is_file()andshutil.copy2()can follow symbolic links. A symbolic-link file in the source can therefore cause data outside the source directory to be copied. Separately, a pre-existing symbolic-link directory beneath the target can redirect writes outside the intended target directory.The rollback implementation reconstructs file paths from the same unvalidated relative names and calls
unlink(). If an intermediate target component is a symbolic link, rollback can reach and delete a file outside the deployment root.Attack Path
- An attacker controls part of the source tree or can prepare the target directory. 2 ...[truncated 1216 chars]
- Remediation
View remediation
Remediation Suggestions
- Resolve the source root and target root before processing files.
- Resolve each source and destination path and verify containment using
Path.is_relative_to()or an equivalent robust check. - Reject symbolic links in the source tree and in every target path component.
- Use file operations that do not follow symbolic links where supported.
- Deploy into a newly created directory owned by the invoking account rather than an existing, potentially attacker-controlled directory.
- Before rollback, repeat the containment and symbolic-link checks.
- Avoid relying on string-prefix comparisons for path validation.
- Run deployment under a dedicated, least-privileged account.
- Add automated tests covering source symlinks, target-directory symlinks, nested links, and rollback behavior.
