T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/video_downloader.py:139
- Finding
- Unsafe Selection and Overwrite of Pre-existing Media Files<![CDATA[ ## Vulnerability Details **File Location**: `scripts/video_downloader.py`, lines 139-149 **Vulnerability Type**: Unsafe file selection and overwrite **Risk Level**: Medium ### Vulnerable Code ```python files = [f for f in os.listdir(output_dir) if f.endswith(('.mp4', '.mkv', '.webm', '.mov', '.avi'))] if not files: raise Exception('未找到下载的视频文件') video_path = os.path.join(output_dir, files[0]) safe_name = sanitize_filename(files[0]) if safe_name != files[0]: new_path = os.path.join(output_dir, safe_name) os.rename(video_path, new_path) video_path = new_path video_path = merge_audio_video_if_needed(video_path, output_dir) size_mb = os.path.getsize(video_path) / (1024*1024) ``` ### Technical Analysis After `yt-dlp` completes, the script enumerates every recognized media file in the supplied output directory and selects `files[0]`. It does not determine which file was created by the current download. Because filesystem enumeration order is not a reliable creation-order guarantee, the selected file can be an unrelated pre-existing file. The selected filename is then sanitized and renamed. The destination path is not checked for an existing file. On operating systems where `os.rename()` replaces an existing destination, this can overwrite another file in the output directory. The implementation also does not reject symbolic links or verify that the selected entry is a regular file. The paths remain confined to the selected output directory because `sanitize_filename()` applies `os.path.basename()`. Therefore, this does not directly provide arbitrary path traversal, but it can still cause incorrect file processing, unintended file replacement, and disclosure of an unrelated local media path. ### Attack Path 1. The victim selects a shared or attacker-influenced directory as the download output directory. 2. The attacker places one or more pre-existing files with supported media extensions in that directory. 3. Optionally, the attacker ...[truncated 1479 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Capture the exact output path produced by `yt-dlp` instead of scanning the entire directory. For example, use `--print after_move:filepath` and parse the resulting absolute path, or use the official `yt-dlp` Python API and obtain the final requested-download path from its metadata. 2. Create each download in a fresh, private temporary directory with restrictive permissions. Move the completed file into a user-selected destination only after validating it. 3. Verify that the resulting path is located under the intended directory using canonicalized paths, such as `Path.resolve()` and `Path.relative_to()`. 4. Reject symbolic links and non-regular files before probing, renaming, merging, or returning the file. 5. Avoid destructive renames. Before moving a file, check whether the destination exists and generate a unique name or fail safely. 6. Where supported, use exclusive file-creation or rename mechanisms that cannot silently replace an existing destination. 7. If directory scanning remains necessary, record the directory state before downloading and only consider newly created files afterward. Capturing `yt-dlp`'s exact output path is still preferable because before-and-after scans can have race conditions. ]]>
