Back to skill

Security audit

Youtube Downloader

Security checks for vulnerabilities and agentic risk

Overview

The skill broadly matches its stated purpose, but weak URL and filename validation could let crafted inputs download from unintended sites or save files outside the intended video asset folder.

Review this skill before installing. It is intended to download videos into your OpenClaw asset folder, but it should add strict hostname validation, canonical YouTube video ID validation, path containment checks, and reasonable file-size/source controls before use with untrusted URLs or users.

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 (2)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/download.sh:15
Finding
Weak YouTube URL Validation Permits Requests to Arbitrary Hosts<![CDATA[ ## Vulnerability Details **File Location**: `scripts/download.sh`, lines 15–25 and 44–51 **Vulnerability Type**: Insufficient URL validation **Risk Level**: Medium ### Vulnerable Code ```bash # Extract video ID if [[ "$URL" == *"youtu.be/"* ]]; then VIDEO_ID=$(echo "$URL" | sed 's/.*youtu\.be\///' | sed 's/\?.*//') elif [[ "$URL" == *"youtube.com/watch"* ]]; then VIDEO_ID=$(echo "$URL" | sed 's/.*v=//' | sed 's/&.*//') elif [[ "$URL" == *"youtube.com/shorts/"* ]]; then VIDEO_ID=$(echo "$URL" | sed 's/.*shorts\///' | sed 's/\?.*//') else echo "ERROR: Invalid YouTube URL" exit 1 fi # Download with yt-dlp at best quality yt-dlp \ -f "bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best" \ --merge-output-format mp4 \ -o "$OUTPUT_PATH" \ --no-playlist \ --no-warnings \ "$URL" ``` ### Technical Analysis The script determines whether a URL is a YouTube URL using shell substring comparisons. It does not parse the URL or verify that its hostname is an authorized YouTube domain. For example, the following attacker-controlled URL contains the accepted string but does not belong to YouTube: ```text https://attacker.example/youtube.com/watch?v=test ``` Because the string contains `youtube.com/watch`, it passes validation and is supplied directly to `yt-dlp`. Depending on the protocols and extractors supported by the installed `yt-dlp` version, this can cause the process to connect to and retrieve content from an attacker-selected host. This is not shell command injection because `"$URL"` is quoted. The security problem is that the semantic destination of the network request is not restricted to the declared YouTube service. ### Attack Path 1. An attacker or untrusted user submits a URL whose path or query contains an accepted YouTube substring. 2. The substring comparison treats the URL as an authorized YouTube URL without validating its hostname. 3. The complete attacker-controlled URL is passed to `yt-dlp ...[truncated 901 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Parse and validate the URL before invoking `yt-dlp`: 1. Require the `https` scheme. 2. Compare the parsed hostname against an explicit allowlist such as: - `youtube.com` - `www.youtube.com` - `m.youtube.com` - `youtu.be` 3. Reject hostnames that merely end with or contain an allowed name, such as `youtube.com.attacker.example`. 4. Reject URLs containing user-information components that may obscure the actual host. 5. Restrict accepted paths to the documented watch, short-link, and shorts formats. 6. Validate the port or reject non-default ports. 7. Consider resolving the hostname and applying network egress controls if requests to private or loopback address ranges are not required. A structured URL parser should be used instead of substring matching. After validation, pass a canonicalized URL to `yt-dlp`. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/download.sh:15
Finding
Unvalidated Video Identifier Is Embedded in the Output Path and yt-dlp Template<![CDATA[ ## Vulnerability Details **File Location**: `scripts/download.sh`, lines 15–35 and 44–49 **Vulnerability Type**: Path traversal and output-template injection **Risk Level**: Medium ### Vulnerable Code ```bash # Extract video ID if [[ "$URL" == *"youtu.be/"* ]]; then VIDEO_ID=$(echo "$URL" | sed 's/.*youtu\.be\///' | sed 's/\?.*//') elif [[ "$URL" == *"youtube.com/watch"* ]]; then VIDEO_ID=$(echo "$URL" | sed 's/.*v=//' | sed 's/&.*//') elif [[ "$URL" == *"youtube.com/shorts/"* ]]; then VIDEO_ID=$(echo "$URL" | sed 's/.*shorts\///' | sed 's/\?.*//') else echo "ERROR: Invalid YouTube URL" exit 1 fi # Sanitize label (remove special chars, replace spaces with underscores) SAFE_LABEL=$(echo "$LABEL" | tr ' ' '_' | tr -cd '[:alnum:]_-') # Output filename FILENAME="${SAFE_LABEL}_${VIDEO_ID}_${TIMESTAMP}.mp4" OUTPUT_PATH="$OUTPUT_DIR/$FILENAME" # Download with yt-dlp at best quality yt-dlp \ -f "bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best" \ --merge-output-format mp4 \ -o "$OUTPUT_PATH" \ --no-playlist \ --no-warnings \ "$URL" ``` ### Technical Analysis Although the label is sanitized, `VIDEO_ID` is extracted with unrestricted text substitutions and is never validated. It can consequently contain directory separators, traversal components, control characters, or percent-based expressions. The resulting value is incorporated into both: - A filesystem path stored in `OUTPUT_PATH`. - The `yt-dlp` output template passed through `-o`. Directory components such as `../` can cause the resolved output location to escape the intended `assets/videos` directory. Percent expressions are also significant because `yt-dlp` interprets its output argument as a template rather than as a purely literal filename. The value is quoted, so this does not directly create shell metacharacter injection. The vulnerability instead arises after the shell passes the attacker-influenced value to filesystem and `yt-dlp` templ ...[truncated 1493 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Apply strict validation before using the identifier in any filename: 1. Require a canonical YouTube video identifier format, for example: ```bash if [[ ! "$VIDEO_ID" =~ ^[A-Za-z0-9_-]{11}$ ]]; then echo "ERROR: Invalid YouTube video ID" exit 1 fi ``` 2. Prefer obtaining the identifier from validated `yt-dlp` metadata rather than extracting it with regular-expression substitutions. 3. Reject slashes, backslashes, dots used as traversal components, control characters, and percent characters. 4. Canonicalize the parent directory and final output path, then verify that the final path remains beneath `OUTPUT_DIR`. 5. Treat the output argument as an untrusted `yt-dlp` template. Escape literal percent characters or construct the template exclusively from validated constants and identifiers. 6. Use a securely generated temporary output file inside `OUTPUT_DIR`, then rename it to a validated final filename after the download succeeds. 7. Avoid following untrusted symbolic links when creating or replacing output files where the platform and downloader options permit it. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (1)

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill instructs the agent to download a remote file, save it into the local asset store, and modify a shared registry, but it does not clearly warn the user that local files will be written and persistent state will be changed. That can cause unintended storage consumption, policy violations, or silent persistence of untrusted content, especially because the action is triggered by a simple URL-plus-intent workflow.

Static analysis

No suspicious patterns detected.