T09 · Insecure Skill Coding Practices
- Location
SKILL.md:274- Finding
Path Traversal and Destructive File Replacement in Bulk Rename Helper
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md, lines 274–281
Vulnerability Type: Unvalidated destination path construction and unsafe file rename
Risk Level: Mediumpython def batch_rename(directory, pattern, replacement): """批量重命名文件""" for filename in os.listdir(directory): new_filename = re.sub(pattern, replacement, filename) if new_filename != filename: old_path = os.path.join(directory, filename) new_path = os.path.join(directory, new_filename) os.rename(old_path, new_path) print(f"Renamed: {filename} -> {new_filename}")Technical Analysis
The function accepts a regular-expression pattern and replacement value without validating the resulting filename. The value produced by
re.sub()is passed directly toos.path.join()and then toos.rename().A replacement containing
.., path separators, or an absolute path can cause the destination to resolve outside the intended archive directory. The function also does not detect destination collisions or require confirmation before moving files. Depending on operating-system behavior,os.rename()may replace an existing destination.The vulnerability is exploitable when an untrusted user or upstream Agent can influence
pattern,replacement, or other rename-rule input passed to this helper.Attack Path
- An attacker or untrusted workflow supplies a crafted replacement value, such as
../target.pdf. re.sub(pattern, replacement, filename)generates a destination containing traversal components.os.path.join(directory, new_filename)constructs a path outside the intended archive directory.os.rename(old_path, new_path)moves the financial document to that external location.- If the destination already exists and the platform permits replacement, the operation may overwrite it without warning.
Impact Assessment
Exploitation occurs with the filesystem privileges of the process ...[truncated 516 chars]
- An attacker or untrusted workflow supplies a crafted replacement value, such as
- Remediation
View remediation
Remediation Suggestions
- Permit only a basename as the generated filename; reject absolute paths,
..,/,\, empty names, and platform-specific reserved names. - Resolve the archive root and destination with
pathlib.Path.resolve(), then verify that the destination remains beneath the resolved archive root. - Reject existing destinations rather than relying on platform-specific
os.rename()replacement behavior. - Validate
patternandreplacementbefore processing and catch invalid regular expressions. - Generate a complete rename plan first, detect duplicate destinations, and present a dry run for confirmation.
- Use an atomic no-replace operation where supported.
- Record successful and failed rename operations in an audit log.
- Run the operation with filesystem permissions limited to the intended archive directory.
A hardened containment check should follow this model:
python from pathlib import Path import os import re def batch_rename(directory, pattern, replacement): root = Path(directory).resolve() rename_plan = [] for entry in root.iterdir(): if not entry.is_file(): continue new_name = re.sub(pattern, replacement, entry.name) if ( not new_name or Path(new_name).is_absolute() or new_name != Path(new_name).name or new_name in {".", ".."} ): raise ValueError(f"Unsafe destination filename: {new_name!r}") destination = (root / new_name).resolve() if destination.parent != root: raise ValueError("Destination escapes the archive directory") if destination.exists(): raise FileExistsError(f"Destination already exists: {destination}") if entry != destination: rename_plan.append((entry, destination)) for source, destination in rename_plan: os.rename(source, destination)- Permit only a basename as the generated filename; reject absolute paths,
