Back to skill

Security audit

video-stt

Security checks for vulnerabilities and agentic risk

Overview

This video transcription skill has a coherent purpose, but its shell wrapper can turn user-controlled options into local Python code execution and it also installs unpinned dependencies during normal use.

Install only if you are comfortable running a local shell-based transcription tool that downloads media, writes audio/transcript files, and may install packages. Avoid passing untrusted values for --model, --format, or --output, and prefer a reviewed version that removes python3 -c interpolation, disables runtime installs, pins dependencies, and accurately documents supported modes.

Vulnerability Patterns
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/stt.sh:103
Finding
Arbitrary Python Code Execution Through Shell Variable Interpolation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/stt.sh:25-40, 82-84, 89-91, 103-137` **Vulnerability Type**: Python code injection through unsafe string interpolation **Risk Level**: High ### Vulnerable Code ```bash # Parse arguments while [[ $# -gt 0 ]]; do case $1 in -o|--output) OUTPUT_FILE="$2" shift 2 ;; -m|--model) MODEL="$2" shift 2 ;; -f|--format) FORMAT="$2" shift 2 ;; ``` ```bash # Find the downloaded file AUDIO_FILE=$(ls -t "$AUDIO_DIR" | head -1) AUDIO_PATH="$AUDIO_DIR/$AUDIO_FILE" ``` ```bash python3 -c " import whisper import json model = whisper.load_model('$MODEL') result = model.transcribe('$AUDIO_PATH') text = result['text'] # Save based on format if '$FORMAT' == 'json': with open('$OUTPUT_FILE', 'w') as f: json.dump(result, f, indent=2) elif '$FORMAT' == 'srt': # Generate SRT with open('$OUTPUT_FILE', 'w') as f: for i, segment in enumerate(result['segments'], 1): start = segment['start'] end = segment['end'] content = segment['text'] f.write(f'$i\\n') f.write(f'{int(start//3600):02d}:{int((start%3600)//60):02d},{int((start%1)*1000):03d} --> ') f.write(f'{int(end//3600):02d}:{int((end%3600)//60):02d},{int((end%1)*1000):03d}\\n') f.write(f'{content}\\n\\n') else: with open('$OUTPUT_FILE', 'w') as f: f.write(text) print(f'Transcription saved to: $OUTPUT_FILE') print(f'Text: {text[:200]}...') " ``` ### Technical Analysis The script constructs an entire Python program inside a double-quoted shell string and directly interpolates `MODEL`, `FORMAT`, `OUTPUT_FILE`, and `AUDIO_PATH` into single-quoted Python string literals. The shell parser does not validate the option values against the documented model and format choices. Consequently, an input containing a single quot ...[truncated 2515 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the dynamically generated `python3 -c` program. Place the transcription implementation in a normal Python module and pass all values as command-line arguments: ```bash python3 "$SCRIPT_DIR/stt.py" \ --model "$MODEL" \ --format "$FORMAT" \ --output "$OUTPUT_FILE" \ "$VIDEO_URL" ``` 2. Parse values with `argparse` in Python so arguments remain data and are never interpreted as source code. 3. Enforce strict allowlists in the shell wrapper before invoking Python: ```bash case "$MODEL" in tiny|base|small|medium|large) ;; *) echo "Invalid model" >&2; exit 2 ;; esac case "$FORMAT" in txt|srt|vtt|json) ;; *) echo "Invalid format" >&2; exit 2 ;; esac ``` 4. Validate that options requiring a value actually have a following argument before reading `$2`. 5. Obtain the downloaded filename deterministically from `yt-dlp`, such as by using its printed post-processing path, instead of selecting the newest arbitrary entry with `ls`. 6. Keep generated audio in a per-run directory created with `mktemp -d`, apply restrictive permissions, and remove it after transcription. 7. If arbitrary output paths are unnecessary, constrain output to the designated output directory and reject paths that resolve outside it. ]]>

T08 · Insecure Dependencies

