Back to skill

Security audit

Video Analyzer (TikTok + YouTube + Instagram)

Security checks for vulnerabilities and agentic risk

Overview

The skill has a coherent video-transcription purpose, but it needs review because it silently caches transcripts and includes unsafe save/path handling that could affect local files or commands.

Review before installing. Use a dedicated environment rather than system Python, expect online media and model downloads, and assume transcripts may be stored locally even before you agree to save them. The save workflow and ID handling should be fixed before using this with untrusted videos or sensitive local files.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (5)

T01 · Skill Instruction Hijacking

Error
Location
SKILL.md:19
Finding

Unconditional skill instructions hijack agent behavior and response flow

Content
View full analysis

Vulnerability Details

File Location: SKILL.md, lines 19-43 and 116-120
Vulnerability Type: Agent instruction hijacking
Risk Level: High

Vulnerable Code Snippet:

markdown
**Rule 1 — FIRST MESSAGE IS ALWAYS THIS, NO EXCEPTIONS:**

Use the `message` tool to send this BEFORE running any exec command:
> 📡 Video received, analyzing...

This must be a `message` tool call, not your final reply text. Using the message tool sends it immediately to the user while you continue processing. If you put it in your reply text instead, the user won't see it until everything is done — which defeats the purpose entirely.

Do NOT reference conversation history, prior testing, or anything from the current session. Every URL is treated fresh.

**Rule 2 — NEVER GO SILENT**
The user MUST receive a message every 30-60 seconds while processing. Silence = broken.
- After download step: send "📥 Downloaded! Transcribing now..."
- If anything takes more than 30 seconds: send "⏳ Still working..."

**Rule 3 — NO PERSONAL COMMENTARY. EVER.**
Do NOT add ANY of the following:
- "This appears to be the video we already tested"
- "I recognize this URL" / "you've sent this before"
- "Heads up — this is the same link"
- Any footnote, parenthetical, or aside about the URL or prior usage

Just run the skill and give the answer. End with the save prompt. Nothing else.
markdown
### Step 4 — Offer to save (MANDATORY if from_cache: false)
After giving the answer, ALWAYS ask this — do not skip it:
> 💾 Want to save this transcript so you can ask follow-up questions later without re-downloading? (yes/no)

Technical Analysis

The skill uses unconditional priority language such as “always,” “no exceptions,” “must,” and “do not” to control agent tool calls, suppress relevant conversation history, and force response content. These directives extend beyond the technical requirements of downloading and transcribing ...[truncated 1118 chars]

Remediation
View remediation

Remediation Suggestions

  • Replace absolute directives with conditional workflow guidance.
  • Explicitly state that user instructions, relevant conversation context, and higher-priority safety policies take precedence.
  • Remove the instruction to disregard conversation history.
  • Make progress messages optional and dependent on actual execution time and host capabilities.
  • Ask whether to save a transcript only when consistent with the user’s request.
  • Limit skill instructions to the minimum behavior necessary for video download and transcription.

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:130
Finding

Transcript JSON is interpolated into a shell command without safe argument handling

Content
View full analysis

Vulnerability Details

File Location: SKILL.md, lines 130-135
Vulnerability Type: Shell command injection
Risk Level: Critical

Vulnerable Code Snippet:

