Back to skill

Security audit

YouTube AnyCaption Summarizer

Security checks for vulnerabilities and agentic risk

Overview

This YouTube summarizer mostly does what it says, but it handles private-video cookies, sends transcript content to an LLM, and posts untrusted video metadata back into an agent session with insufficient guardrails.

Review carefully before installing. Use cookie support only when necessary, prefer an explicit cookies.txt file over browser extraction, and treat cookies as account credentials. Do not process confidential private videos unless you are comfortable with transcript text and metadata being sent to the configured OpenClaw model. Disable or patch automatic progress forwarding and redact session identifiers from logs before using this in sensitive agent sessions.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (3)

T01 · Skill Instruction Hijacking

Error
Location
scripts/run_youtube_batch_end_to_end.py:43
Finding

Untrusted YouTube Metadata Is Forwarded as an Agent Message

Content
View full analysis
str | None: if event == "video_started": title = payload.get("title") or payload.get("url") or "video" index = payload.get("index") total = payload.get("total") prefix = f"[{index}/{total}] " if index and total else "" return f"{prefix}Started: {title}" if event == "video_summary_done": title = payload.get("title") or payload.get("url") or "video" return f"Summary ready: {title}" if event == "batch_complete": success_count = payload.get("success_count") total = payload.get("total") failure_count = payload.get("failure_count") return f"Batch complete: {success_count}/{total} succeeded, {failure_count} failed" if event == "video_failed": title = payload.get("title") or payload.get("url") or "video" phase = payload.get("phase") or "unknown phase" error = str(payload.get("error") or "unknown error").strip() if len(error) > 220: error = error[:217] + "..." return f"Failed: {title} ({phase})\n{error}" return None def forward_progress_update(event: str, **payload: Any) -> None: session_key = payload.get("sessionKey") or get_launch_session_key() message = build_forward_message(event, payload) if not session_key or not message: return cmd = [ "openclaw", "agent", "--session-id", session_key, "--message", message, ] result = subprocess.run(cmd, text=True, capture_output=True) ``` ### Technical Analysis The video title and some failure details originate from remote, untrusted sources. The title is inserted directly i ...[truncated 1763 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/run_youtube_batch_end_to_end.py:25
Finding

OpenClaw Session Identifier Is Disclosed in Process Logs

Content
View full analysis
str | None: preferred = os.environ.get(LAUNCH_SESSION_KEY_ENV, "").strip() if preferred: return preferred for key in ("OPENCLAW_SESSION_KEY", "SESSION_KEY", "OPENCLAW_PARENT_SESSION_KEY"): value = os.environ.get(key, "").strip() if value: return value return None ``` The identifier is added to emitted event payloads: ```python failure = { "url": url, "video_id": video_id, "attempts": args.max_attempts, "phase": last_phase, "error": last_error or "Unknown error", "sessionKey": get_launch_session_key(), } emit_event("video_failed", **failure) ``` It is also emitted when the batch completes: ```python batch_payload = { "success_count": len(success_reports), "total": len(urls), "failure_count": len(failures_map), "sessionKey": get_launch_session_key(), } emit_event("batch_complete", **batch_payload) forward_progress_update("batch_complete", **batch_payload) ``` `emit_event` writes the complete payload to stderr: ```python def emit_event(event: str, **payload: Any) -> None: record = {"event": event, **payload} print(json.dumps(record, ensure_ascii=False), file=sys.stderr) sys.stderr.flush() ``` ### Technical Analysis The script reads a session identifier from several environment variables and includes it in JSON event records written to stderr. The identifier is required internally to target progress messages, but it is not required in diagnostic output. Standard error is frequently captured by parent agents, CI systems, process supervisors, shell redirection, and centralized log collectors. Consequently, an environment-derived session identifier can escape its in ...[truncated 1434 chars]
Remediation
View remediation

other

Error
Location
scripts/generate_summary_llm.py:141
Finding

Private Transcript Content May Be Sent to a Remote LLM Without Explicit Disclosure or Consent

