Back to skill

Security audit

music-manager

Security checks for vulnerabilities and agentic risk

Overview

This music downloader mostly does what it claims, but it reads Chrome browser cookies by default and can write downloads outside the intended music folder.

Install only if you are comfortable with yt-dlp being allowed to read your Chrome cookies by default. Before use, set BROWSER = None unless you truly need authenticated downloads, review the exact download destination, and avoid untrusted category names because they can redirect files outside ~/Music.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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 (2)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/download_music.py:25
Finding

Unrestricted Category Path Allows Writes Outside the Music Directory

Content
View full analysis

Vulnerability Details

File Location: scripts/download_music.py, lines 25–28
Vulnerability Type: Path traversal and unrestricted filesystem write destination
Risk Level: Medium

Vulnerable Code

python
def ensure_dir(category):
    """Ensure the category directory exists."""
    category_path = os.path.join(MUSIC_DIR, category)
    os.makedirs(category_path, exist_ok=True)
    return category_path

The resulting path is subsequently used as the output directory:

python
output_dir = ensure_dir(category)

output_template = os.path.join(
    output_dir,
    "%(title)s-%(uploader)s-%(extractor)s.%(ext)s"
)

Technical Analysis

The category value comes directly from the second command-line argument and is passed to os.path.join() without validation or canonicalization.

A relative value containing parent-directory components, such as ../../tmp/music, can escape MUSIC_DIR. An absolute category path is more direct: on supported platforms, os.path.join(MUSIC_DIR, absolute_path) resolves to the supplied absolute path rather than a child of MUSIC_DIR.

os.makedirs() then creates the selected directory, and the path is incorporated into the yt-dlp output template. Although the final filename is generated by yt-dlp, the user controls the directory in which the downloaded media is written.

The issue is not shell command injection because subprocess.run() receives an argument list. It is instead an insufficient path-boundary validation vulnerability.

Attack Path

  1. An attacker or untrusted caller supplies a category containing traversal components or an absolute path:
    bash
    python3 scripts/download_music.py "https://example.com/media" "../../tmp/attacker-output"
    
  2. ensure_dir() joins the untrusted category with MUSIC_DIR without resolving and checking the resulting path.
  3. os.makedirs() creates the destination outside the intended music library.
  4. The destination is embedded in the `yt-d ...[truncated 855 chars]
Remediation
View remediation

Remediation Suggestions

Treat categories as logical names rather than arbitrary paths:

  1. Reject absolute category paths.
  2. Resolve both the configured music root and proposed destination to canonical paths.
  3. Verify that the destination remains strictly within MUSIC_DIR.
  4. Optionally restrict category names to an allowlist of safe characters and prohibit . and .. path components.
  5. Consider refusing symbolic-link components where an attacker can modify the music directory concurrently.

Example hardening:

python
from pathlib import Path
import re

def ensure_dir(category):
    if not category or Path(category).is_absolute():
        raise ValueError("Category must be a non-empty relative name")

    if any(part in (".", "..") for part in Path(category).parts):
        raise ValueError("Category contains prohibited path components")

    if not re.fullmatch(r"[\w .-]+", category):
        raise ValueError("Category contains unsupported characters")

    music_root = Path(MUSIC_DIR).expanduser().resolve()
    category_path = (music_root / category).resolve()

    try:
        category_path.relative_to(music_root)
    except ValueError:
        raise ValueError("Category must remain inside the music directory")

    category_path.mkdir(parents=True, exist_ok=True)
    return str(category_path)

For stronger protection against symbolic-link races, perform filesystem operations through directory file descriptors or revalidate the resolved destination immediately before invoking the downloader.

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/download_music.py:20
Finding

Browser Authentication Cookies Are Accessed by Default

Content
View full analysis

Vulnerability Details

File Location: scripts/download_music.py, lines 20–21 and 31–34
Vulnerability Type: Excessive default access to browser authentication material
Risk Level: Medium

Vulnerable Code

python
# Chrome cookie extraction method: chrome / safari / firefox
# Set to None if cookies should not be used
BROWSER = "chrome"
python
def get_cookie_arg():
    """Return cookie arguments."""
    if BROWSER:
        return f"--cookies-from-browser {BROWSER}"
    return ""

The returned option is included in every downloader invocation:

python
cookie_arg = get_cookie_arg().split() if get_cookie_arg() else []

cmd = [
    "yt-dlp",
] + cookie_arg + [
    "--extract-audio",
    "--audio-format", "mp3",
    "--audio-quality", "0",
    "--output", output_template,
    "--no-playlist",
    url
]

Technical Analysis

The default configuration causes every download to invoke:

text
yt-dlp --cookies-from-browser chrome

This asks a third-party executable to access the current user's Chrome cookie database and use applicable authenticated session state. Cookie access occurs even for public content and arbitrary user-provided HTTP or HTTPS URLs where authentication is unnecessary.

The documentation describes browser-cookie use as optional, but the implementation enables it by default. This violates least-privilege principles by granting the downloader access to sensitive browser authentication material without an explicit per-download decision.

No project code was found that directly prints or intentionally exfiltrates cookie values. The confirmed issue is unnecessary default access and exposure of authentication context, not proof of credential theft.

Attack Path

  1. A user runs the documented download command without modifying the default configuration.
  2. The script sets BROWSER to chrome.
  3. get_cookie_arg() generates --cookies-from-browser chrome.
  4. The script starts the externally installed `yt ...[truncated 1298 chars]
