CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-26331

yt-dlp: Downloading Shells Instead of Videos via --netrc-cmd

Amit Schendel
Amit Schendel
Senior Security Researcher

Feb 24, 2026·6 min read·134 visits

Executive Summary (TL;DR)

If you use `yt-dlp` with the `--netrc-cmd` option to handle credentials, you are vulnerable to RCE. Attackers can embed shell commands in URLs (e.g., subdomains) which get passed unsanitized to your system shell. Update to version 2026.02.21 immediately.

A high-severity OS command injection vulnerability in yt-dlp allows attackers to execute arbitrary code via crafted URLs. By exploiting the `--netrc-cmd` feature and permissive hostname extraction logic, a malicious link can turn a video download into a full system compromise.

The Hook: When Features Bite Back

We all love yt-dlp. It is the Swiss Army knife of media archiving, capable of ripping video from the darkest corners of the internet with a single command. It’s a tool built by hackers, for hackers (and data hoarders). But like any complex tool with a million switches, some of those switches are connected to dynamite. Enter --netrc-cmd.

This specific flag is designed for the power users—the ones who don't just want to put their credentials in a static .netrc file. It allows you to specify a shell command that yt-dlp will execute to fetch credentials dynamically. You give it a template, like pass show /internet/{}, and yt-dlp replaces {} with the machine name (hostname) of the site you're downloading from.

Sounds convenient, right? It is, until you realize that "machine name" isn't always just youtube.com. For certain extractors, that machine name is derived directly from the URL you fed the tool. If you're letting the internet dictate the arguments to your shell commands without a bouncer at the door, you're asking for a bad time. And in CVE-2026-26331, the bouncer wasn't just on break; he didn't exist.

The Flaw: Trusting the Untrustable

The core of this vulnerability lies in a classic misunderstanding of trust boundaries. The developers assumed that a hostname or a "machine identifier" extracted from a URL would be a benign string—something alphanumeric like vimeo or pornhub. For the vast majority of extractors, this is hardcoded. But for a select few—specifically GetCourseRuIE, TeachableIE, TeachableCourseIE, and PornHubIE—the extraction logic was dynamic.

These extractors pulled the "machine" identifier directly from the URL using regular expressions that were far too permissive. For example, they might look for anything that isn't a slash. This means a URL like https://;rm -rf /;@example.com could technically parse validly in terms of structure, but the "machine" part becomes ;rm -rf /;.

Here is the fatal error: yt-dlp takes this dirty input, stuffs it into your command template (replacing {}), and then hands the whole mess over to Python's subprocess.Popen with shell=True. Using shell=True is the programming equivalent of driving blindfolded. It tells the OS to interpret the string as a full shell command, metacharacters and all. The semicolon isn't just part of a string anymore; it's a command separator. The game is over.

The Code: Autopsy of a Shell Injection

Let's look at the "smoking gun." The vulnerability lived in how the netrc_machine variable was handled before being passed to the shell. Prior to the fix, the code essentially did this:

# Vulnerable Logic (Pseudocode)
cmd = self.params['netrc_cmd'].replace('{}', netrc_machine)
# The fatal flaw: shell=True
subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, ...)

If netrc_machine contained ; calc.exe, the resulting command sent to the OS would be echo ; calc.exe. The shell sees an empty echo, finishes it, and then happily executes calc.exe.

The fix, implemented in commit 1fbbe29b99dc61375bf6d786f824d9fcf6ea9c1a, applies a strict whitelist approach. Instead of trying to play whack-a-mole with dangerous characters, the developers defined exactly what a valid machine name looks like.

# The Fix (yt_dlp/extractor/common.py)
ALLOWED = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_'
 
# ... inside _get_netrc_login_info ...
if netrc_machine.startswith(('-', '_')) or not all(c in ALLOWED for c in netrc_machine):
    raise ExtractorError(f'Invalid netrc machine: {netrc_machine!r}', expected=True)