Content
View full analysis
str: """Call the OpenClaw LLM via the openclaw infer model run CLI.""" full_prompt = f"{system_msg}\n\n---\n\n{user_msg}" env = os.environ.copy() session_key = env.get(LAUNCH_SESSION_KEY_ENV, "").strip() if session_key: env[LAUNCH_SESSION_KEY_ENV] = session_key result = subprocess.run( ["openclaw", "infer", "model", "run", "--model", model, "--gateway", "--prompt", full_prompt], text=True, capture_output=True, timeout=240, env=env ) ``` Up to 60,000 transcript characters are selected for submission: ```python normalized = normalize_transcript_text(raw_text) if len(normalized) > args.max_transcript_chars: normalized = normalized[:args.max_transcript_chars] + \ "\n\n[... transcript truncated for summary generation ...]" system_msg, user_msg = build_summary_prompt( titl ...[truncated 2164 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (36)

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

High
Category
YARA Match
Confidence
75% confidence
Finding

YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Content

Scanner excerpt · README.md (reported line 74)May include surrounding context.

ngle video

bash
python3 scripts/run_youtube_workflow.py "https://www.youtube.com/watch?v=VIDEO_ID"

Force a target summary language

bash
python3 scripts/run_youtube_workflow.py "https://www.youtube.com/watch?v=VIDEO_ID" \
  --summary-language zh-CN

Private or restricted video

bash
python3 scripts/run_youtube_workflow.py "https://www.youtube.com/watch?v=VIDEO_ID" \
  --cookies-from-browser chrome

Batch mode

bash
python3 scripts/run_youtube_workflow.py --batch-file ./youtube-urls.txt

How the workflow works

  1. fetch video metadata first
  2. create safe output paths and per-video folders
  3. try manual subtitles, then auto-captions
  4. fall back to local Whisper when needed
  5. write a raw transcript markdown artifact
  6. generate a polished summary markdown artifact
  7. run completion/finalization to return a session-ready result

Example use cases

  • “Summarize this YouTube video into markdown.”
  • “Process this private YouTube video w

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description presents a full end-to-end YouTube transcript extraction and summarization workflow, including subtitle handling, Whisper fallback, private video access, batch processing, and completion reporting. The supplied code chunk does not perform any of those primary functions. Instead, it narrowly edits two existing local files: it replaces the language section in a raw transcript markdown file, updates embedded workflow metadata to mark the detected language as backfilled by the LLM, and inserts or updates a 'Summary Language' section in a summary markdown file. While 'language backfill' is mentioned in the declared description, this code only implements that small supporting subtask and not the broader advertised behavior. Therefore the description materially overstates what this code chunk actually does.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description presents a full YouTube transcript-and-summary pipeline with subtitle extraction, Whisper fallback, language handling, private video access, batch workflows, transcript cleanup, and polished summary generation. The supplied code chunk does none of that. It is a post-processing/reporting script whose sole purpose is to compute and print timing metadata based on an existing raw transcript file and a summary file. While 'completion reporting' is mentioned in the description, this code only covers that narrow reporting aspect and not the primary advertised functionality. Therefore the code chunk materially differs from the declared purpose.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The declared description promises a full YouTube transcription and summarization system with multiple subtitle modes, Whisper fallback, language features, private video support, and workflow reporting. The actual code chunk is a narrow utility script for preparing sanitized folder and file paths based on a title and video ID. While this may be a supporting component of such a workflow, on its own it does not match the declared primary purpose. The code does not access YouTube, read captions, invoke transcription or summarization, or process batches; it only generates filenames/paths.

Content

No source excerpt is available for this finding.

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

High
Category
YARA Match
Confidence
75% confidence
Finding

The --cookies-from-browser chrome instruction is not automatically malware, but in a skill context it touches highly sensitive browser-stored authentication data and can normalize risky secret extraction practices. Without strict guardrails, this capability can expose session cookies to scripts, logs, or downstream tooling, enabling account access or impersonation if mishandled.

Content

Scanner excerpt · SKILL.md (reported line 107)May include surrounding context.

ummary

bash
python3 scripts/run_youtube_workflow.py "https://www.youtube.com/watch?v=VIDEO_ID" \
  --summary-language zh-CN

Restricted video with cookies

bash
python3 scripts/run_youtube_workflow.py "https://www.youtube.com/watch?v=VIDEO_ID" \
  --cookies /path/to/cookies.txt

or

bash
python3 scripts/run_youtube_workflow.py "https://www.youtube.com/watch?v=VIDEO_ID" \
  --cookies-from-browser chrome

Batch / queue mode

See references/batch-input-format.md.

Safe invocation rule for batch mode:

  • if you have exactly one URL, use run_youtube_workflow.py <url>
  • if you have more than one URL, first create a plain-text batch file with one URL per line, then pass only --batch-file to the batch runner
  • do not pass multiple positional URLs directly to run_youtube_batch_end_to_end.py

Recommended end-to-end batch mode:

bash
cat > ./youtube-urls.txt <<'EOF'
https://www.youtube.com/watch?v=VIDEO_ID_1
https://www.youtube.com/watch?v=VIDEO_ID_2
EOF
py

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 117)May include surrounding context.

md
- do not pass multiple positional URLs directly to `run_youtube_batch_end_to_end.py`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 126)May include surrounding context.

