Back to skill

Security audit

cutmv

Security checks for vulnerabilities and agentic risk

Overview

The video-processing skill is coherent, but it needs Review because it contains an unsafe Python eval path and can silently overwrite user files.

Review this skill before installing. It is intended for local video processing, but avoid using its info command on untrusted media or with an untrusted FFmpeg/FFprobe in PATH until eval is replaced with safe fraction parsing. Use new output filenames or backups because processing commands may overwrite existing files without prompting.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Error
Location
skill.py:319
Finding

Unsafe Evaluation of FFprobe-Derived Frame-Rate Data

Content
View full analysis

Vulnerability Details

File Location: skill.py:319
Vulnerability Type: Python code injection through unrestricted eval()
Risk Level: High

Vulnerable Code:

python
"fps": eval(video_stream.get("r_frame_rate", "0/1")) if video_stream else None,

Technical Analysis

The get_video_info() method obtains JSON data from the external ffprobe process and passes the r_frame_rate string directly to Python's unrestricted eval() function. Although legitimate FFprobe output normally represents frame rates as numeric fractions such as 30/1 or 30000/1001, the code does not validate that the value conforms to this restricted format.

eval() interprets its input as a Python expression and executes it in the current process context. Consequently, if the FFprobe output is manipulated to contain a Python expression, that expression can access Python built-ins, import modules, execute operating-system commands, read or alter files, and perform other actions available to the Skill process.

A specially crafted media file alone is not proven to make a standard FFprobe installation emit arbitrary Python expressions in r_frame_rate. Practical exploitation therefore requires a vulnerable or malicious FFprobe build, a spoofed executable earlier in PATH, or another means of manipulating FFprobe's JSON output. Nevertheless, unrestricted evaluation is unnecessary and creates a dangerous execution sink across a process trust boundary.

Attack Path

  1. The attacker gains influence over the ffprobe executable selected from PATH, its output, or a vulnerable media-parsing path that controls the returned r_frame_rate value.
  2. A user or Agent invokes VideoTool.get_video_info() on the supplied media file.
  3. The Skill executes ffprobe and parses its standard output as JSON.
  4. The attacker-controlled expression is retrieved from the video stream's r_frame_rate field.
  5. At skill.py:319, eval() ex ...[truncated 707 chars]
Remediation
View remediation

Remediation Suggestions

Remove eval() and parse the frame rate as a constrained rational number:

python
from fractions import Fraction

frame_rate = video_stream.get("r_frame_rate", "0/1")
try:
    numerator, denominator = frame_rate.split("/", 1)
    if not numerator.isdigit() or not denominator.isdigit():
        raise ValueError("Invalid frame-rate format")
    if int(denominator) == 0:
        raise ValueError("Frame-rate denominator cannot be zero")
    fps = float(Fraction(int(numerator), int(denominator)))
except (ValueError, ZeroDivisionError):
    fps = None

Alternatively, apply a strict regular expression such as ^[0-9]+/[1-9][0-9]*$ before using fractions.Fraction.

Additional hardening should include:

  • Resolve ffprobe to a trusted absolute path rather than relying solely on ambient PATH.
  • Check the FFprobe subprocess return code before parsing its output.
  • Reject malformed JSON and unexpected field types.
  • Apply reasonable bounds to numerator, denominator, and calculated frame rate.
  • Run media parsing with minimal filesystem, environment, and network privileges.
  • Keep FFmpeg and FFprobe updated because they process attacker-controlled binary media formats.
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • 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 (12)

eval() call detected

High
Category
Dangerous Code Execution
Confidence
99% confidence
Finding

The code uses eval() on ffprobe-derived metadata: r_frame_rate is taken from JSON output generated after parsing an attacker-supplied media file, then executed as Python code. If an attacker can influence that field or the ffprobe output path, this can lead to arbitrary code execution in the context of the tool.

Content

Scanner excerpt · skill.py (reported line 319)May include surrounding context.

python
"codec": video_stream.get("codec_name") if video_stream else None,
                "width": video_stream.get("width") if video_stream else None,
                "height": video_stream.get("height") if video_stream else None,
                "fps": eval(video_stream.get("r_frame_rate", "0/1")) if video_stream else None,
            } if video_stream else None,
            "audio": {
                "codec": audio_stream.get("codec_name") if audio_stream else None,

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · README-CN.md (reported line 32)May include surrounding context.

Ubuntu/Debian:

bash
sudo apt install ffmpeg

Windows:

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

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

Ubuntu/Debian:

bash
sudo apt install ffmpeg

Windows:

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

python
def _check_ffmpeg(self):
        """Check if ffmpeg is installed."""
        try:
            subprocess.run(
                ["ffmpeg", "-version"],
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

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

md
raise RuntimeError(
                "FFmpeg not found. Please install FFmpeg first:\n"
                "  macOS: brew install ffmpeg\n"
                "  Ubuntu: sudo apt install ffmpeg\n"
                "  Windows: winget install ffmpeg"
            )

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · skill.py (reported line 38)May include surrounding context.

python
raise RuntimeError(
                "FFmpeg not found. Please install FFmpeg first:\n"
                "  macOS: brew install ffmpeg\n"
                "  Ubuntu: sudo apt install ffmpeg\n"
                "  Windows: winget install ffmpeg"
            )

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The helper forces '-y' on all FFmpeg runs, causing silent overwrite of any existing output file path provided to the tool. In an agent or automation context where paths may be influenced externally, this can destroy user data or overwrite important files without confirmation.

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

python
def _run_ffmpeg(self, args):
        """Run ffmpeg command."""
        cmd = ["ffmpeg", "-y"] + args
        result = subprocess.run(
            cmd,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,

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

python
"-of", "default=noprint_wrappers=1:nokey=1",
            input_file
        ]
        result = subprocess.run(
            probe_cmd,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,

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

python
"-of", "default=noprint_wrappers=1:nokey=1",
            input_file
        ]
        result = subprocess.run(
            probe_cmd,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

This markdown file documents commands that write processed media and extracted frames to user-specified paths, but it does not include any user warning about file creation or possible overwriting of existing outputs. For a skill that affects user data on disk, the description should disclose that behavior so users understand the integrity impact before running it.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The add_subtitle docstring describes adding subtitle files to video, and the inline comment at L505 says the code will convert SRT to ASS for better compatibility. In reality, no conversion is performed: an ASS path is assigned at L506 but never used, and ffmpeg is invoked directly on the original subtitle file. This is an intent/documentation mismatch in the inline comment.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.dynamic_code_execution

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
skill.py:319