T09 · Insecure Skill Coding Practices
- Location
SKILL.md:29- Finding
Unrestricted Rename Destination Allows Path Traversal
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md, lines 29-36
Vulnerability Type: Unrestricted destination path / path traversal
Risk Level: Highpython renamed = [] for filename in os.listdir(directory): new_name = re.sub(pattern, replacement, filename) if new_name != filename: old_path = os.path.join(directory, filename) new_path = os.path.join(directory, new_name) os.rename(old_path, new_path) renamed.append((filename, new_name))Technical Analysis
The generated
new_nameis derived from the caller-controlled regular-expression replacement and is passed toos.path.join()without validation. A replacement can contain parent-directory components such as../, path separators, or an absolute path.If
new_nameis absolute,os.path.join(directory, new_name)discards the intended base directory. If it contains parent-directory components, path resolution can escape the selected directory. The same underlying weakness is also present in the documentedsafe_rename()implementation at lines 123-150. Its dry-run option does not make an actual run safe because destination paths remain unrestricted whendry_run=False.Attack Path
- An attacker influences the
replacementvalue supplied tobatch_rename()orsafe_rename(). - The attacker provides a replacement containing an escape path, such as
../target/\1, or an absolute destination path. re.sub()produces a destination name containing that path.os.path.join()constructs a destination outside the requested directory.- When execution reaches
os.rename(), a source entry is moved to an unintended writable location. - If a destination already exists and the operating system permits replacement, that destination may be overwritten.
Impact Assessment
The operation runs with the privileges of the Python process. An attacker can move affected files to any destinat ...[truncated 339 chars]
- An attacker influences the
- Remediation
View remediation
Remediation Suggestions
- Accept only a basename as the generated destination name.
- Reject absolute paths,
..components, directory separators, NUL characters, and platform-specific alternate separators. - Resolve the base and destination paths with
pathlib.Path.resolve()and verify that the destination remains a direct child of the resolved base directory. - Perform the boundary check immediately before renaming to reduce time-of-check/time-of-use exposure.
- Do not rely on a dry run as a security control; repeat all validation during the actual operation.
- Require explicit authorization before replacing any existing destination.
- Consider using directory file descriptors and relative rename operations on platforms that support them to constrain filesystem operations more robustly.