Notice two things here: First, the ALLOWED string limits characters to alphanumerics, dots, dashes, and underscores. No semicolons, no ampersands, no backticks. Second, they explicitly ban strings starting with - or _. This prevents Argument Injection, where an attacker could theoretically pass a flag (like --output /etc/passwd) to the password manager command even if they couldn't execute arbitrary code.

The Exploit: Popping Shells via URL

Let's construct a realistic attack scenario. You are a security researcher (or a miscreant) targeting a user known to use yt-dlp with the --netrc-cmd flag. Perhaps they have a cron job that downloads videos from a list, or they use a wrapper script.

The Setup: The victim runs yt-dlp with a command to fetch passwords: yt-dlp --netrc-cmd "echo Password for {}" [URL]

The Payload: You craft a malicious URL targeting the GetCourseRu extractor, which is vulnerable to this injection. You want to run id.

https://;id;#.getcourse.ru/video

The Execution Flow:

  1. yt-dlp parses the URL. The regex captures ;id;# as the machine identifier.
  2. It substitutes this into the command: echo Password for ;id;#.
  3. The shell executes:
    • echo Password for (prints text)
    • ; (separator)
    • id (EXECUTES THE PAYLOAD)
    • ;# (comments out the rest of the line)

> [!WARNING] > The Redirect Trap: You don't even need the user to paste the ugly URL directly. yt-dlp follows redirects. You can send a link to https://tinyurl.com/cute-cat-video. yt-dlp resolves it, gets redirected to your malicious getcourse.ru payload, and triggers the RCE automatically. This makes the attack vector significantly wider, effectively turning any processed link into a potential bomb.

The Impact: Why You Should Care

This is a High Severity (8.8) vulnerability for a reason. While it requires the user to enable a specific flag (--netrc-cmd), the consequences are catastrophic. We aren't talking about a crash or a memory leak; we are talking about arbitrary code execution.

If this runs on a developer's laptop, the attacker has access to SSH keys, source code, and browser cookies. If this runs on a server (e.g., a Discord bot that downloads videos or a web service wrapping yt-dlp), the attacker now owns that server. They can pivot into the internal network, install persistence, or exfiltrate data.

The fact that yt-dlp is often used in automated pipelines makes this particularly dangerous. A single malicious entry in a download queue could compromise the entire pipeline. The barrier to entry is low—just a crafted string—and the impact is total compromise of the user context running the application.

The Fix: Remediation Strategy

The remediation is straightforward: Update yt-dlp immediately.

The patch was released in version 2026.02.21. If you are running anything older (specifically between 2023.06.21 and 2026.02.21), you are exposed.

If you cannot update for some reason (perhaps you enjoy living dangerously or are stuck in corporate bureaucracy hell), you must audit your usage:

  1. Disable --netrc-cmd: Do not use this flag. Use a static .netrc file or standard credential passing mechanisms.
  2. Sanitize Configurations: Check your yt-dlp.conf files. If you see --netrc-cmd with {} in it, comment it out.

But really, just run yt-dlp -U. It takes five seconds and saves you from being the punchline of a security conference talk.

Official Patches

GitHub (yt-dlp)Official Release 2026.02.21
GitHub (yt-dlp)GitHub Security Advisory

Fix Analysis (1)

Technical Appendix

CVSS Score
8.8/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H

Affected Systems

yt-dlp (Python)Video downloading automation pipelinesDiscord bots using yt-dlpWeb services wrapping yt-dlp

Affected Versions Detail

Product
Affected Versions
Fixed Version
yt-dlp
yt-dlp
>= 2023.06.21, < 2026.02.212026.02.21
AttributeDetail
CWECWE-78 (OS Command Injection)
CVSS8.8 (High)
Attack VectorNetwork (via malicious URL)
ConstraintRequires --netrc-cmd usage
Exploit StatusProof-of-Concept Available
PatchStrict Alphanumeric Whitelist

MITRE ATT&CK Mapping

T1059Command and Scripting Interpreter
Execution
T1204.001User Execution: Malicious Link
Execution
T1566Phishing
Initial Access
CWE-78
OS Command Injection

Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')

Known Exploits & Detection

