Back to skill

Security audit

YouTube Digest

Security checks for vulnerabilities and agentic risk

Overview

The skill’s YouTube transcript purpose is coherent, but its CLI passes user-supplied URLs through shell commands in a way that can allow command injection.

Review before installing. The main risk is that a crafted YouTube URL could execute local shell commands as the user running the CLI. This should be fixed by using execFileSync or spawnSync with argument arrays and stricter URL parsing before the skill is considered safe for normal use.

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

Error
Location
src/cli.js:28
Finding

Arbitrary Command Execution Through Unsafely Interpolated Video URL

Content
View full analysis

Vulnerability Details

File Location: src/cli.js, lines 28-35 and 45-52
Vulnerability Type: OS command injection
Risk Level: High

Vulnerable Code

js
function getVideoInfo(url) {
  try {
    const output = execSync(`yt-dlp --dump-json --no-download "${url}"`, {
      encoding: 'utf-8',
      timeout: 30000,
      stdio: ['pipe', 'pipe', 'pipe']
    });
    return JSON.parse(output);
js
try {
  // Try auto-generated first, then manual subs
  execSync(`yt-dlp --write-auto-sub --sub-lang en --skip-download --sub-format vtt -o "${tmpFile}" "${url}"`, {
    encoding: 'utf-8',
    timeout: 30000,
    stdio: ['pipe', 'pipe', 'pipe']
  });

Technical Analysis

The application inserts the user-controlled url directly into shell command strings passed to execSync(). Because string-form execSync() invokes a shell, shell metacharacters contained in the URL are interpreted as command syntax rather than as part of a single yt-dlp argument.

The preceding extractVideoId() validation does not prevent exploitation. Its YouTube URL regular expression is not anchored to the end of the input and only needs to find a matching URL prefix. Consequently, an input can begin with a valid-looking YouTube URL and contain a closing quote, command separators, and an additional command afterward. Although the extracted video ID is used to decide whether the input is acceptable, the original untrusted url is subsequently passed to the shell.

Both the video-information and transcript retrieval paths contain this unsafe command construction, so all supported commands can reach at least one vulnerable sink after dependency validation succeeds.

Attack Path

  1. The attacker persuades a user or automated process to invoke the CLI with a crafted URL.
  2. The supplied value starts with a URL accepted by extractVideoId(), such as a YouTube watch URL containing an apparent video identif ...[truncated 1358 chars]
Remediation
View remediation

Remediation Suggestions

  1. Replace shell-string execution with an API that passes arguments separately and disables shell interpretation. For example:

    js
    import { execFileSync } from 'child_process';
    
    const output = execFileSync(
      'yt-dlp',
      ['--dump-json', '--no-download', url],
      {
        encoding: 'utf-8',
        timeout: 30000,
        stdio: ['pipe', 'pipe', 'pipe']
      }
    );
    

    Apply the same pattern to transcript retrieval:

    js
    execFileSync(
      'yt-dlp',
      [
        '--write-auto-sub',
        '--sub-lang', 'en',
        '--skip-download',
        '--sub-format', 'vtt',
        '-o', tmpFile,
        url
      ],
      {
        encoding: 'utf-8',
        timeout: 30000,
        stdio: ['pipe', 'pipe', 'pipe']
      }
    );
    
  2. Do not attempt to make string-form shell execution safe solely through quoting or character replacement. Argument-array execution with no shell should be the primary control.

  3. Parse input with the standard URL class and enforce an explicit host allowlist such as youtube.com, www.youtube.com, and youtu.be. Validate the expected pathname and require the video identifier to match the complete expected 11-character format.

  4. Reject malformed URLs, embedded control characters, unexpected credentials, and unsupported protocols before invoking external tools.

  5. Add regression tests using URLs containing quotes, semicolons, command substitutions, newlines, and other shell metacharacters. Tests should confirm that these values are rejected or passed only as inert arguments.

  6. Run the CLI with least privilege and avoid executing it under administrative accounts or highly privileged automation identities.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (4)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

This code invokes yt-dlp to fetch video info and subtitles from remote YouTube URLs, which necessarily performs network requests and transmits the user-supplied URL to an external service. While the CLI prints progress messages, it does not clearly disclose that it will contact external services or send request data off the local system.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The yt-dlp invocation hard-codes --sub-lang en, which imposes an English-only locale choice on transcript retrieval. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the constraint is justified or configurable.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
91% confidence
Finding

The dependency is specified with a caret range (^1.2.1), which allows newer compatible versions to be installed automatically. This can introduce supply-chain risk because future releases may contain malicious code, regressions, or vulnerable transitive dependencies, and installs may become non-reproducible across environments.

Content

Scanner excerpt · package.json (reported line 17)May include surrounding context.

json
"author": "Elonito",
  "license": "MIT",
  "dependencies": {
    "youtube-transcript": "^1.2.1"
  }
}

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

The help text says the tool can 'Extract summaries and transcripts from YouTube videos' and labels the 'summary' command accordingly. However, the implementation of cmdSummary only fetches video info, concatenates the transcript, and prints a transcript preview and counts, with no summarization logic or condensation beyond truncation.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
src/cli.js:32