Warning
Location
scripts/stt.py:18
Finding
Unpinned Dependencies Are Installed Automatically at Runtime<![CDATA[ ## Vulnerability Details **File Location**: `scripts/stt.py:18-26, 53-60`; `scripts/stt.sh:94-100`; `SKILL.md:96-100` **Vulnerability Type**: Unsafe runtime dependency installation and supply-chain exposure **Risk Level**: Medium ### Vulnerable Code From `scripts/stt.py`: ```python # 检查依赖 def check_dependencies(): """检查必要的命令是否可用""" for cmd in ["yt-dlp", "ffmpeg"]: result = subprocess.run(["which", cmd], capture_output=True) if result.returncode != 0: print(f"Warning: {cmd} not found. Installing...") subprocess.run(["brew", "install", cmd], check=False) ``` ```python def transcribe(audio_path: str, model: str = "base", output_path: str = None) -> dict: """使用 Whisper 转录音频""" try: import whisper except ImportError: print("Installing whisper...") subprocess.run(["uv", "pip", "install", "whisper"], check=True) import whisper ``` From `scripts/stt.sh`: ```bash if [ ! -d "$SCRIPT_DIR/.venv" ]; then echo "Creating Python environment with uv..." cd "$SCRIPT_DIR" uv venv uv pip install whisper fi ``` The installation instructions in `SKILL.md` likewise use unpinned package names: ```bash uv venv uv pip install yt-dlp whisper ffmpeg-python ``` ### Technical Analysis The Skill installs Python packages and Homebrew formulae by mutable package names without specifying reviewed versions, cryptographic hashes, or a lockfile. Installation occurs automatically during normal execution when dependencies are missing. This design delegates the effective code executed by the Skill to the current state of external package repositories and their transitive dependency graphs. A compromised release, maintainer account, package-index response, repository mirror, or unexpectedly changed package could introduce code that was not part of the audited project. Python packages may execute code during installation, import, and normal operation. Homebrew formula install ...[truncated 2028 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not install dependencies automatically during transcription. Detect missing requirements, fail safely, and provide explicit setup instructions. 2. Declare exact, reviewed dependency versions in project metadata and commit a lockfile produced by the selected package manager. 3. Require cryptographic hashes for Python artifacts where supported, and use a trusted, explicitly configured package index. 4. Pin Homebrew dependencies to reviewed versions where practical, or require administrators/users to provision system tools separately. 5. Verify the exact Python distribution intended to provide the `whisper` import. Use the canonical package source and package name documented by the selected Whisper implementation. 6. Review and pin transitive dependencies, not only top-level package names. 7. Build the environment in a controlled setup stage and prevent package installation during ordinary Skill execution. 8. Run transcription in a minimally privileged environment with restricted filesystem access, no unnecessary credentials, and limited network access. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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
Findings (15)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
Claiming cloud API and VTT support that are not implemented creates a trust and transparency failure. In security-sensitive agent workflows, inaccurate capability claims can cause users to route data under false assumptions about processing mode, output format, or network exposure.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
Claiming cloud API and VTT support that are not implemented creates a trust and transparency failure. In security-sensitive agent workflows, inaccurate capability claims can cause users to route data under false assumptions about processing mode, output format, or network exposure.

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
A transcription skill should not silently install system packages on the host. This grants the skill environment-modifying capability beyond its declared purpose and increases the blast radius through package-manager side effects, privileged operations, and software supply-chain exposure.

Lp3

Medium
Category
MCP Least Privilege
Confidence
84% confidence
Finding
The skill documentation demonstrates shell execution and file-writing behavior, but it does not declare any tool scope such as permissions or allowed-tools. In an agent environment, this weakens least-privilege controls and can allow the skill to run with broader capabilities than users or orchestrators expect.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The documentation describes use of cloud transcription APIs and API keys without warning that audio extracted from user-supplied video URLs may be sent to third-party services. This can expose sensitive or copyrighted content to external providers without informed consent, which is especially risky for a transcription skill handling arbitrary user media.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The file includes user-facing natural-language content in Chinese in the module docstring, and additional CLI help and status messages throughout the script are also Chinese-only. This imposes a specific language/locale on users without any opt-in or documented justification, which matches the language policy violation criteria.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
# 使用 uv 运行
def run_with_uv(cmd: list):
    """使用 uv 运行命令"""
    return subprocess.run(["uv", "run", "python"] + cmd, check=True)

# 检查依赖
def check_dependencies():
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 check_dependencies():
    """检查必要的命令是否可用"""
    for cmd in ["yt-dlp", "ffmpeg"]:
        result = subprocess.run(["which", cmd], capture_output=True)
        if result.returncode != 0:
            print(f"Warning: {cmd} not found. Installing...")
            subprocess.run(["brew", "install", cmd], check=False)
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
result = subprocess.run(["which", cmd], capture_output=True)
        if result.returncode != 0:
            print(f"Warning: {cmd} not found. Installing...")
            subprocess.run(["brew", "install", cmd], check=False)

# 下载音频
def download_audio(url: str, output_dir: Path) -> str:
Confidence
98% confidence
Finding
Automatically installing system packages with Homebrew modifies the host environment at runtime, which exceeds the stated purpose of simple transcription. In an agent setting this can unexpectedly change system state, pull and execute package install scripts, and create a supply-chain risk if triggered in sensitive environments.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
# 下载音频
def download_audio(url: str, output_dir: Path) -> str:
    """从视频 URL 下载音频"""
    audio_file = output_dir / f"audio_{int(subprocess.run(['date', '+%s'], capture_output=True, text=True).stdout.strip())}.wav"
    
    cmd = [
        "yt-dlp",
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
]
    
    print(f"Downloading audio from: {url}")
    subprocess.run(cmd, check=True, capture_output=True)
    
    # 找到实际下载的文件
    actual_file = max(output_dir.glob("audio_*.wav"), key=os.path.getmtime)
Confidence
87% confidence
Finding
The code passes a user-supplied URL directly to yt-dlp, causing the skill to fetch arbitrary remote content. While there is no shell injection because arguments are passed as a list, this still creates an SSRF-like/network egress risk and can be abused to access internal services or force downloads from attacker-controlled endpoints.

Context-Inappropriate Capability

Medium
Confidence
98% confidence
Finding
Runtime pip installation allows the skill to retrieve and execute external code dynamically, which is unnecessary and risky for a media transcription utility. This broadens the skill's authority and can lead to non-reproducible, externally influenced execution.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
import whisper
    except ImportError:
        print("Installing whisper...")
        subprocess.run(["uv", "pip", "install", "whisper"], check=True)
        import whisper
    
    print(f"Loading Whisper {model} model...")
Confidence
97% confidence
Finding
Installing a Python package at runtime introduces environment mutation and a supply-chain exposure unrelated to the core execution path of a transcription request. In hosted or multi-tenant agent environments, this can be abused to change interpreter state or pull unpinned code from external registries during execution.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
The CLI advertises `vtt` as a supported output format, but `save_output` only implements `json`, `srt`, and a default plain-text branch. This creates a clear mismatch between the documented/declared behavior and what the code actually does.

Natural-Language Policy Violations

Low
Confidence
90% confidence
Finding
SQP-3 applies to all file types and covers language or locale policy violations. The user-facing documentation is predominantly in Chinese, but the file does not offer an alternative language or explain that the skill is intentionally region- or locale-specific, which can violate organizational language-choice expectations.

Static analysis

No suspicious patterns detected.