GitHubProof of Concept demonstrating command injection via GetCourseRu extractor

Vulnerability Timeline

Fix committed to master
2026-02-14
yt-dlp version 2026.02.21 released
2026-02-21
GHSA Advisory Published
2026-02-23
CVE-2026-26331 Published
2026-02-24

References & Sources

  • [1]NVD Entry
  • [2]GHSA Advisory

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•about 1 hour ago•CVE-2026-61560
9.8

CVE-2026-61560: Unauthenticated Remote Path Traversal and Access Token Exfiltration in @zereight/mcp-gitlab

CVE-2026-61560 is a critical security vulnerability in the @zereight/mcp-gitlab Server-Sent Events (SSE) server. By utilizing default, unauthenticated route setups and exposing vulnerable administrative tools, remote attackers can execute path traversal attacks to read internal process variables and hijack GitLab operations.

Amit Schendel
Amit Schendel
3 views•8 min read
•about 2 hours ago•CVE-2026-61590
7.4

CVE-2026-61590: Network-Exposed Observability Endpoints and Remote Method-Invocation in djust

A critical access control vulnerability in djust prior to 1.0.7 exposes diagnostic endpoints and remote method-invocation capabilities to unauthorized network actors. The vulnerability arises due to decoupling IP boundary validation into an opt-in middleware that was omitted from official configuration documentation, leaving views to rely solely on the status of Django's DEBUG flag.

Alon Barad
Alon Barad
4 views•7 min read
•about 3 hours ago•CVE-2026-61595
7.7

CVE-2026-61595: Multi-Tenancy Isolation Bypass on WebSocket and SSE Paths in djust

The multi-tenant isolation mechanism in djust prior to version 1.0.7 fails open on active WebSocket and Server-Sent Events (SSE) connections. Because the tenant context is stored in thread-local variables and initialized exclusively via HTTP middleware, asynchronous event loops executing ASGI/WebSocket code paths do not carry the resolved tenant identifier. When queries are executed without this context, the default database manager fails open, allowing authenticated users of any tenant to query and read sensitive rows across all other tenant accounts.

Amit Schendel
Amit Schendel
3 views•5 min read
•about 4 hours ago•CVE-2025-59953
9.8

CVE-2025-59953: Unauthenticated Remote Code Execution in LMDeploy AsyncRPCServer via Insecure Pickle Deserialization

LMDeploy prior to version 0.10.2 is vulnerable to remote code execution because its AsyncRPCServer component implements unauthenticated, remote-accessible communication sockets and uses the insecure pickle.loads() deserializer to process incoming requests.

Alon Barad
Alon Barad
3 views•6 min read
•about 5 hours ago•CVE-2026-68904
7.0

CVE-2026-68904: Uncontrolled Resource Consumption (Socket Leak and Reconnection Storm) in node-opcua

CVE-2026-68904 is a high-severity Denial of Service (DoS) vulnerability in the node-opcua library. It arises from a logical flaw in the keepalive session manager combined with incorrect socket termination at the TCP transport layer. When server-side anomalies occur, affected clients fall into an infinite, high-frequency reconnection loop. Due to the use of graceful teardown (socket.end) instead of immediate termination (socket.destroy) during negotiation failures, sockets remain open in the FIN-WAIT-2 state. This accumulates system file descriptors and memory, eventually crashing the client process.

Amit Schendel
Amit Schendel
8 views•8 min read
•about 6 hours ago•CVE-2026-61593
8.1

CVE-2026-61593: Cross-Site Request Forgery in djust Server-Sent Events Transport Layer

CVE-2026-61593 is a high-severity Cross-Site Request Forgery (CSRF) vulnerability discovered in the Server-Sent Events (SSE) transport layer of djust, an open-source framework that implements Phoenix LiveView-style reactive server-side rendering for Django applications. Before version 1.0.7, a lack of origin verification on the SSE stream endpoint, combined with @csrf_exempt decorators on message POST endpoints, allowed an attacker to hijack active client sessions through cross-origin interactions.

Alon Barad
Alon Barad
5 views•5 min read