md
- do not pass multiple positional URLs directly to `run_youtube_batch_end_to_end.py`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 179)May include surrounding context.

md
- do not pass multiple positional URLs directly to `run_youtube_batch_end_to_end.py`

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/detailed-workflow.md (reported line 310)May include surrounding context.

md
- If subtitles are absent or unusable, fall back cleanly to Whisper without treating that as a workflow failure.
- Use the transcript normalization helper before summarizing when the raw transcript is messy or when rolling captions create repeated phrases.
- When language auto-detection is inconclusive, record `unknown` rather than pretending the language is known.
- `--cookies-from-browser` may require local browser/keychain access and can hang or fail in locked-down/headless environments; prefer explicit cookie files when reliability matters.
- Private/login-gated video access should be validated with a real test video before blaming the rest of the pipeline.
- If the transcript is tiny or low-information, write a correspondingly small, honest summary instead of inventing detail.
- If the transcript is too large, summarize in chunks and then synthesize the final summary.

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · scripts/generate_summary_llm.py (reported line 144)May include surrounding context.

python
def call_llm(system_msg: str, user_msg: str, model: str) -> str:
    """Call the OpenClaw LLM via the openclaw infer model run CLI."""
    full_prompt = f"{system_msg}\n\n---\n\n{user_msg}"
    env = os.environ.copy()
    session_key = env.get(LAUNCH_SESSION_KEY_ENV, "").strip()
    if session_key:
        env[LAUNCH_SESSION_KEY_ENV] = session_key

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
91% confidence
Finding

Copying the full environment into a child process can expose unrelated secrets such as API keys, browser/session tokens, cloud credentials, and other sensitive variables to downstream code. In this skill, that risk is amplified because the workflow chains into other local scripts and handles private/restricted YouTube content, increasing the chance that more secrets than necessary are propagated across components.

Content

Scanner excerpt · scripts/run_youtube_batch_end_to_end.py (reported line 223)May include surrounding context.

python
str(raw_path),
        str(summary_path),
    ]
    env = os.environ.copy()
    session_key = get_launch_session_key()
    if session_key:
        env[LAUNCH_SESSION_KEY_ENV] = session_key

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

High
Category
YARA Match
Confidence
75% confidence
Finding

YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Content

Scanner excerpt · scripts/run_youtube_workflow.py (reported line 666)May include surrounding context.

