Back to skill

Security audit

Openclaw Thumbnail Forge

Security checks for vulnerabilities and agentic risk

Overview

This skill is a local video thumbnail workflow with expected file writes and local media-tool execution, with no evidence of hidden network, credential, persistence, or destructive behavior.

Install Pillow in a virtual environment from a trusted package index, run the scripts as a normal user, keep PATH limited to trusted directories, and point outputs to a directory where overwriting generated PNG or JSON files is acceptable.

Vulnerability Patterns
  • Tool Hijacking and SpoofingModifies or replaces tools so legitimate-looking calls execute attacker logic
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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)

T08 · Insecure Dependencies

Note
Location
SKILL.md:39
Finding

Unpinned Pillow Dependency Installation

Content
View full analysis
Remediation
View remediation
``` 2. Generate and record SHA-256 hashes for approved distribution artifacts. 3. Require hash validation during installation: ```bash python3 -m pip install --require-hashes -r requirements.txt ``` 4. Document an approved HTTPS package index and avoid silently relying on user-configured third-party mirrors. 5. Use a lock-file workflow and automated dependency-update review so version changes are explicit and reproducible. 6. Periodically scan the pinned version for published vulnerabilities and update it through a reviewed change. ]]>

T07 · Tool Hijacking and Spoofing

Warning
Location
scripts/pick_frames.py:47
Finding

PATH-Based ffmpeg and ffprobe Executable Hijacking

Content
View full analysis
float: """Return media duration in seconds. Raises RuntimeError on ffprobe failure.""" res = subprocess.run( [ "ffprobe", "-v", "error", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", str(path), ], check=False, capture_output=True, text=True, ) if res.returncode != 0: # Surface only the last meaningful line so the user gets a clean message. msg = (res.stderr or "").strip().splitlines() last = msg[-1] if msg else "ffprobe failed" raise RuntimeError(f"ffprobe failed: {last}") try: return float(res.stdout.strip()) except ValueError: raise RuntimeError("ffprobe returned no duration") def detect_scene_changes(path: Path, threshold: float = 0.3) -> List[float]: res = subprocess.run( [ "ffmpeg", "-hide_banner", "-i", str(path), "-filter:v", f"select='gt(scene,{threshold})',showinfo", "-f", "null", "-", ], check=False, capture_output=True, text=True, ) timestamps: List[float] = [] for line in res.stderr.splitlines(): m = re.search(r"pts_time:([0-9.]+)", line) if m: timestamps.append(float(m.group(1))) return timestamps def extract_frame_at(src: Path, timestamp: float, out_path: Path) -> bool: res = subprocess.run( [ "ffmpeg", "-hide_banner", "-y", "-ss", f"{timestamp}", "-i", str(src), "-frames:v", "1", "-q:v", "2", str(out_path), ], check=False, capture_output=True, text=True, ) return res.returnco ...[truncated 2497 chars]
Remediation
View remediation
Vulnerability Patterns
  • 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
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (12)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description presents a broader end-to-end video thumbnail generation system, including automated frame selection from videos, objective scoring, A/B ranking, and export to multiple platform sizes. The supplied code chunk does only the composition stage on an already-provided input image: it validates paths, opens a local image, optionally resizes and boosts contrast/color, overlays gradient/text/logo elements, and saves one PNG output. This is related to thumbnail composition, so the code is not unrelated or malicious, and it does remain local with no remote calls. However, the actual behavior is materially narrower than the declared primary purpose, omitting several key advertised capabilities.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description presents a full thumbnail-generation pipeline for videos, including frame selection, visual composition, and objective ranking, with export as one final step. The supplied code chunk only implements the export/resizing portion for an already-finished image. It performs local image resizing/cropping to YouTube, Shorts, Instagram, X, and LinkedIn sizes and makes no remote calls, which is consistent with part of the description. However, the primary behavior of this code is materially narrower and different from the declared purpose: it neither generates thumbnails from video nor performs scoring, overlays, watermarking, or A/B ranking. Therefore the description does not accurately represent what this code chunk actually does.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The declared description presents a broader end-to-end local video thumbnail generator: analyze video frames, pick the best frames using objective metrics, compose polished thumbnails, rank A/B variants, and export platform-specific sizes. The supplied code chunk is much narrower. It accepts a source frame image and output directory, then calls a sibling script to create four preset style variants differing by color scheme and text position. With --auto-pick, it calls another sibling scorer script and copies the winning image. There are no remote calls, which is consistent with the description, but the main claimed capabilities around video analysis, frame selection, and multi-size export are absent from this code. Because the actual behavior is only a small orchestration subset of the declared end-to-end tool, the description does not accurately represent what this supplied chunk actually does.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The code is consistent with only one subset of the description: local frame selection from videos using brightness, sharpness, and scene-change-related scoring, with no remote calls. However, the declared purpose substantially overstates functionality. This script does not compose thumbnails, add text/graphics/watermarks, generate multiple output aspect ratios/sizes, or rank thumbnail design variants. Its primary implemented behavior is candidate frame extraction and scoring, outputting PNG frames and a JSON report. Therefore the description does not accurately represent what this code chunk actually does.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description presents a full local thumbnail-generation pipeline for videos: extracting and selecting frames, composing polished thumbnail designs, producing multiple platform-specific outputs, and ranking variants. The supplied code chunk instead implements only the ranking/scoring portion for existing image files. It reads one or more image paths, computes heuristic metrics such as contrast, focal-pop proxy, saturation, text-band detection, brightness, and edge density, then ranks images and optionally writes a JSON report. This is materially narrower and different in primary purpose from a thumbnail generator. While the 'no AI APIs, no remote calls' aspect is consistent, the core advertised capabilities—video handling, frame selection, composition, watermarking, and multi-size export—are absent from the code shown.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding

Without declared permissions the skill's intent is opaque and cannot be validated.

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/make_variants.py (reported line 112)May include surrounding context.

python
cmd += ["--logo", args.logo, "--logo-corner", args.logo_corner,
                    "--logo-scale", str(args.logo_scale)]

        res = subprocess.run(cmd, check=False, text=True, stderr=subprocess.PIPE)
        if res.returncode != 0:
            print(f"  variant {letter} failed: {res.stderr.strip()}", file=sys.stderr)
            continue

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/make_variants.py (reported line 138)May include surrounding context.

python
file=sys.stderr)
            return 0
        cmd = [sys.executable, str(scorer), "--json"] + [str(p) for p in produced]
        res = subprocess.run(cmd, check=False, text=True, capture_output=True)
        if res.returncode != 0:
            print(f"warning: scorer failed: {res.stderr.strip()}",
                  file=sys.stderr)

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/pick_frames.py (reported line 49)May include surrounding context.

python
def probe_duration(path: Path) -> float:
    """Return media duration in seconds. Raises RuntimeError on ffprobe failure."""
    res = subprocess.run(
        [
            "ffprobe", "-v", "error",
            "-show_entries", "format=duration",

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/pick_frames.py (reported line 70)May include surrounding context.

python
def detect_scene_changes(path: Path, threshold: float = 0.3) -> List[float]:
    res = subprocess.run(
        [
            "ffmpeg", "-hide_banner", "-i", str(path),
            "-filter:v", f"select='gt(scene,{threshold})',showinfo",

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/pick_frames.py (reported line 87)May include surrounding context.

python
def extract_frame_at(src: Path, timestamp: float, out_path: Path) -> bool:
    res = subprocess.run(
        [
            "ffmpeg", "-hide_banner", "-y",
            "-ss", f"{timestamp}",

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

This code file performs a file write when --output is provided, creating parent directories and overwriting the target path via write_text. While this behavior is functional and user-initiated, there is no explicit warning about the write/overwrite side effect in a confirmation prompt or dedicated cautionary comment near the operation.

Content

No source excerpt is available for this finding.