T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/batch_rename.py:46
- Finding
- Path Traversal and File Overwrite Through Unvalidated Rename Parameters<![CDATA[ ## Vulnerability Details **File Location**: `scripts/batch_rename.py`, lines 46-69 **Vulnerability Type**: Unvalidated destination path and unsafe file replacement **Risk Level**: High ### Vulnerable Code ```python if mode == 'sequence': new_name = f"{prefix}{str(start_num + i).zfill(3)}{suffix}{ext}" elif mode == 'date': date_str = datetime.now().strftime(date_format) new_name = f"{prefix}{date_str}{suffix}{ext}" elif mode == 'prefix': new_name = f"{prefix}{name}{suffix}{ext}" elif mode == 'suffix': new_name = f"{name}{suffix}{ext}" elif mode == 'replace': new_name = filename.replace(replace_old, replace_new) else: print(f"Unknown renaming mode: {mode}") continue new_path = os.path.join(folder_path, new_name) # Check for duplicate names if old_path == new_path: continue if dry_run: print(f"Preview: {filename} → {new_name}") else: try: os.rename(old_path, new_path) ``` ### Technical Analysis The `prefix`, `suffix`, `replace_old`, and `replace_new` command-line values are incorporated into `new_name` without rejecting absolute paths, parent-directory components, or platform-specific directory separators. Passing a value containing `../`, `..\`, or an absolute path can cause `os.path.join()` to produce a destination outside the selected directory. The comment stating that duplicate names are checked is inaccurate. The code only detects a no-op rename where the source and destination strings are identical. It does not detect: - Multiple source files mapping to the same destination. - A destination that already exists. - A destination that resolves outside `folder_path`. - Case-insensitive collisions on Windows. - Symlink or junction traversal. On platforms and filesystems where `os.rename()` replaces an existing ...[truncated 1223 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Reject absolute paths, parent-directory components, null bytes, and both Windows and POSIX path separators in all filename parameters. 2. Resolve the source directory and every proposed destination with `Path.resolve()`, then verify that the destination remains a direct child of the source directory. 3. Precompute the complete rename plan before changing any files. 4. Reject duplicate destinations, case-folded collisions, and destinations that already exist. 5. Use a two-phase rename through uniquely generated temporary names to prevent source-to-destination cycles. 6. Refuse replacement by default. If replacement is required, expose an explicit `--overwrite` option and request confirmation. 7. Record an operation journal or provide a rollback manifest. 8. Avoid running the utility with administrative privileges. ]]>
