5 min read

yt-dlp: Download Video and Audio From Thousands of Sites (GitHub, Scanned)

The command-line downloader behind most video tools, for YouTube and thousands of other sites.

yt-dlp logo
✅
Scan: safe. Nothing malicious. The note is about use rather than code: downloading can break a site's terms, so keep to content you have the right to save. Scanned Oct 19, 2026; the full report is below.

yt-dlp is a command-line program that downloads video and audio from YouTube and from thousands of other sites, from news broadcasters and lecture platforms to podcasts and social networks. Give it a link and it fetches the best available quality; add a flag and it pulls a whole playlist or channel, extracts the audio as MP3, embeds subtitles, chapters and thumbnails, or picks a specific resolution and format.

It began as a fork of youtube-dl and has long since become the version everyone uses. Many graphical downloaders, media servers and AI transcription tools on this list run yt-dlp underneath, because its extractors are fixed within days whenever a site changes. Its own builds are single files for Windows, macOS and Linux that update themselves with yt-dlp -U.

It is released into the public domain under the Unlicense, with about 199,300 stars and 1,760 contributors, at release 2026.08.19 when scanned. Full YouTube support now needs a JavaScript runtime such as Deno alongside it, and ffmpeg is needed to merge video and audio and to convert formats.

  • Repository: github.com/yt-dlp/yt-dlp
  • Licence: Unlicense (The Unlicense)
  • Language: Python. Stars: 199.3K. Forks: 17.4K. Last push: Oct 10, 2026.
  • Scan: safe, Oct 19, 2026, commit 8973412

Who it is for

Anyone who wants an offline copy of videos, lectures or podcasts they are allowed to keep, archivists, researchers and developers who need media files for transcription or editing.

Getting started

1. Install with pip (or download the single-file build from the releases page)

python3 -m pip install -U "yt-dlp[default]"

2. Download a video in the best quality

yt-dlp "https://www.youtube.com/watch?v=VIDEO_ID"

3. Extract the audio as MP3

yt-dlp -x --audio-format mp3 "https://www.youtube.com/watch?v=VIDEO_ID"

4. Update a standalone build

yt-dlp -U

Install ffmpeg and a JavaScript runtime (Deno is recommended) as well; without them some formats cannot be merged and YouTube support is incomplete. Homebrew, winget and most Linux package managers also carry yt-dlp.

Safety scan

We cloned yt-dlp/yt-dlp at commit 8973412 on Oct 19, 2026 and ran the checks described on the GitHub Tools page: credential patterns, decode-and-execute code, install-time scripts, committed binaries, risky CI workflows, every host the code talks to, known vulnerabilities in pinned dependencies, and project hygiene. A person read every hit. This is what we found.

  • The 6 secret hits are API keys that sites embed in their own web players (Google Drive, Shahid and a few streaming services), which yt-dlp's extractors send the same way the official player does. They are not the project's credentials.
  • The 11 pattern hits are test data: long hex-escaped strings in the tests for its JavaScript challenge solver, and one very long line in the tests for its JavaScript interpreter. The 3 bare-IP URLs are media servers that two extractors talk to. No committed binaries and no install hooks across 1,239 files and about 265,000 lines of Python.
  • 7 known advisories (5 high) in uv.lock, all in urllib3 and virtualenv, which the lockfile pins for development and testing. yt-dlp's own builds bundle their dependencies separately, and pip installs current releases.
  • Legally, yt-dlp is a general tool, and the project refuses to support sites that exist mainly for piracy. Whether a particular download is allowed depends on the site's terms and your country's copyright law.
  • 13 workflows; the one pull_request_target workflow only reacts to labels with comments and never checks out PR code. 8 of 11 third-party actions are pinned to commits, CodeQL is on, and its OpenSSF Scorecard is 8 out of 10. No security policy file in the repository.

What the scanner counted

CheckResult
Secrets6 candidates found and read; see the notes above.
Suspicious code11 pattern hits found and read; every one is listed under the raw findings.
Install-time codeNone: nothing runs at install beyond the package manager itself.
Committed binariesNone.
CI workflows13 workflows. 1 uses pull_request_target, none check out the pull request head. 3 of 11 third-party actions pinned to a tag rather than a commit.
Network hosts40 distinct hosts referenced from source; most often www.youtube.com, github.com, vimeo.com, twitter.com. 3 URLs to a bare IP address, listed under the raw findings.
Known vulnerabilities7 advisories across 61 pinned packages: 0 critical, 5 high, 2 moderate, 0 low. uv.lock: 61 packages, 7 advisories.
Project hygieneHas CodeQL, licence file, contributing guide. Missing security policy, automated dependency updates.
OpenSSF Scorecard8.0 out of 10, as of Oct 12, 2026.

The raw findings

Every hit the scanner wrote out, with a link to the exact line at the scanned commit. Secrets candidates are redacted.

