Back to skill

Security audit

油管视频转音频到飞书

Security checks for vulnerabilities and agentic risk

Overview

This skill has a coherent YouTube-to-Feishu goal, but the bundled code does not actually complete the promised upload flow and handles URLs, environment variables, and temporary audio files too broadly.

Review this before installing as a working uploader. In its current form it should be treated as a local YouTube audio downloader that may leave MP3 files on disk, not as a reliable Feishu upload-and-cleanup automation. It should be fixed to parse and allowlist YouTube URLs, use per-run temporary directories, delete files deterministically, enforce size limits, pass only required environment variables, pin dependencies, and report Feishu upload/send status only after those actions actually succeed.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (4)

T09 · Insecure Skill Coding Practices

Error
Location
index.js:65
Finding
Weak YouTube URL Validation Allows Requests to Unintended Network Targets<![CDATA[ ## Vulnerability Details **File Location**: `index.js:65-74`, with the accepted URL passed to `yt-dlp` at `youtube_upload.py:29-35` and `youtube_upload.py:51-60` **Vulnerability Type**: Improper URL validation and potential server-side request forgery **Risk Level**: High ### Vulnerable Code ```javascript async function youtube_upload(params, config) { const url = params.url; if (!url || !url.includes("youtube.com") && !url.includes("youtu.be")) { return { error: "Please provide a valid YouTube URL, e.g.: https://www.youtube.com/watch?v=..." }; } return _runPython([ "--url", url, ...(params.title ? ["--title", params.title] : []), ], config); } ``` The accepted value is subsequently supplied directly to `yt-dlp`: ```python info_cmd = [ "yt-dlp", "--dump-json", "--no-download", url ] ``` ```python download_cmd = [ "yt-dlp", "-x", "--audio-format", "mp3", "--audio-quality", "192K", "-o", output_template, url ] ``` ### Technical Analysis The JavaScript entry point treats any string containing `youtube.com` or `youtu.be` as a valid YouTube URL. Substring matching does not establish the URL scheme, parsed hostname, port, user-information component, or actual network destination. For example, a value such as `http://127.0.0.1:8080/resource#youtube.com` contains the accepted substring but targets a loopback service. Once accepted, the complete attacker-controlled value is passed as a discrete argument to `yt-dlp`. The use of `execFile` prevents ordinary shell metacharacter injection, but it does not prevent `yt-dlp` from making an outbound request to an unintended destination. Redirect handling also needs to be considered. Even an initially approved URL can potentially redirect to a destination outside the intended host allowlist unless redirects are checked or restricted. ### Attack Path 1. An attacker invokes `youtube_upload` with a URL whose fragment, path, query, or user-information ...[truncated 990 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse the input with the standard `URL` class rather than applying substring checks. 2. Require `https:` unless a documented use case explicitly requires another scheme. 3. Compare the normalized hostname against an explicit allowlist, such as: - `youtube.com` - `www.youtube.com` - `m.youtube.com` - `youtu.be` 4. Reject embedded credentials, unexpected ports, malformed URLs, IP-literal hosts, and hostnames that merely end in misleading text. 5. Restrict or validate redirects so that every redirect destination remains on the approved host allowlist. 6. Apply equivalent validation in the Python layer so the security boundary does not depend solely on the JavaScript wrapper. 7. Where possible, run the downloader with egress controls that deny loopback, link-local, and private-network destinations. Example validation: ```javascript function validateYouTubeUrl(value) { let parsed; try { parsed = new URL(value); } catch { return false; } const allowedHosts = new Set([ "youtube.com", "www.youtube.com", "m.youtube.com", "youtu.be", ]); return parsed.protocol === "https:" && allowedHosts.has(parsed.hostname.toLowerCase()) && !parsed.username && !parsed.password && !parsed.port; } ``` ]]>

T09 · Insecure Skill Coding Practices

Error
Location
youtube_upload.py:63
Finding
Shared Temporary Directory and Arbitrary MP3 Selection Can Return Another Invocation's File<![CDATA[ ## Vulnerability Details **File Location**: `youtube_upload.py:63-87` **Vulnerability Type**: Unsafe shared temporary-file handling and cross-invocation race condition **Risk Level**: High ### Vulnerable Code ```python # Download audio output_template = os.path.join(output_dir, "%(title)s.%(ext)s") download_cmd = [ "yt-dlp", "-x", # Extract audio "--audio-format", "mp3", "--audio-quality", "192K", "-o", output_template, url ] try: result = subprocess.run(download_cmd, capture_output=True, text=True, timeout=300) if result.returncode != 0: return {"error": f"Download failed: {result.stderr}"} # Find downloaded file downloaded_files = list(Path(output_dir).glob("*.mp3")) if not downloaded_files: return {"error": "No audio file found after download"} audio_file = downloaded_files[0] file_size = audio_file.stat().st_size file_size_mb = round(file_size / (1024 * 1024), 2) ``` The directory is shared by every invocation: ```python # Create temp directory temp_dir = os.path.join(os.path.dirname(__file__), "..", "..", "temp") os.makedirs(temp_dir, exist_ok=True) ``` ### Technical Analysis All executions write into the same predictable `../../temp` directory. After `yt-dlp` exits, the program scans every MP3 in that directory and selects the first item returned by `Path.glob()`. The selected file is not correlated with the current video ID, downloader output, process, start time, or invocation-specific directory. Directory iteration order is not a security guarantee. A stale file from an earlier run or a file generated concurrently can therefore be selected instead of the file created for the current request. The dispatched `youtube_upload.py` path also does not delete the returned MP3, making stale files persist and increasing the likelihood of cross-invocation selection. ### Attack Path 1. User A downloads an audio file, leaving it in the shared `../../temp` directory. 2. Us ...[truncated 1186 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create a private directory for every invocation using `tempfile.TemporaryDirectory()` or `tempfile.mkdtemp()`. 2. Set restrictive filesystem permissions where the platform supports them. 3. Use a collision-resistant output name based on a generated identifier rather than the video title. 4. Obtain the exact generated path from `yt-dlp`, for example through a controlled output template or machine-readable print option. 5. Resolve and verify the resulting path to ensure it remains beneath the invocation-specific directory. 6. Never identify the current result by selecting the first file from a shared glob. 7. Delete the invocation directory in a `finally` block after downstream processing completes. 8. If the file must outlive the Python process for a later upload, return a capability-bound reference and arrange deterministic deletion immediately after upload or after a short expiry period. 9. Add concurrency tests proving that simultaneous invocations cannot select each other's files. A safer structure would be: ```python with tempfile.TemporaryDirectory(prefix="youtube-audio-") as temp_dir: output_template = os.path.join(temp_dir, "%(id)s.%(ext)s") # Run yt-dlp and identify only the file created inside this directory. # Upload or securely transfer the file before the context exits. ``` ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
youtube_upload.py:51
Finding
Missing Download Size Enforcement and Cleanup Permit Storage Exhaustion<![CDATA[ ## Vulnerability Details **File Location**: `youtube_upload.py:51-87` and `youtube_upload.py:103-145` **Vulnerability Type**: Uncontrolled resource consumption and missing temporary-file cleanup **Risk Level**: Medium ### Vulnerable Code ```python download_cmd = [ "yt-dlp", "-x", # Extract audio "--audio-format", "mp3", "--audio-quality", "192K", "-o", output_template, url ] try: result = subprocess.run(download_cmd, capture_output=True, text=True, timeout=300) if result.returncode != 0: return {"error": f"Download failed: {result.stderr}"} # Find downloaded file downloaded_files = list(Path(output_dir).glob("*.mp3")) if not downloaded_files: return {"error": "No audio file found after download"} audio_file = downloaded_files[0] file_size = audio_file.stat().st_size file_size_mb = round(file_size / (1024 * 1024), 2) ``` The successful execution path returns the file information but performs no cleanup: ```python output = { "status": "success", "message": f"Audio downloaded: {result['file_name']} ({result['file_size_mb']} MB)", "video_info": { "title": result["video_title"], "id": result["video_id"], "duration": result["video_duration"], "url": result["video_url"], }, "file_info": { "path": result["file_path"], "name": result["file_name"], "size": result["file_size"], "size_mb": result["file_size_mb"], }, "next_steps": [ "1. Upload to Feishu cloud: feishu_drive_file (action=upload, file_path=<path>)", "2. Send to user: feishu_im_user_message (msg_type=file, content={'file_key': <token>})", ] } print(json.dumps(output, indent=2, ensure_ascii=False)) ``` ### Technical Analysis The Skill documentation declares a maximum file size of 100 MB and automatic cleanup, but the dispatched implementation enforces neither control. The five-minute process timeout limits wall ...[truncated 1498 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Enforce the documented limit before downloading when metadata provides a reliable expected size. 2. Pass an explicit downloader limit such as `--max-filesize 100M`. 3. Apply a post-download size check because metadata may be absent or inaccurate. 4. Delete files that exceed the permitted limit before returning an error. 5. Use a per-invocation temporary directory and remove it in a `finally` block on success, failure, cancellation, and timeout. 6. Explicitly terminate and reap the complete downloader/converter process tree when timeouts occur. 7. Configure filesystem quotas and global concurrency limits as defense in depth. 8. Limit video duration in addition to output bytes, because conversion can also consume substantial CPU. 9. Ensure cleanup happens only after the Feishu upload has actually completed, rather than retaining files indefinitely for an unspecified downstream process. 10. Monitor temporary-directory usage and periodically remove abandoned invocation directories using a narrowly scoped cleanup policy. Example downloader hardening: ```python download_cmd = [ "yt-dlp", "--max-filesize", "100M", "-x", "--audio-format", "mp3", "--audio-quality", "192K", "-o", output_template, url, ] ``` After download, independently verify: ```python max_size = 100 * 1024 * 1024 if audio_file.stat().st_size > max_size: audio_file.unlink(missing_ok=True) return {"error": "Downloaded audio exceeds the 100 MB limit"} ``` ]]>

T08 · Insecure Dependencies

Note
Location
requirements.txt:1
Finding
Unbounded yt-dlp Dependency Produces Non-Reproducible and Unsafe Installations<![CDATA[ ## Vulnerability Details **File Location**: `requirements.txt:1` **Vulnerability Type**: Unbounded third-party dependency version **Risk Level**: Low ### Vulnerable Code ```text yt-dlp>=2024.0.0 ``` The installation documentation also recommends an unpinned installation: ```bash pip install yt-dlp ``` ### Technical Analysis The requirement defines only a minimum version. Any future `yt-dlp` release satisfying the constraint can therefore be installed without project review. The resulting environment is not reproducible and can change when dependencies are resolved at different times. This finding does not establish that the current `yt-dlp` package is malicious. The risk arises because a future compromised, defective, or behaviorally incompatible release could be selected automatically. No package hashes are supplied to verify the exact artifact installed. Because `yt-dlp` is directly executed against attacker-supplied media URLs and writes files locally, compromise of that dependency would execute with the same filesystem and network privileges as the Skill. ### Attack Path 1. An administrator or automated installer processes `requirements.txt`. 2. The package resolver selects the newest available release satisfying `>=2024.0.0`. 3. A future compromised or otherwise unsafe release is downloaded because no upper bound, lock file, or hash prevents its selection. 4. The package is installed and later executed by the Skill. 5. Any malicious package behavior runs with the privileges of the installer or Skill process. This is a supply-chain exposure rather than evidence of a currently compromised dependency. ### Impact Assessment If the selected dependency release were compromised, it could access files, environment variables, and network resources available to the Python process. Installation hooks could also execute with the privileges used during package installation. The likelihood is lower than the directly exploitable coding flaws becaus ...[truncated 97 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin `yt-dlp` to an exact version that has been reviewed and tested. 2. Record transitive dependencies in a generated lock file where applicable. 3. Use hashes with `pip --require-hashes` to verify downloaded artifacts. 4. Update dependencies through a controlled review process rather than automatically accepting every future release. 5. Run dependency vulnerability and provenance checks in continuous integration. 6. Install dependencies in an isolated virtual environment as a non-privileged user. 7. Document the tested Python and FFmpeg versions because downloader behavior also depends on external binaries. Example form: ```text yt-dlp==<reviewed-version> \ --hash=sha256:<verified-distribution-hash> ``` The exact version and hash should be generated from a trusted package source and validated during the project's release process rather than copied without verification. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (20)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The skill claims to upload files to Feishu, but the finding indicates it only stores files locally and emits next-step instructions rather than actually invoking Feishu upload tools. While this is not an exploit primitive by itself, it is a trust and transparency problem that can cause users to believe data was transferred or cleaned up when it was not, leaving local artifacts behind.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The skill claims to upload files to Feishu, but the finding indicates it only stores files locally and emits next-step instructions rather than actually invoking Feishu upload tools. While this is not an exploit primitive by itself, it is a trust and transparency problem that can cause users to believe data was transferred or cleaned up when it was not, leaving local artifacts behind.

Credential Access

High
Category
Privilege Escalation
Content
return new Promise((resolve) => {
    const child = execFile(PYTHON, [SCRIPT_PATH, ...args], {
      maxBuffer: 50 * 1024 * 1024,
      env: { ...process.env, ...config?.env },
      cwd: TEMP_DIR,
    }, (error, stdout, stderr) => {
      if (error) {
Confidence
93% confidence
Finding
Merging `process.env` and `config?.env` into the subprocess environment gives the Python script access to all ambient credentials available to the Node process. If the Python script, its dependencies, or any invoked network-facing tooling are compromised or overly verbose, those credentials could be exfiltrated or misused, making this a real credential exposure risk.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The publishing guide promotes a workflow that downloads content from YouTube and uploads it to Feishu, but it does not clearly instruct publishers to present strong user-facing warnings about external data transfer, third-party processing, privacy implications, or account/permission scope. In a skill marketplace context, this omission can cause users to trigger transfers of potentially sensitive or copyrighted content to external services without informed consent or understanding of downstream effects.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
This markdown file documents behavior that affects user data and system integrity: it downloads remote content, uploads files to a third-party cloud service, sends messages on the user's behalf, and deletes temporary files. While the features are described, there is no clear cautionary warning about external data transfer, required trust in the destination account, or local file cleanup effects.

Lp3

Medium
Category
MCP Least Privilege
Confidence
87% confidence
Finding
The skill advertises command/tool behavior that relies on shell execution and environment variables, but it does not declare any explicit tool scope such as allowed-tools or permissions. This weakens security review and policy enforcement because the runtime capabilities are broader than what the manifest makes explicit, increasing the chance of unintended command execution or access to sensitive environment data.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The skill spawns a Python subprocess and forwards the full parent environment plus config-provided environment variables into it. This can expose secrets such as API tokens, cloud credentials, or session data to the child process and to any libraries it invokes, which is risky because the subprocess handles untrusted user-supplied URLs and its behavior is not disclosed or constrained here.

Description-Behavior Mismatch

Medium
Confidence
98% confidence
Finding
The script advertises a complete workflow including Feishu upload and message delivery, but those actions are only placeholders and never actually occur. This is dangerous because users may believe media was transferred to Feishu and handled there, while it remains stored locally, creating security, privacy, and operational mismatches.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The cleanup routine intentionally retains the just-downloaded audio file and only deletes older files later, without clearly warning the user that media persists locally. In this skill context, downloaded audio may contain private or copyrighted material, so silent retention on shared hosts or multi-user systems can expose data to unintended parties.

Intent-Code Divergence

Medium
Confidence
98% confidence
Finding
The final output claims the file was uploaded and sent even though the send step is commented out and upload_to_feishu only returns a placeholder status. False success reporting can cause users or downstream agents to stop verifying delivery, leaving sensitive files on disk and leading to data handling errors or accidental exposure.

Missing User Warnings

Medium
Confidence
85% confidence
Finding
The skill sends the user-provided URL to yt-dlp, which causes network communication with YouTube and possibly related hosts, but this is not clearly disclosed in the user-facing behavior. While expected for a YouTube downloader, lack of explicit disclosure can still create privacy and consent issues around third-party contact and metadata exposure.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
]
    
    try:
        result = subprocess.run(info_cmd, capture_output=True, text=True, timeout=60)
        if result.returncode != 0:
            return {"error": f"Failed to get video info: {result.stderr}"}
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
]
    
    try:
        result = subprocess.run(info_cmd, capture_output=True, text=True, timeout=60)
        if result.returncode != 0:
            return {"error": f"Failed to get video info: {result.stderr}"}
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
]
    
    try:
        result = subprocess.run(download_cmd, capture_output=True, text=True, timeout=300)
        if result.returncode != 0:
            return {"error": f"Download failed: {result.stderr}"}
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
]
    
    try:
        result = subprocess.run(download_cmd, capture_output=True, text=True, timeout=300)
        if result.returncode != 0:
            return {"error": f"Download failed: {result.stderr}"}
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Description-Behavior Mismatch

Medium
Confidence
98% confidence
Finding
The skill metadata claims it uploads to Feishu cloud storage, but the code only downloads media locally and prints manual follow-up instructions. This mismatch can mislead operators about what actions are automated, what data remains on disk, and whether additional human or agent steps will transmit files elsewhere.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The skill saves downloaded audio into a persistent temp directory under the project tree without clearly disclosing local file creation, retention, or cleanup behavior. This can expose potentially sensitive media artifacts to other users, later processes, or accidental reuse if the environment is shared.

Unpinned Dependencies

Low
Category
Supply Chain
Content
yt-dlp>=2024.0.0
Confidence
95% confidence
Finding
The dependency is specified as `yt-dlp>=2024.0.0`, which allows installation of any newer version and makes builds non-reproducible. This increases supply-chain risk because a future compromised or incompatible release could be pulled in without review, and it also prevents verifying whether known advisories affect the resolved version.

Unverifiable Dependency: yt-dlp has 16 known advisory(ies) (CVE-2023-46121 (yt-dlp Generic Extractor MITM Vulnerability via Arbitrary Proxy Injection); GHSA-3v33-3wmw-3785 (yt-dlp has dependency on potentially malicious third-party code in Douyu extract); CVE-2023-40581 ( yt-dlp on Windows vulnerable to `--exec` command injection when using `%q`) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
92% confidence
Finding
The manifest uses `yt-dlp` without pinning to a specific release, while the package has multiple published advisories. In a skill that downloads media from untrusted remote sites, use of a vulnerable `yt-dlp` version could be more dangerous because parsing attacker-controlled metadata or invoking extractor logic may expose the host to command injection, unsafe network behavior, or malicious third-party code paths depending on the installed version and platform.

Missing User Warnings

Low
Confidence
73% confidence
Finding
The script invokes yt-dlp with the provided YouTube URL, which results in network requests to external services to retrieve metadata and download content. While the action is functionally expected, the user-facing documentation and prompts do not explicitly disclose that the supplied URL and related request data will be transmitted over the network.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
index.js:21