Remediation
View remediation

Remediation Suggestions

Disable browser-cookie access by default and require explicit user authorization:

python
BROWSER = None

Add an explicit command-line option, such as:

text
--cookies-from-browser chrome

Security hardening should include:

  1. Use anonymous downloads by default.
  2. Require opt-in cookie access for each invocation that needs authentication.
  3. Validate the browser name against a fixed allowlist rather than constructing options from arbitrary values.
  4. Restrict cookie-enabled downloads to explicitly trusted and supported domains.
  5. Clearly disclose that enabling the option reads browser authentication data.
  6. Avoid printing cookie paths, values, or verbose downloader diagnostics that could contain sensitive request information.
  7. Pin or otherwise verify the provenance of the installed yt-dlp executable because it receives access to browser authentication state.

A safer argument construction avoids splitting a formatted string:

python
SUPPORTED_BROWSERS = {"chrome", "safari", "firefox"}

def get_cookie_args(browser=None):
    if browser is None:
        return []
    if browser not in SUPPORTED_BROWSERS:
        raise ValueError("Unsupported browser")
    return ["--cookies-from-browser", browser]
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (8)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The skill's declared purpose is music downloading, but the content also directs extraction and use of browser cookies from local browsers such as Chrome for authenticated access. Accessing local browser cookies is sensitive local-data access that can expose session material or account-linked tokens, and it is not transparently declared in the skill description.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill clearly instructs use of shell-capable operations (brew install, python3 scripts/download_music.py) but does not declare any tool scope or allowed tools. This weakens execution boundaries and transparency, making it easier for an agent or integrator to invoke shell actions without explicit review or least-privilege constraints.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill description omits clear warnings that it retrieves content from external sites and writes converted files into the user's local music library. Without upfront disclosure, users may not realize the skill performs network downloads and local filesystem writes, increasing the risk of unintended content acquisition, overwriting files, or unsafe storage behavior.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill description and usage guidance are written entirely in Chinese, including the manifest description and operational steps, with no indication that the user can select another language. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale restriction is clearly documented and justified.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The script is configured to extract cookies from the user's Chrome profile by default, which accesses sensitive authenticated browser data unrelated to a basic music-download workflow. Those cookies can enable access to logged-in services and increase the blast radius if the downloader, its dependencies, or logs are compromised.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script reads authenticated browser cookies without a clear runtime warning or consent flow, so users may unknowingly grant access to sensitive session material. In the context of a general music manager, this is more dangerous because users would not reasonably expect browser-profile data to be accessed just to download audio.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/download_music.py (reported line 72)May include surrounding context.

python
print("开始下载...")
    
    try:
        result = subprocess.run(cmd, capture_output=True, text=True)
        if result.returncode == 0:
            print("✅ 下载成功!")
            for line in result.stdout.split('\n'):

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

The file includes natural-language instructions in Chinese for setup and usage, and the runtime help output is also Chinese. This can violate a language/locale policy when a skill forces one language without opt-in or an alternative.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.