Back to skill

Security audit

Youtube Summarizer

Security checks for vulnerabilities and agentic risk

Overview

The skill is a real video summarizer, but it automatically uses sensitive browser cookies and sends transcripts to external LLM services in ways users should review carefully.

Review this skill before installing. It is suitable only if you are comfortable with video transcripts and metadata being sent to configured or fallback LLM providers, and with Bilibili mode reading Chrome browser cookies. Avoid using it on private, licensed, internal, or account-restricted videos unless you first disable external fallback behavior and browser-cookie use, and prefer pinned dependencies plus a private temporary work directory.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (4)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/summarize.py:170
Finding
Authenticated Browser Requests Are Made with TLS Certificate Verification Disabled<![CDATA[ ## Vulnerability Details **File Location**: `scripts/summarize.py:170-180` **Vulnerability Type**: Authenticated network communication without certificate verification **Risk Level**: High ### Vulnerable Code ```python # Step 1: Download video print(" 📥 Downloading video...", file=sys.stderr) download_cmd = [ "yt-dlp", "--cookies-from-browser", "chrome", "--no-check-certificates", "-f", "bestvideo[height<=720]+bestaudio/best[height<=720]", "--merge-output-format", "mp4", "-o", video_path, url, ] subprocess.run(download_cmd, check=True, timeout=300) ``` ### Technical Analysis The Bilibili download operation instructs `yt-dlp` to obtain authentication cookies from the user's Chrome browser while simultaneously disabling TLS certificate verification. The `--no-check-certificates` option prevents `yt-dlp` from validating whether the remote server presents a certificate issued for the expected host by a trusted certificate authority. HTTPS encryption without certificate authentication does not protect against an active man-in-the-middle attacker. Because browser cookies are enabled in the same command, requests may carry authenticated session information. Although cookie domain rules normally limit which cookies are attached to a request, a network attacker capable of intercepting traffic to the relevant domain can impersonate that domain when certificate verification is disabled. Reading the user's general Chrome authentication state also grants broader access than is necessary for summarizing public videos. A dedicated, narrowly scoped cookie file or browser profile would follow least-privilege principles more closely. ### Attack Path 1. A user invokes the Skill to summarize a Bilibili video. 2. The Skill launches `yt-dlp` with Chrome browser cookies. 3. The user is connected through a hostile Wi-Fi network, compromised proxy, malicious DNS resolver, or another attacker-controlled network path. 4. The attacker redi ...[truncated 945 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `--no-check-certificates` and require normal TLS certificate validation. 2. Treat certificate failures as fatal rather than silently weakening transport security. 3. Do not read the user's default Chrome profile automatically. 4. Make authenticated browser access explicitly opt-in and explain why it is required. 5. Prefer a dedicated browser profile or user-supplied cookie file containing only the minimum cookies needed for Bilibili. 6. Provide a public-video mode that never accesses browser cookies. 7. Avoid printing cookie values, request headers, or authenticated URLs in logs. 8. Document how users can revoke the dedicated session if compromise is suspected. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/summarize.py:552
Finding
Video Transcripts Are Automatically Disclosed to an Anonymous Third-Party LLM<![CDATA[ ## Vulnerability Details **File Location**: `scripts/summarize.py:500-558` **Vulnerability Type**: Automatic external transmission of transcript content **Risk Level**: High ### Vulnerable Code ```python def generate_summary(title: str, channel: str, duration: str, transcript: str) -> Optional[str]: """Generate summary using LLM API (multi-backend fallback chain).""" prompt = SUMMARY_PROMPT_TEMPLATE.format( title=title, channel=channel, duration=duration, transcript=transcript[:8000] ) env_url = os.environ.get("LLM_API_URL") env_key = os.environ.get("LLM_API_KEY") env_model = os.environ.get("LLM_MODEL", "gpt-4o-mini") if env_url and env_key: print(f" 🔑 Using LLM_API_URL env var: {env_url}", file=sys.stderr) result = _call_llm(env_url, env_key, env_model, prompt) if result: return result oc_token = os.environ.get("OPENCLAW_GATEWAY_TOKEN") if oc_token: api_url = env_url or "http://localhost:18789/v1/chat/completions" print(f" 🔑 Using OPENCLAW_GATEWAY_TOKEN → {api_url}", file=sys.stderr) result = _call_llm(api_url, oc_token, env_model, prompt) if result: return result gh_token = os.environ.get("GITHUB_TOKEN") or os.environ.get("GH_TOKEN") if gh_token: print(" 🔑 Trying GitHub Copilot API...", file=sys.stderr) copilot_token = get_copilot_session_token(gh_token) if copilot_token: copilot_model = os.environ.get("LLM_MODEL", "claude-haiku-4.5") result = _call_llm( "https://api.githubcopilot.com/chat/completions", copilot_token, copilot_model, prompt ) if result: return result poll_key = os.environ.get("POLLINATIONS_API_KEY") if poll_key: print(" 🔑 Trying Pollinations API (with key)...", file=sys.stderr) result = _call ...[truncated 2896 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Disable anonymous third-party fallback by default. 2. Require an explicit option such as `--allow-external-llm pollinations` before sending content to that provider. 3. Add a guaranteed local-only mode that fails closed if no approved local backend is available. 4. Display the destination host and the categories of data being transmitted before the first request. 5. Require separate consent before externally processing media obtained with browser cookies. 6. Allow users to configure transcript truncation, redaction, and sensitive-term filtering. 7. Validate custom API endpoints against an administrator-controlled allowlist. 8. Require HTTPS for non-loopback custom endpoints. 9. Document provider retention and privacy implications. 10. Record only the selected provider in logs; do not log prompt content, API tokens, or full sensitive URLs. ]]>

T08 · Insecure Dependencies

Warning
Location
setup.sh:40
Finding
Setup Installs Unpinned Third-Party Dependencies Without Integrity Verification<![CDATA[ ## Vulnerability Details **File Location**: `setup.sh:40-43` **Vulnerability Type**: Mutable and unverified dependency installation **Risk Level**: Medium ### Vulnerable Code ```bash # Activate and install dependencies echo "📦 Installing Python dependencies..." source "$VENV_DIR/bin/activate" pip install --quiet youtube-transcript-api requests innertube faster-whisper ``` ### Technical Analysis The setup script installs four packages without exact version constraints or cryptographic hashes. Every setup invocation can therefore resolve to different package versions than those reviewed during the audit. If a dependency maintainer account, package release process, package index, or transitive dependency is compromised, a malicious release can be installed automatically. Python packages can execute code during installation or later when imported by the Skill. The absence of version locking also creates reproducibility and compatibility risks. The audit cannot establish that future versions will preserve the same security properties as the currently reviewed versions. ### Attack Path 1. An attacker compromises an upstream package, maintainer account, release workflow, or dependency. 2. The attacker publishes a malicious version under one of the package names used by the setup script. 3. A user runs `setup.sh` after that release becomes the version selected by `pip`. 4. `pip` downloads and installs the malicious package into the Skill's virtual environment. 5. Malicious installation hooks may run immediately, or the payload executes when `summarize.py` imports the dependency. 6. The payload executes with the permissions of the user running setup or the Skill. ### Impact Assessment A compromised dependency can execute arbitrary code with the invoking user's privileges. It could read files accessible to that user, inspect environment variables and API tokens, modify the virtual environment, access browser data, or communicate over the network. T ...[truncated 186 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create a reviewed dependency lock file containing exact versions. 2. Generate and enforce SHA-256 hashes for every direct and transitive package. 3. Install with a command equivalent to: ```bash python -m pip install --require-hashes -r requirements.lock ``` 4. Invoke pip through the selected interpreter rather than relying on the shell's `pip` resolution. 5. Pin the package index to an approved HTTPS repository. 6. Review transitive dependencies and refresh the lock file through a controlled update process. 7. Add automated vulnerability and provenance scanning for locked dependencies. 8. Avoid running setup as root or through `sudo`. 9. Consider using signed release artifacts or a trusted internal package mirror. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/summarize.py:153
Finding
Predictable Shared Temporary Files Permit Symlink Overwrites and Persistent Data Exposure<![CDATA[ ## Vulnerability Details **File Location**: `scripts/summarize.py:153-161`, `scripts/summarize.py:201-202`, and `scripts/summarize.py:781-786` **Vulnerability Type**: Unsafe temporary-file creation and retention **Risk Level**: Medium ### Vulnerable Code ```python video_id = extract_bilibili_id(url) video_path = os.path.join(output_dir, f"bili_{video_id}.mp4") audio_path = os.path.join(output_dir, f"bili_{video_id}_audio.mp3") frames_dir = os.path.join(output_dir, f"bili_{video_id}_frames") transcript_path = os.path.join(output_dir, f"bili_{video_id}_transcript.txt") ``` ```python with open(transcript_path, "w", encoding="utf-8") as f: f.write(transcript_with_timestamps) ``` ```python # Write output output_path = Path(args.output) output_path.parent.mkdir(parents=True, exist_ok=True) with open(output_path, "w", encoding="utf-8") as f: json.dump(results, f, indent=2, ensure_ascii=False) ``` The default output location is also predictable: ```python DEFAULT_OUTPUT = "/tmp/youtube_summary.json" ``` ### Technical Analysis The Skill creates videos, extracted audio, frame directories, transcripts, and summary output under predictable paths, commonly in the shared `/tmp` directory. Names are derived from public video identifiers, making them straightforward for another local user to predict. Normal Python file opening follows symbolic links. The transcript and JSON writes do not use exclusive creation, no-follow semantics, or atomic replacement. An attacker who can create entries in the same shared temporary directory may pre-create a symbolic link at a predicted path and cause the Skill to truncate or overwrite another file writable by the victim. The generated artifacts may contain full transcript text and media obtained through an authenticated browser session. The Skill does not explicitly assign restrictive permissions and does not remove the files after processing. Effective permissions depend on the user's `umask`, and stale artifa ...[truncated 1414 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create a unique private workspace for every execution: ```python import tempfile with tempfile.TemporaryDirectory(prefix="youtube-summarizer-") as work_dir: ... ``` 2. Ensure the temporary directory is accessible only to the current user. 3. Create sensitive files with mode `0600` and directories with mode `0700`. 4. Use exclusive creation or no-follow semantics when opening files in potentially shared locations. 5. Write final JSON output to a securely created temporary file and atomically replace the requested destination. 6. Reject output paths that resolve through symbolic links unless explicitly authorized. 7. Clean videos, audio, transcripts, and frames in a `finally` block. 8. Provide an explicit `--keep-artifacts` option when retention is required instead of retaining files by default. 9. Avoid globally predictable default output names; use unique names or require an explicit output path. 10. Enforce limits on download size, frame count, temporary storage consumption, and processing duration. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (28)

Tainted flow: 'url' from requests.get (line 114, network input) → subprocess.run (code execution)

Critical
Category
Data Flow
Content
url = f"https://www.youtube.com/@{channel_id}/videos"

    try:
        result = subprocess.run(
            [
                "yt-dlp",
                "--flat-playlist",
Confidence
90% confidence
Finding
External input (network, user) flows to a code execution sink. This enables remote code execution or command injection.

Tainted flow: 'gh_token' from os.environ.get (line 525, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Content
def get_copilot_session_token(gh_token: str) -> Optional[str]:
    try:
        import requests
        r = requests.get(
            "https://api.github.com/copilot_internal/v2/token",
            headers={
                "Authorization": f"token {gh_token}",
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Tainted flow: 'api_url' from os.environ.get (line 519, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
}
        if api_key:
            headers["Authorization"] = f"Bearer {api_key}"
        response = requests.post(
            api_url,
            headers=headers,
            json={
Confidence
98% confidence
Finding
The skill sends full prompts containing video transcript content to an API endpoint controlled by environment variables, and can attach bearer credentials to that request. In an agent environment, this creates a data-exfiltration path where sensitive transcript content and API keys may be transmitted to an arbitrary external service without explicit validation or user confirmation.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
The skill also performs frame extraction, image insertion, AI-based frame selection, and persistent local configuration writes that are not clearly captured by the summary-focused description. While not inherently malicious, these extra behaviors increase data processing scope and storage footprint beyond what a user may reasonably infer.

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding
The skill also performs frame extraction, image insertion, AI-based frame selection, and persistent local configuration writes that are not clearly captured by the summary-focused description. While not inherently malicious, these extra behaviors increase data processing scope and storage footprint beyond what a user may reasonably infer.

YARA rule 'info_stealer': Information stealer patterns (credential harvesting, browser data theft) [malware]

High
Category
YARA Match
Content
.path.join(output_dir, f"bili_{video_id}_audio.mp3")
    frames_dir = os.path.join(output_dir, f"bili_{video_id}_frames")
    transcript_path = os.path.join(output_dir, f"bili_{video_id}_transcript.txt")

    print(f"🎬 Bilibili: {video_id}", file=sys.stderr)

    # Step 1: Download video
    print("  📥 Downloading video...", file=sys.stderr)
    download_cmd = [
        "yt-dlp",
        "--cookies-from-browser", "chrome",
        "--no-check-certificates",
        "-f", "bestvideo[height<=720]+bestaudio/best[height<=720]",
        "--merge-output-format", "mp4",
        "-o", video_path,
        url,
    ]
    subprocess.run(download_cmd, check=True, timeout=300)

    # Step 2: Extract audio
    print("  🎵 Extracting audio...", file=sys.stderr)
    subprocess.run([
        "ffmpeg", "-y", "-i", video_path,
        "-vn", "-acodec", "libmp3lame", "-q:a", "2",
        audio_path,
    ], check=True, timeout=120, capture_output=True)

    # Step 3: Whisper transcription
    print
Confidence
97% confidence
Finding
Accessing browser cookies from Chrome is behavior commonly associated with credential harvesting because it reads sensitive authentication material from the user's browser profile. Although the apparent goal is to bypass Bilibili restrictions for downloading, in a skill context this is still dangerous because it reaches into unrelated credentials and session state.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
download_cmd = [
        "yt-dlp",
        "--cookies-from-browser", "chrome",
        "--no-check-certificates",
        "-f", "bestvideo[height<=720]+bestaudio/best[height<=720]",
        "--merge-output-format", "mp4",
        "-o", video_path,
Confidence
99% confidence
Finding
The use of --no-check-certificates disables TLS certificate verification during video download, making the tool susceptible to man-in-the-middle interception or content tampering. That weakens transport security precisely when downloading untrusted remote media and potentially authenticated resources.

Missing User Warnings

High
Confidence
99% confidence
Finding
The summarization flow transmits transcript content to external LLM providers, including fallback to anonymous and environment-configured services, without a clear warning that user data is leaving the local environment. Transcripts may contain proprietary, personal, or sensitive content, so silent transmission meaningfully increases privacy and compliance risk.

Description-Behavior Mismatch

Medium
Confidence
98% confidence
Finding
The manifest description says the skill handles both YouTube and Bilibili video transcript extraction and summarization. However, the README explicitly states '此 Skill 仅支持 YouTube' ('this skill only supports YouTube'), which is a direct mismatch in declared behavior and supported platforms.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The README states that extracted transcripts and content may be sent automatically to multiple third-party LLM endpoints, including anonymous/free services, without an explicit warning about data disclosure. In a summarization skill, users may paste or process sensitive, copyrighted, or private material, so silent transmission can lead to confidentiality, compliance, or policy violations.

Lp3

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding
The skill advertises significant capabilities—shell execution, network access, filesystem reads/writes, and environment-variable use—without declaring an explicit tool scope or permission boundary. That makes review and runtime governance harder, and increases the chance an agent invokes the skill with broader access than users expect.

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
The skill contains substantial end-user instructions in Chinese, but it does not indicate that language is selectable or that the skill is intentionally limited to Chinese-speaking users. This can violate a language/locale policy when a skill implicitly forces one language without user opt-in.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The documentation notes Chrome cookies are used to bypass Bilibili anti-scraping, but does not present this as a clear security/privacy warning. Reading browser cookies can expose authenticated session material and may surprise users who did not intend to grant access to local browser state.

Missing User Warnings

Medium
Confidence
99% confidence
Finding
The Bilibili download path invokes yt-dlp with --cookies-from-browser chrome, which accesses locally stored browser session cookies without an explicit warning or consent step. In a skill ecosystem, reading browser cookies is highly sensitive because it touches authentication material unrelated to the stated summarization task and can expose account-bound data or session secrets.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
"-o", video_path,
        url,
    ]
    subprocess.run(download_cmd, check=True, timeout=300)

    # Step 2: Extract audio
    print("  🎵 Extracting audio...", file=sys.stderr)
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
# Step 2: Extract audio
    print("  🎵 Extracting audio...", file=sys.stderr)
    subprocess.run([
        "ffmpeg", "-y", "-i", video_path,
        "-vn", "-acodec", "libmp3lame", "-q:a", "2",
        audio_path,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
The Whisper transcription call forces `language="zh"`, which constrains processing to Chinese regardless of the actual audio language or user preference. This is a natural-language locale policy issue because the file does not offer language selection or explain a justified region-specific limitation.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
if not skip_frames:
        print(f"  🖼️  Extracting keyframes (every {frame_interval}s)...", file=sys.stderr)
        os.makedirs(frames_dir, exist_ok=True)
        subprocess.run([
            "ffmpeg", "-y", "-i", video_path,
            "-vf", f"fps=1/{frame_interval}", "-q:v", "2",
            os.path.join(frames_dir, "frame_%03d.jpg"),
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
url = f"https://www.youtube.com/@{channel_id}/videos"

    try:
        result = subprocess.run(
            [
                "yt-dlp",
                "--flat-playlist",
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def get_video_details(video_id: str) -> Optional[Dict]:
    """Get detailed video metadata using yt-dlp"""
    try:
        result = subprocess.run(
            [
                "yt-dlp",
                "--no-warnings",
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Tainted flow: 'url' from requests.get (line 114, network input) → requests.get (network output)

Medium
Category
Data Flow
Content
def _download_caption(url: str) -> Optional[str]:
    try:
        import requests
        r = requests.get(url, timeout=15)
        if r.status_code == 200 and r.text.strip():
            return r.text
    except Exception:
Confidence
65% confidence
Finding
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

External Transmission

Medium
Category
Data Exfiltration
Content
try:
        import requests
        r = requests.get(
            "https://api.github.com/copilot_internal/v2/token",
            headers={
                "Authorization": f"token {gh_token}",
                "Editor-Version": "vscode/1.95.0",
Confidence
88% confidence
Finding
This request exchanges a locally available GitHub token for a Copilot session token, extending use of ambient credentials to a third-party service. While the destination is GitHub rather than an arbitrary host, silently consuming developer tokens in a summarization skill expands credential exposure and may surprise users.

External Transmission

Medium
Category
Data Exfiltration
Content
}
        if api_key:
            headers["Authorization"] = f"Bearer {api_key}"
        response = requests.post(
            api_url,
            headers=headers,
            json={
Confidence
97% confidence
Finding
This external POST sends the summarization prompt, which includes transcript text, to a remote API and may include authorization credentials. Because the endpoint can be environment-controlled and multiple fallback services are tried automatically, the skill creates a significant outbound data channel beyond what a user may reasonably expect.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The skill harvests multiple environment-provided credentials and uses them to obtain third-party model access beyond simple local processing. In an agent context, this broadens the trust boundary substantially and may cause unintended use of ambient credentials, especially when users invoke the skill expecting only transcript extraction and summarization.

External Transmission

Medium
Category
Data Exfiltration
Content
if copilot_token:
            copilot_model = os.environ.get("LLM_MODEL", "claude-haiku-4.5")
            result = _call_llm(
                "https://api.githubcopilot.com/chat/completions",
                copilot_token,
                copilot_model,
                prompt
Confidence
96% confidence
Finding
This call sends user-derived transcript content to the GitHub Copilot chat completions API after obtaining a session token, creating external disclosure of processed content. In the context of a summarizer skill, this is sensitive because remote transmission is automatic and tied to ambient credentials rather than explicit user authorization.

Static analysis

No suspicious patterns detected.