Secret candidates (6, redacted)
WhereRuleMatch
yt_dlp/extractor/cybrary.py:12google-api-keyAIzaSy…zSw (39 chars)
yt_dlp/extractor/googledrive.py:144google-api-keyAIzaSy…nb8 (39 chars)
yt_dlp/extractor/shahid.py:39aws-access-keyAKIAI6…MUQ (20 chars)
yt_dlp/extractor/stacommu.py:15google-api-keyAIzaSy…Ahg (39 chars)
yt_dlp/extractor/stacommu.py:177google-api-keyAIzaSy…rfc (39 chars)
yt_dlp/extractor/wrestleuniverse.py:32google-api-keyAIzaSy…AdA (39 chars)
Pattern hits (11)
WhereRuleMatch
test/test_jsc/test_ejs_integration.py:65long-hex-escape-run (test/example)'\x00\x01\x02%\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x30\x31\x32\x33\x34\x35\x36\x37\x38\x…
test/test_jsc/test_ejs_integration.py:66long-hex-escape-run (test/example)'\x00\x01\x02%\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x30\x31\x32\x33\x34\x35\x36\x37\x38\x…
test/test_jsc/test_ejs_integration.py:89long-hex-escape-run (test/example)'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x2…
test/test_jsc/test_ejs_integration.py:90long-hex-escape-run (test/example)'\x6a\x69\x68\x67\x66\x65\x64\x63\x62\x61\x60\x5f\x5e\x5d\x5c\x5b\x5a\x59\x58\x57\x56\x55\x54\x53\x52\x51\x50\x4f\x4e\x4d\x4c\x4b\x4a\x49\x48\x47\x46\x45\x44\x4…
test/test_jsc/test_ejs_integration.py:97long-hex-escape-run (test/example)'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x2…
test/test_jsc/test_ejs_integration.py:98long-hex-escape-run (test/example)'\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2…
test/test_jsc/test_ejs_integration.py:105long-hex-escape-run (test/example)'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x2…
test/test_jsc/test_ejs_integration.py:106long-hex-escape-run (test/example)'\x46\x66\x65\x64\x63\x62\x61\x60\x5f\x5e\x67\x6a\x5b\x5a\x59\x58\x57\x56\x55\x54\x53\x52\x51\x50\x4f\x4e\x4d\x4c\x4b\x4a\x49\x48\x47\x2c\x45\x44\x43\x42\x41\x4…
test/test_jsc/test_ejs_integration.py:113long-hex-escape-run (test/example)'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x2…
test/test_jsc/test_ejs_integration.py:114long-hex-escape-run (test/example)'\x19\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x00\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x2…
test/test_jsinterp.py:402very-long-line4455 chars
URLs to bare IP addresses (3)
WhereRuleMatch
yt_dlp/extractor/presstv.py:34ip-literal-urlbase_url = 'http://192.99.219.222:82/presstv'
yt_dlp/extractor/saitosan.py:16ip-literal-url'thumbnail': 'http://111.171.196.85:8088/921f916f-7f55-4c97-b92e-5d9d0fef8f5f/thumb',
yt_dlp/extractor/saitosan.py:32ip-literal-url'thumbnail': 'http://111.171.196.85:8088/1a3933e1-a01a-483b-8931-af15f37f8082/thumb',
Worst known vulnerabilities (7 of 7)
AdvisorySeverityPackageSummary
GHSA-8988-9cw3-xx77highurllib3@2.7.0urllib3: HTTPS proxy TLS configuration may be ignored or overridden
GHSA-vxq7-64xx-v4gwhighurllib3@2.7.0urllib3: HTTPResponse.stream()/read_chunked() buffers an unbounded chunk-size line into memory
GHSA-94p9-xgh2-xp45highvirtualenv@21.7.4virtualenv: Downloaded seed wheels (pip/setuptools) are not integrity-checked before use
GHSA-p58f-9548-mpm2highvirtualenv@21.7.4virtualenv bash and fish activation scripts execute commands embedded in paths
GHSA-x78j-v8h9-3j2qhighvirtualenv@21.7.4virtualenv: Command injection via --prompt in activate.bat (batch activator)
GHSA-gh4c-6fx4-qh6gmoderateurllib3@2.7.0urllib3: Chunked Deflate streaming can enter an infinite loop
GHSA-9h9j-4vrj-gf7gmoderatevirtualenv@21.7.4virtualenv writes prompt values into pyvenv.cfg without sanitizing line boundaries, allowing configuration injection
Workflows worth a look

By the numbers

Stars199.3K
Forks17.4K
Contributors1,760
Commits24K
Open issues2,045
Open pull requests675
Releases136
Latest release2026.08.19
LicenceUnlicense
Main languagePython
Project age5 years
Last pushOct 10, 2026
Tracked files1,239
Lines of code265.1K
Checkout size12 MB

Lines by language: Python 249.1K, Markdown 12.2K, YAML 2,693, JSON 549, TOML 485, Shell 92.

Questions

Is yt-dlp free?

Yes. yt-dlp is free and in the public domain under the Unlicense, with no account, ads or paid version. Be wary of paid apps that are only a wrapper around it.

The tool itself is legal to use, and it is widely used for archiving, research and accessibility. Downloading a specific video may break the site's terms of service or copyright law, so stick to content you own, content under an open licence, or content the site lets you save.

Why does yt-dlp say a JavaScript runtime is needed for YouTube?

YouTube now requires solving JavaScript challenges to get some formats. yt-dlp does this with its yt-dlp-ejs component, which needs a runtime such as Deno, Node.js, Bun or QuickJS installed. Without one, it may only find a few formats or fail on some videos.


This post is part of GitHub Tools, where every repository is cloned and scanned before it is written up. The scan is a snapshot of one commit on one day; the repository has moved on since, so check it before you install.