python
lp="Fetch metadata and planned paths only")
    parser.add_argument("--subtitle-first", action="store_true", default=True, help="Try subtitles before local transcription")
    parser.add_argument("--no-subtitle-first", dest="subtitle_first", action="store_false", help="Skip subtitle-first attempt")
    parser.add_argument("--cookies", help="Path to yt-dlp cookies file")
    parser.add_argument("--cookies-from-browser", help="Browser name for yt-dlp cookie extraction, e.g. chrome or safari")
    parser.add_argument("--retries", type=int, default=3, help="Retry count for yt-dlp operations")
    parser.add_argument("--retry-backoff", type=float, default=3.0, help="Base backoff seconds for yt-dlp retries")
    parser.add_argument("--continue-on-error", action="store_true", help="In batch mode, continue processing after an item fails")
    args = parser.parse_args()

    if not args.url and not args.batch_file:
        parser.error("Provide a URL or --batch-file")

    for tool in ("yt-dlp"

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The README explicitly promotes use of browser cookies for private or restricted videos but does not warn that browser-cookie extraction accesses highly sensitive authenticated session material. In a skill context, users may copy commands without realizing this can expose account sessions or broaden the tool's access to private content if logs, artifacts, or downstream scripts mishandle the cookies.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill advertises and instructs use of shell commands, file reads/writes, environment-variable use, network downloads, and local tooling, but it does not declare an explicit tool scope such as permissions or allowed-tools. That creates an avoidable trust and containment gap: an agent or reviewer cannot easily determine the intended execution boundary, increasing the risk of over-broad tool use during operation.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The markdown lists invocation examples like "Summarize this YouTube video into markdown" and "Generate a transcript and polished summary for this YouTube link" without clearly constraining when this skill should activate instead of other generic summarization skills. These phrases are common user requests and could cause unintended invocation collisions in environments with multiple video or summarization skills.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill instructs users to supply cookie files or extract browser cookies for restricted videos, but it does so without a clear warning that cookies are sensitive authentication material. This increases the chance of credential misuse, accidental disclosure, or over-collection of browser-derived secrets, especially in agent-driven environments where logs, prompts, or output artifacts may persist.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · README.md (reported line 39)May include surrounding context.

md
brew install yt-dlp ffmpeg whisper-cpp
MODELS_DIR="$HOME/.openclaw/workspace"
MODEL_PATH="$MODELS_DIR/ggml-medium.bin"
mkdir -p "$MODELS_DIR"
if [ ! -f "$MODEL_PATH" ]; then
  curl -L https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-medium.bin \
    -o "$MODEL_PATH.part" && mv "$MODEL_PATH.part" "$MODEL_PATH"

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · SKILL.md (reported line 44)May include surrounding context.

md
brew install yt-dlp ffmpeg whisper-cpp
MODELS_DIR="$HOME/.openclaw/workspace"
MODEL_PATH="$MODELS_DIR/ggml-medium.bin"
mkdir -p "$MODELS_DIR"
if [ ! -f "$MODEL_PATH" ]; then
  curl -L https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-medium.bin \
    -o "$MODEL_PATH.part" && mv "$MODEL_PATH.part" "$MODEL_PATH"

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · references/detailed-workflow.md (reported line 13)May include surrounding context.

md
brew install yt-dlp ffmpeg whisper-cpp
MODELS_DIR="$HOME/.openclaw/workspace"
MODEL_PATH="$MODELS_DIR/ggml-medium.bin"
mkdir -p "$MODELS_DIR"
if [ ! -f "$MODEL_PATH" ]; then
  curl -L https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-medium.bin \
    -o "$MODEL_PATH.part" && mv "$MODEL_PATH.part" "$MODEL_PATH"

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The workflow explicitly instructs the agent to create, overwrite, and later delete local files, but it does not require an upfront user-facing notice or confirmation before modifying the filesystem. In an agent setting, this can lead to unexpected data loss, overwriting existing outputs, or deletion of user files in a chosen parent directory if path handling or run context is misunderstood.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill supports --cookies and --cookies-from-browser for restricted videos, which can access authentication material tied to the user's accounts, but the workflow does not present a clear privacy/security warning before doing so. In practice, this may cause users to expose session cookies or grant browser-derived credential access without understanding the sensitivity of that action.

Content

No source excerpt is available for this finding.

Tainted flow: 'text' from pathlib.Path.read_text (line 45, file read) → pathlib.Path.write_text (file write)

Medium
Category
Data Flow
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.

Content

Scanner excerpt · scripts/backfill_detected_language.py (reported line 41)May include surrounding context.

python
replacement = "## Workflow Metadata (JSON)\n```json\n" + json.dumps(metadata, ensure_ascii=False, indent=2) + "\n```"
    text = WORKFLOW_METADATA_RE.sub(replacement, text, count=1)
    raw_path.write_text(text, encoding="utf-8")


def update_summary(summary_path: Path, language: str) -> None:

Tainted flow: 'text' from pathlib.Path.read_text (line 47, file read) → pathlib.Path.write_text (file write)

Medium
Category
Data Flow
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.

Content

Scanner excerpt · scripts/backfill_detected_language.py (reported line 54)May include surrounding context.

python
text = re.sub(r"(## Video ID\s*\n.*?\n)", rf"\1\n## Summary Language\n{language}\n", text, count=1, flags=re.S)
    else:
        text = f"## Summary Language\n{language}\n\n" + text
    summary_path.write_text(text, encoding="utf-8")


def main() -> None:

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The help text explicitly says the language tag is chosen by the current LLM/session, which implies the tool may impose a language/locale decision rather than offering a user-selected preference. This matches the policy concern around forcing a specific language without user opt-in.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The script sends potentially sensitive transcript content, along with metadata such as title and source URL, to an LLM backend without any explicit consent gate or runtime disclosure. In this skill's context, transcripts may come from private or restricted YouTube videos via cookies, so silent transmission to another service boundary can expose confidential internal content.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.