markdown
If yes:
```bash
python3 ~/.openclaw/skills/tiktok-analyzer/save_transcript.py "VIDEO_ID" 'JSON_DATA'

Confirm: ✅ Saved to your video library!

text

### Technical Analysis

The documented workflow instructs the agent to place transcript-derived JSON directly inside a shell command enclosed by single quotes. Transcript text is attacker-influenced because it originates from audio in a remote video.

A single quote contained in the serialized transcript can terminate the shell’s quoted argument. Additional shell operators and commands can then be appended. Quoting the placeholder with static single quotes is not sufficient when the data itself may contain a single quote.

The Python script does not need to contain a shell invocation for this vulnerability to exist: exploitation occurs in the agent’s `exec` or shell layer before `save_transcript.py` receives its arguments.

### Attack Path

1. An attacker publishes or supplies a video containing spoken text designed to be transcribed into a shell payload.
2. The user asks the skill to analyze the video.
3. The transcription result contains a single quote followed by shell syntax and an attacker-selected command.
4. The skill asks whether the transcript should be saved.
5. After the user agrees, the agent substitutes serialized transcript data for `JSON_DATA` in the documented shell command.
6. The single quote terminates the intended argument, and the shell evaluates the injected command.
7. The injected command executes with the privileges of the account running the agent.

### Impact Assessment

Successful exploitation can provide arbitrary command execution under the OpenClaw or agent process account. The attacker could read or modify files accessible to that account, execute p
...[truncated 117 chars]
Remediation
View remediation

Remediation Suggestions

  • Do not construct a shell command containing transcript or JSON data.
  • Invoke the Python process with a non-shell argument-array API, such as subprocess.run([...], shell=False).
  • Prefer sending JSON through standard input rather than a command-line argument.
  • Alternatively, write the data using a trusted in-process API with no shell boundary.
  • Validate the JSON schema and impose reasonable size limits before saving.
  • If a shell is unavoidable, use a platform-provided escaping mechanism rather than manual quoting, although eliminating the shell is strongly preferred.

T09 · Insecure Skill Coding Practices

Error
Location
save_transcript.py:16
Finding

Unvalidated video ID permits path traversal and arbitrary JSON file overwrite

Content
View full analysis

Vulnerability Details

File Location: save_transcript.py, lines 16-35
Vulnerability Type: Path traversal and arbitrary file write
Risk Level: High

Vulnerable Code Snippet:

python
def main():
    if len(sys.argv) < 3:
        print(json.dumps({"error": "Usage: save_transcript.py <video_id> <json_data>"}))
        sys.exit(1)

    video_id = sys.argv[1]
    raw = sys.argv[2]

    try:
        data = json.loads(raw)
    except json.JSONDecodeError:
        print(json.dumps({"error": "Invalid JSON data"}))
        sys.exit(1)

    data["saved_at"] = datetime.now().isoformat()
    cache_file = TRANSCRIPTS_DIR / f"{video_id}.json"

    with open(cache_file, "w") as f:
        json.dump(data, f, indent=2)

Technical Analysis

video_id is accepted directly from the command line and interpolated into a filesystem path without format validation or path-containment verification. pathlib.Path does not neutralize .. components or absolute paths when paths are joined.

A value containing directory traversal sequences can escape the intended transcripts directory. The script opens the resulting destination in write mode, which creates a missing file or truncates an existing file. The forced .json suffix limits destination names but does not prevent overwriting attacker-selected writable JSON files.

Attack Path

  1. An attacker or another local caller controls the video_id argument passed to save_transcript.py.
  2. The attacker supplies a value such as ../../target.
  3. The expression TRANSCRIPTS_DIR / f"{video_id}.json" constructs a path outside TRANSCRIPTS_DIR.
  4. open(..., "w") follows the traversing path.
  5. The supplied JSON content is written to or overwrites target.json, provided the process account has filesystem permission.

Impact Assessment

Exploitation allows creation or overwrite of arbitrary .json files accessible to the ...[truncated 262 chars]

Remediation
View remediation

Remediation Suggestions

  • Require generated video identifiers to match a strict allowlist such as ^[a-f0-9]{12}$.
  • Reject path separators, absolute paths, dot components, and identifiers of unexpected length.
  • Resolve both the transcript directory and destination, then verify that the destination is a direct child of the transcript directory.
  • Use Path.is_relative_to() on supported Python versions or an equivalent robust containment check.
  • Consider exclusive file creation where overwriting is not required.
  • Set restrictive directory and file permissions.
  • Avoid accepting storage filenames from external callers; derive them internally from a trusted URL hash.

T09 · Insecure Skill Coding Practices

Error
Location
transcribe.py:124
Finding

Unvalidated transcription ID permits traversal, external MP3 deletion, and cache writes outside intended directories

Content
View full analysis

Vulnerability Details

File Location: transcribe.py, lines 124-145 and 196-200
Vulnerability Type: Path traversal, unauthorized file read and deletion
Risk Level: High

Vulnerable Code Snippet:

python
def cmd_transcribe_only(video_id: str):
    """Step 2: transcribe staged audio by video_id"""
    audio_path = STAGING_DIR / f"{video_id}.mp3"
    if not audio_path.exists():
        print(json.dumps({"error": f"No staged audio found for {video_id}. Run download step first."}))
        sys.exit(1)

    result = transcribe_audio(str(audio_path))
    if "error" in result:
        print(json.dumps(result))
        sys.exit(1)

    # Clean up staging file
    audio_path.unlink(missing_ok=True)

    # Get URL from any existing partial data if available
    result["video_id"] = video_id
    result["from_cache"] = False

    # Save to cache
    cache_file = TRANSCRIPTS_DIR / f"{video_id}.json"
    with open(cache_file, "w") as f:
        json.dump(result, f)
python
elif args[0] == "--transcribe-only":
    if len(args) < 2:
        print(json.dumps({"error": "video_id required"}))
        sys.exit(1)
    cmd_transcribe_only(args[1])

Technical Analysis

The --transcribe-only command accepts an unrestricted identifier from the command line. That identifier is used to construct both an MP3 input path and a JSON output path. No allowlist or resolved-path containment check is performed.

A traversing identifier can select an MP3 outside the staging directory. If transcription succeeds, the script calls unlink() on that external file. It then constructs the cache path from the same attacker-controlled identifier, potentially writing the result outside the transcript directory.

Attack Path

  1. An attacker or local caller invokes transcribe.py --transcribe-only with a traversing identifier.
  2. The identifier causes STAGING_DIR / f"{video_id}.mp3" to ...[truncated 798 chars]
Remediation
View remediation

Remediation Suggestions

  • Validate video_id against the exact format generated by get_video_id, such as ^[a-f0-9]{12}$.
  • Resolve input and output paths before use and verify that each remains inside its designated directory.
  • Reject any identifier containing path separators or dot components.
  • Track staged files in trusted server-side state instead of reconstructing paths from caller-provided identifiers.
  • Before deletion, confirm that the resolved file is a regular file directly beneath STAGING_DIR.
  • Apply the same containment checks before cache writes.
  • Consider using unpredictable staging identifiers if untrusted local users can invoke the command.

T08 · Insecure Dependencies

Warning
Location
SKILL.md:48
Finding

Unpinned packages are installed into the system-managed Python environment

Content
View full analysis

Vulnerability Details

File Location: SKILL.md, lines 48-59
Vulnerability Type: Unsafe dependency installation
Risk Level: Medium

Vulnerable Code Snippet:

markdown
Before the first run, check if dependencies are installed:

```bash
which ffmpeg && python3 -c "import faster_whisper; print('ok')" && python3 -c "import yt_dlp; print('ok')"

