T09 · Insecure Skill Coding Practices
- Location
scripts/organizer.py:52- Finding
Existing Files Can Be Overwritten During Type-Based Organization
- Content
View full analysis
Vulnerability Details
File Location:
scripts/organizer.py, lines 52–58
Vulnerability Type: Unsafe destination collision handling
Risk Level: MediumVulnerable Code
python target_dir = folder / category if not target_dir.exists(): target_dir.mkdir(exist_ok=True) new_path = target_dir / item.name # Avoid overwriting files with the same name if new_path.exists(): new_path = target_dir / f"{item.stem}_{item.suffix}" shutil.move(str(item), str(new_path))Technical Analysis
The code checks whether the original destination exists, but its fallback destination is not checked for another collision. For a source file named
report.txt, the fallback expression producesreport_.txt. If bothDocuments/report.txtandDocuments/report_.txtalready exist, the program still passes the occupied fallback path toshutil.move.On platforms where the underlying move or rename operation replaces an existing destination, this silently overwrites
Documents/report_.txt. On platforms that reject replacement, the operation can instead fail and interrupt organization. The existence check and move are also separate operations, so another process could create the destination between them.Attack Path
- The victim selects a directory containing a source file named
report.txt. - The directory already contains
Documents/report.txt. - The directory also contains
Documents/report_.txt, which holds data the victim wants to preserve. - The victim runs:
bash python3 scripts/organizer.py by-type /path/to/directory - The organizer detects the first collision and selects
Documents/report_.txt. - Because it does not verify that fallback path,
shutil.movemay replace the existing fallback file.
An attacker who can create files in the selected directory can prepare this collision layout, but exploitation does not require an attacker: ordinary repeated org ...[truncated 427 chars]
- The victim selects a directory containing a source file named
- Remediation
View remediation
Remediation Suggestions
Generate and validate candidate names until a free destination is found:
python new_path = target_dir / item.name counter = 1 while new_path.exists(): new_path = target_dir / f"{item.stem}_{counter}{item.suffix}" counter += 1 shutil.move(str(item), str(new_path))Where supported, use an atomic no-replace operation to prevent a time-of-check/time-of-use race. If atomic no-replace semantics are unavailable, catch destination-collision errors and retry with a new candidate. The application should also log every final source and destination and clearly report failures instead of silently replacing files.
