T09 · Insecure Skill Coding Practices
- Location
scripts/run_task.py:78- Finding
Configuration-Controlled Path Traversal Enables File Movement Outside the Intended Destination
- Content
View full analysis
Vulnerability Details
File Location:
scripts/run_task.py, lines 78-96
Vulnerability Type: Unvalidated destination path / path traversal
Risk Level: HighVulnerable Code
python for file in source.iterdir(): if file.is_file(): ext = file.suffix.lower() target_folder = None for rule in rules: if rule.get('extension', '').lower() == ext: target_folder = rule.get('folder', 'Other') break if target_folder is None: target_folder = 'Other' target_path = destination / target_folder if self.dry_run: self.log(f"Would move: {file.name} -> {target_folder}/") else: target_path.mkdir(parents=True, exist_ok=True) shutil.move(str(file), str(target_path / file.name))Technical Analysis
The
folderproperty is read directly from task configuration and appended to the configured destination without validation or containment checking. Python path composition does not guarantee that the resulting path remains underdestination.A value containing parent-directory components, such as
../../target, traverses outside the intended destination. An absolutefolderpath can replace the destination entirely when the paths are combined. The code then creates the attacker-selected directory and moves every matching regular file from the source directory into it.This violates least privilege because a file-organization task should only modify files within its explicitly configured source and destination boundaries. The implementation instead allows configuration authors to select any filesystem destination writable by the process.
Attack Path
- An attacker supplies or modifies a file-organizer configuration accessible to the user or automation system.
- The attacker adds a matching rule conta ...[truncated 1839 chars]
- Remediation
View remediation
Remediation Suggestions
Treat all paths and folder names from configuration as untrusted input.
- Reject absolute values for
target_folder. - Resolve both the destination root and candidate target path before performing any filesystem operation.
- Require the resolved candidate path to remain strictly beneath the resolved destination root.
- Reject
.., empty folder names, and unexpected path separators if each rule is intended to specify only one directory name. - Define an explicit collision policy rather than allowing platform-dependent overwrites.
- Validate the source and destination against an approved workspace boundary when the skill runs in an agent environment.
- Perform validation in dry-run mode as well, so unsafe configurations are reported before live execution.
Example hardening:
python destination_root = destination.resolve() folder_value = rule.get("folder", "Other") if not isinstance(folder_value, str) or not folder_value.strip(): raise ValueError("Rule folder must be a non-empty string") folder_path = Path(folder_value) if folder_path.is_absolute() or ".." in folder_path.parts: raise ValueError(f"Unsafe target folder: {folder_value}") target_path = (destination_root / folder_path).resolve() if not target_path.is_relative_to(destination_root): raise ValueError(f"Target escapes destination: {folder_value}") target_file = target_path / file.name if target_file.exists(): raise FileExistsError(f"Refusing to overwrite: {target_file}") target_path.mkdir(parents=True, exist_ok=True) shutil.move(str(file), str(target_file))For Python versions without
Path.is_relative_to(), useos.path.commonpath()with resolved paths and verify that the common path equals the approved destination root.- Reject absolute values for