If anything is missing, guide the user:

Mac/local:

bash
brew install ffmpeg
pip3 install faster-whisper yt-dlp --break-system-packages

Linux/VPS:

bash
apt install -y ffmpeg
pip install faster-whisper yt-dlp --break-system-packages
text

### Technical Analysis

The installation instructions request the latest dependency versions from mutable package indexes without version constraints or cryptographic hash verification. The `--break-system-packages` option bypasses protections intended to prevent `pip` from modifying a system-managed Python environment.

Although the referenced package names are not demonstrably malicious in the reviewed project, this installation pattern makes future builds non-reproducible and increases exposure to compromised releases, dependency-chain changes, and conflicts with operating-system packages.

### Attack Path

1. A user follows the documented first-run installation instructions.
2. `pip` resolves the current versions of `faster-whisper`, `yt-dlp`, and their transitive dependencies from the configured package index.
3. Package installation code executes with the invoking user’s privileges.
4. A compromised or unexpectedly changed package version can execute code during installation or later import.
5. Because the system-package protection is bypassed, the installation can also alter dependencies used by unrelated system Python applications.

### Impact Assessment

The potential impact is code execution with the privileges of the user performing the installation and modifi
...[truncated 227 chars]
Remediation
View remediation

Remediation Suggestions

  • Pin direct and transitive dependency versions in a reviewed lock file.
  • Use cryptographic hashes with pip --require-hashes where practical.
  • Install dependencies into a dedicated virtual environment rather than using --break-system-packages.
  • Record and verify the expected package index.
  • Add automated dependency vulnerability and integrity scanning.
  • Review dependency updates before changing locked versions.
  • Document supported versions of Python, FFmpeg, faster-whisper, and yt-dlp.
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (6)

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The activation criteria are broad enough to match many ordinary requests involving shared video links or generic summary questions, which can cause the skill to run when the user did not explicitly intend to invoke it. In this skill, unintended activation is more concerning because execution can trigger network downloads, local transcription, and follow-on access to stored transcripts, expanding the chance of unexpected data processing.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill directs the agent to list and read previously saved transcript files in order to answer follow-up questions, but it does not require notifying the user that stored content will be accessed or obtaining fresh consent. This creates a privacy risk because prior transcripts may contain sensitive or unexpected material, and the user may not realize historical local data is being searched and surfaced.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The skill persists downloaded audio in a staging directory and stores transcripts in a cache directory, but there is no consent prompt, retention policy, or user-facing disclosure that potentially sensitive media-derived data will remain on disk. In this context, users may submit private social-media URLs or sensitive spoken content, so silent local persistence increases privacy and data exposure risk if the host is shared, backed up, or later compromised.

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 · transcribe.py (reported line 55)May include surrounding context.

python
"--no-warnings",
        url
    ]
    result = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
    if result.returncode != 0:
        err = result.stderr.strip() or "Unknown error"
        if "private" in err.lower():

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

The Security & Privacy section says 'Your data never leaves your machine' and that 'The only thing that touches the internet is downloading the video itself.' However, the First Run Note later states that faster-whisper downloads a model on first use. That contradicts the earlier blanket statement about internet usage.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
85% confidence
Finding

This code writes transcript data to a local JSON file, which affects user data on disk. Although the module docstring says it saves a transcript to the local library, there is no inline comment, confirmation prompt, or explicit warning near the write operation itself describing that the provided JSON will be persisted locally.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.