Back to skill

Security audit

Social Video Downloader

Security checks for vulnerabilities and agentic risk

Overview

The skill does what it claims, but its downloader has under-disclosed network and temporary-file safety weaknesses that merit review before installation.

Install only if you are comfortable with a local downloader making network requests from your machine and sending generated files back through the message tool. Prefer installing yt-dlp in an isolated pinned environment, run the downloader in a network-restricted sandbox if possible, and avoid use on sensitive hosts until the temporary-file handling and SSRF controls are tightened.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/download.py:66
Finding
SSRF Protection Is Vulnerable to DNS Rebinding and Unvalidated Redirects<![CDATA[ ## Vulnerability Details **File Location**: `scripts/download.py`, lines 66–82, with the validated URL subsequently used at lines 94–106 and 132–133 **Vulnerability Type**: Incomplete server-side request forgery protection **Risk Level**: High ### Complete Code Snippet ```python # Resolve and check for private IPs (SSRF protection) import socket try: addr_infos = socket.getaddrinfo(hostname, None) for info in addr_infos: ip_str = info[4][0] ip = ipaddress.ip_address(ip_str) for blocked in BLOCKED_IP_RANGES: if ip in blocked: return False, f"Hostname resolves to blocked IP: {ip_str}" except socket.gaierror: return False, f"Cannot resolve hostname: {hostname}" return True, None ``` The URL is later passed to separate `yt-dlp` processes: ```python cmd = [ "yt-dlp", "-o", output_file, "--no-playlist", "--merge-output-format", "mp4", "--retries", "2", "--socket-timeout", "30", "--no-warnings", "--", url ] result = subprocess.run(cmd, capture_output=True, text=True, timeout=120) ``` ```python meta_cmd = ["yt-dlp", "--no-playlist", "--print", "title", "--no-warnings", "--", url] meta_result = subprocess.run(meta_cmd, capture_output=True, text=True, timeout=30) ``` ### Technical Analysis The application resolves and validates the supplied hostname once, before invoking `yt-dlp`. The subprocess performs its own DNS resolution later, creating a time-of-check/time-of-use gap. A hostname that resolves to a public address during validation could resolve to an internal address when `yt-dlp` connects. The application also validates only the original URL. It does not apply the domain and IP restrictions to HTTP redirects or additional media URLs discovered by a `yt-dlp` extractor. Consequently, a permitted public endpoint may redirect the subprocess to an otherwise prohibited destination. Passing the URL as a separate subprocess argument prevents shell injectio ...[truncated 1595 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Enforce the destination policy for every outbound request, including redirects and extractor-discovered media URLs. - Resolve destinations through a controlled network proxy that rejects loopback, private, link-local, reserved, multicast, and cloud metadata ranges for both IPv4 and IPv6. - Pin the connection to an address validated immediately before use where the downloader and TLS behavior permit this safely. - Restrict the downloader in a network sandbox or container whose firewall cannot route to internal networks or metadata endpoints. - Reject redirects to disallowed domains and IP addresses rather than relying only on validation of the original URL. - Expand IP filtering to cover all non-global and special-use address classes, preferably by positively requiring globally routable addresses. - Apply equivalent restrictions to both the metadata probe and the actual download subprocess. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/download.py:88
Finding
Predictable Shared Temporary Filename Permits File Substitution<![CDATA[ ## Vulnerability Details **File Location**: `scripts/download.py`, lines 88–89 and 111–114 **Vulnerability Type**: Unsafe temporary-file creation and time-of-check/time-of-use file handling **Risk Level**: High ### Complete Code Snippet ```python def download(url, output_dir="/tmp"): """Download video using yt-dlp.""" timestamp = int(time.time()) output_file = os.path.join(output_dir, f"social_dl_{timestamp}.mp4") # Use -- to prevent option injection, pass URL as separate argument cmd = [ "yt-dlp", "-o", output_file, "--no-playlist", "--merge-output-format", "mp4", "--retries", "2", "--socket-timeout", "30", "--no-warnings", "--", url ] result = subprocess.run(cmd, capture_output=True, text=True, timeout=120) if result.returncode != 0: return None, f"Download failed: {result.stderr.strip()}" if not os.path.exists(output_file): return None, "Download failed: file not created" return output_file, None ``` The Skill workflow subsequently instructs the Agent to transmit and remove the returned path: ```markdown 3. On `SUCCESS:<path>`, send file to user via the message tool 4. On `ERROR:...`, report failure to user 5. After sending, delete the temp file with `rm <path>` ``` ### Technical Analysis The output name is based on the current time in whole seconds and is placed in the shared `/tmp` directory by default. Another local user can predict the filename and create a file or symbolic link at that location before `yt-dlp` writes the result. The script neither creates the destination exclusively nor validates the final object with `lstat`. After the subprocess exits, it only tests `os.path.exists`, which does not establish that the path is a newly created regular file, that it is not a symbolic link, or that it is owned by the expected user. The returned path is then intended to be sent to the user and deleted. The exact han ...[truncated 1599 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Create a private output directory with `tempfile.TemporaryDirectory()` or `tempfile.mkdtemp()` and permissions limited to the current user. - Generate output names using cryptographically unpredictable values instead of whole-second timestamps. - Ensure output creation uses exclusive semantics and does not follow symbolic links where supported. - Before transmission, use `os.lstat()` and reject symbolic links, non-regular files, unexpected owners, and files outside the private temporary directory. - Resolve the final path and verify that it remains beneath the trusted temporary directory. - Avoid accepting a file solely because it exists; verify that it was produced during the current invocation. - Perform cleanup in Python against the validated path rather than instructing the Agent to construct a shell `rm` command. - Use a `try`/`finally` block so validated temporary artifacts are removed on success, failure, and timeout. ]]>

T08 · Insecure Dependencies

Warning
Location
SETUP.md:6
Finding
Unpinned Dependency Is Installed into the System Python Environment<![CDATA[ ## Vulnerability Details **File Location**: `SETUP.md`, lines 6–9 **Vulnerability Type**: Unpinned third-party dependency and unsafe system-environment modification **Risk Level**: Medium ### Complete Code Snippet ```bash # Debian/Ubuntu/Kali sudo apt install ffmpeg pip install --break-system-packages yt-dlp # macOS brew install yt-dlp ffmpeg ``` ### Technical Analysis The setup instructions install `yt-dlp` without a fixed version or package hash. As a result, installations are not reproducible: the package artifact obtained during setup can differ from the artifact that was reviewed. The `--break-system-packages` option permits `pip` to modify a Python environment managed by the operating-system package manager. This weakens environment isolation and can introduce dependency conflicts or replace components expected by other system applications. There is no evidence in the reviewed project that `yt-dlp` itself is malicious or that dependency confusion or typosquatting is being intentionally performed. The risk arises from trusting a mutable, unpinned third-party release and installing it into a broad system environment. ### Attack Path 1. A user follows the documented setup command. 2. `pip` resolves the latest available `yt-dlp` release rather than a specifically reviewed version. 3. If the package source, distribution account, release artifact, or dependency chain is compromised, the altered package is installed. 4. Package installation behavior runs with the installing user's privileges and modifies the system Python environment. 5. Subsequent Skill invocations execute the installed `yt-dlp` command, allowing a compromised dependency to access URLs, downloaded content, files available to the user, and subprocess execution capabilities. This path requires compromise or malicious modification of the external dependency or its delivery chain; no such compromise is demonstrated in the project itself. ### Impact Assessment A compromised pa ...[truncated 513 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Install the downloader in an isolated virtual environment or through `pipx`; do not use `--break-system-packages`. - Pin `yt-dlp` to a reviewed version. - Maintain a lock file or hash-verified requirements file and install with hash enforcement where supported. - Define a controlled update process that reviews release notes and security advisories before changing the pinned version. - Prefer trusted operating-system package repositories where their update and integrity model meets project requirements. - Pin or otherwise control other operational dependencies, including `ffmpeg`, in production deployment manifests. - Run the downloader with least privilege inside a restricted container or sandbox to limit the impact of a compromised dependency. ]]>
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • 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
Findings (4)

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
```bash
# Debian/Ubuntu/Kali
sudo apt install ffmpeg
pip install --break-system-packages yt-dlp

# macOS
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill instructs the agent to invoke a local Python script and perform network-backed media downloads, but the manifest declares no explicit tool scope or allowed-tools restrictions. This creates an authorization gap where the runtime may permit broader shell or network actions than intended, making misuse, overreach, or unsafe execution paths harder to constrain and audit.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
"--", url
    ]

    result = subprocess.run(cmd, capture_output=True, text=True, timeout=120)

    if result.returncode != 0:
        return None, f"Download failed: {result.stderr.strip()}"
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
# Check metadata first
    print(f"Checking metadata for: {url}")
    meta_cmd = ["yt-dlp", "--no-playlist", "--print", "title", "--no-warnings", "--", url]
    meta_result = subprocess.run(meta_cmd, capture_output=True, text=True, timeout=30)

    if meta_result.returncode != 0 or not meta_result.stdout.strip():
        print(f"ERROR: Could not fetch video metadata. URL may be invalid or blocked.")
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Static analysis

No suspicious patterns detected.