Back to skill

Security audit

支持从 YouTube、Bilibili、抖音及所有 yt-dlp 兼容平台下载视频,可自动选择最佳分辨率、合并音视频并清理文件名

Security checks for vulnerabilities and agentic risk

Overview

This is a straightforward video-downloader skill, but users should choose output folders carefully and avoid untrusted URLs.

Install only if you are comfortable with a tool that fetches user-provided video URLs and writes media files locally. Use a fresh, private output directory for each download, avoid shared or untrusted folders, and do not use it for internal, localhost, or otherwise sensitive URLs.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

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. ]]>
Vulnerability Patterns
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (8)

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill advertises shell execution, file reads, and file writes via its described use of yt-dlp/ffmpeg and local output paths, but it does not declare any explicit tool scope such as permissions or allowed-tools. This creates an authorization gap: an agent may invoke broader capabilities than reviewers or policy expect, increasing the risk of unsafe command execution, arbitrary file access, or writes to unintended locations.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The manifest description and the entire user-facing documentation are written only in Chinese, with no indication that other languages are supported or that Chinese is required for a region-specific purpose. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy violation.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The module docstring and all user-facing usage text are written only in Chinese, which imposes a specific language on users without opt-in. The policy explicitly flags language or locale constraints unless the skill offers a choice or documents a justified regional scope.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def has_audio_stream(filepath):
    try:
        result = subprocess.run(
            ['ffprobe', '-v', 'error', '-select_streams', 'a', '-show_entries', 'stream=codec_type', '-of', 'csv=p=0', filepath],
            capture_output=True, text=True, timeout=10
        )
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def has_video_stream(filepath):
    try:
        result = subprocess.run(
            ['ffprobe', '-v', 'error', '-select_streams', 'v', '-show_entries', 'stream=codec_type', '-of', 'csv=p=0', filepath],
            capture_output=True, text=True, timeout=10
        )
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
merged_path = os.path.join(output_dir, f'{base_name}_merged.mp4')
            cmd = ['ffmpeg', '-i', video_path, '-i', other_file, '-c:v', 'copy', '-c:a', 'aac', '-map', '0:v:0', '-map', '1:a:0', merged_path]
            try:
                subprocess.run(cmd, check=True, capture_output=True, timeout=120)
                if os.path.exists(merged_path):
                    print(f'合并完成: {merged_path}')
                    return merged_path
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
print('获取视频格式信息...')
    list_cmd = ['yt-dlp', '-F', '--no-warnings', url]
    try:
        result = subprocess.run(list_cmd, capture_output=True, text=True, timeout=30, encoding='utf-8')
        lines = result.stdout.splitlines()
    except Exception as e:
        raise Exception(f'获取格式列表失败: {e}')
Confidence
76% confidence
Finding
The script passes an untrusted user-supplied URL directly to yt-dlp, which can trigger outbound network access to arbitrary hosts and potentially internal services depending on the runtime environment. While this is not shell injection, it does create an SSRF-like/network pivot risk because the tool is explicitly a downloader and the skill context encourages fetching attacker-controlled URLs.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
url
    ]
    try:
        subprocess.run(download_cmd, check=True, timeout=600, capture_output=True, text=True, encoding='utf-8')
    except subprocess.CalledProcessError as e:
        raise Exception(f'下载失败: {e.stderr}')
    files = [f for f in os.listdir(output_dir) if f.endswith(('.mp4', '.mkv', '.webm', '.mov', '.avi'))]
Confidence
84% confidence
Finding
This is the main yt-dlp download execution path and accepts an arbitrary user-controlled URL, causing the host to retrieve attacker-chosen remote content. In agent or server environments, that can be abused for SSRF-style access, bandwidth/disk exhaustion, or retrieval of hostile media/content via a trusted system.

Static analysis

No suspicious patterns detected.