Back to skill

Security audit

slide-to-video-converter

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly does what it claims, but its optional TTS server is under-secured and could expose local file operations and heavy compute work to network clients.

Review before installing, especially if you will use the HTTP TTS server or process confidential presentations. Prefer Edge TTS only for content you are comfortable sending to an online service, bind any local TTS server to 127.0.0.1, avoid exposing it to a network without authentication, and pin dependencies/model revisions for repeatable installs.

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 (4)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/tts_server.py:413
Finding

Unauthenticated Network Service Accepts Unrestricted Local File Paths

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/restart_tts.sh:19
Finding

Broad Process Matching Can Terminate Unrelated Processes

Content
View full analysis
/dev/null || true) if [ -n "$PIDS" ]; then echo "[1/4] Stopping existing TTS server (PID: $PIDS)..." kill $PIDS 2>/dev/null || true sleep 2 # Force kill if still alive PIDS_REMAINING=$(pgrep -f "tts_server.py" 2>/dev/null || true) if [ -n "$PIDS_REMAINING" ]; then echo " ⚠️ Force killing remaining processes..." kill -9 $PIDS_REMAINING 2>/dev/null || true sleep 1 fi ``` ### Technical Analysis `pgrep -f` matches the complete command line rather than a project-owned PID. Any accessible process whose command line contains `tts_server.py` can be selected, including: - A TTS server belonging to another checkout. - An unrelated user command containing that string. - A development or diagnostic process referencing the filename. The script first sends the default termination signal and then repeats the broad search before issuing `SIGKILL`. It does not verify the target executable, working directory, project root, process owner, start time, or parent process. ### Attack Path 1. A legitimate process is launched with `tts_server.py` somewhere in its command line. 2. A user runs `scripts/restart_tts.sh`. 3. `pgrep -f "tts_server.py"` returns the unrelated process ID. 4. The script sends a termination signal. 5. If the process remains alive after two seconds, the script sends `SIGKILL`, preventing cleanup or state flushing. ### Impact Assessment The script operates only with the invoking user's process permissions and does not elevate privileges. Nevertheless, it can terminate unrelated processes owned by that user, causing: - Local denial of service. - Loss of in-memory state or incomplete writes. - Disruption of unrelated projects. - Forced G ...[truncated 112 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
SKILL.md:63
Finding

Unpinned Python Dependencies and Mutable Model Artifact

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
scripts/restart_tts.sh:49
Finding

Detached TTS Server Lacks Safe Lifecycle and Exposure Controls

Content
View full analysis
"$LOG_FILE" 2>&1 & NEW_PID=$! echo " PID: $NEW_PID" echo " Log: $LOG_FILE" ``` The server started by this command defaults to all-interface binding: ```python parser.add_argument( "--host", type=str, default="0.0.0.0", help="Server host (default: 0.0.0.0)", ) ``` ### Technical Analysis `nohup` intentionally allows the process to survive terminal closure. The script does not create a PID file, install a cleanup trap, define an idle timeout, or provide a reliable project-specific stop mechanism. Combined with the server's `0.0.0.0` default, the detached process may remain network-reachable after the initiating terminal or automation session ends. This is not an operating-system startup registration or reboot-persistent backdoor. It is a long-lived detached process whose lifecycle is insufficiently controlled. ### Attack Path 1. A user invokes `scripts/restart_tts.sh`. 2. The server is detached through `nohup`. 3. The user closes the terminal or assumes the task has ended. 4. The server continues running and, once functional, listens on every interface. 5. Reachable clients can continue submitting requests until the process is manually identified and stopped. ### Impact Assessment The process runs with the invoking user's privileges. Potential effects include: - Unexpected continued network exposure. - Persistent GPU memory and system-resource consumption during the login session. - Continued availability of unauthenticated TTS endpoints. - Difficulty reliably stopping only the project-owned process. This exceeds the minimum lifecycle needed for a one-time slide conversion unless the user explicitly r ...[truncated 48 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (60)

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The declared description presents a full presentation-to-video pipeline, including document conversion, speaker notes handling, multiple TTS modes, and JSON subtitle input. The supplied code does not implement those end-to-end capabilities. Instead, it assumes slide images and WAV audio already exist and focuses narrowly on assembling them into an MP4 with optional synchronized subtitle overlays. Batch processing is partially consistent, and subtitle syncing/video generation are consistent, but the primary purpose in this chunk is materially narrower than the declared end-to-end pipeline. Therefore this is a description-behavior mismatch for the supplied code chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description presents a broad end-to-end presentation-to-narrated-video system with document conversion, TTS generation, subtitle handling, and batch processing. The supplied code chunk does not implement those capabilities. Its purpose is narrowly limited to merging already-generated slide MP4 files into one final MP4 via FFmpeg, with compatibility checks and optional re-encoding. While such a merger could be one supporting component within a larger pipeline, this code chunk by itself materially differs from the declared primary purpose and lacks the core described functionality.

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 pipeline for turning presentations into narrated MP4 videos with subtitles and multiple TTS backends. The supplied code chunk does not implement that overall behavior. It performs only a narrow preprocessing task: converting PDF pages into PNG images at configured resolutions. While this could be a supporting component of the larger pipeline, the actual code chunk's behavior is materially narrower than the declared purpose and lacks the core advertised capabilities such as TTS, audio validation, subtitle syncing, video assembly, or PPT/PPTX handling. Therefore, the description does not accurately represent what this specific code chunk actually does.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The code largely matches the general theme of creating narrated slide videos, but the declared description significantly overstates implemented capabilities. The actual script is specifically a PDF + JSON-subtitles to MP4 pipeline using Edge TTS. It does not accept PPT/PPTX as inputs in this chunk, does not extract speaker notes from presentation files, and lacks the advertised alternate TTS backends and LibreOffice-based PPTX conversion. Subtitle timing is approximated from text length rather than robustly auto-synced from speech analysis, though this alone is less severe than the missing core features. Because several prominent declared capabilities are absent, this is a material description-behavior mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description is for a broad presentation-to-video pipeline, but the supplied code chunk is only one component: a local HTTP TTS service for Qwen3-TTS. Its primary purpose is speech synthesis and batch generation of WAV audio for slide notes from script.md. While TTS is related to the larger system, the code does not implement the core declared outcomes: converting presentation files, handling JSON subtitles, producing MP4 output, or coordinating multiple TTS modes such as Edge TTS. This is a material description-behavior mismatch rather than a minor implementation-detail difference.

Content

No source excerpt is available for this finding.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
84% confidence
Finding

The documented --skip-validation option disables the audio quality-control step that is presented as a core safeguard. If users rely on validation to catch corrupted, mismatched, or manipulated narration, bypassing it can let incorrect or maliciously substituted output pass through unnoticed.

Content

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

md
python scripts/pipeline.py --force-audio

# Skip audio validation (use existing audio as-is)
python scripts/pipeline.py --skip-validation

# Custom validation threshold
python scripts/pipeline.py --threshold 0.7 --max-retries 3

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
95% confidence
Finding

The --skip-validation flag disables the only quality-control check that verifies generated or existing audio matches the intended slide text, yet the pipeline will still accept and publish output. In an automation context, this can be abused to pass tampered, stale, or mismatched audio into final videos, undermining output integrity and potentially enabling misleading or malicious content insertion.

Content

Scanner excerpt · scripts/pipeline.py (reported line 767)May include surrounding context.

python
help="Skip image generation (use existing images)",
    )
    parser.add_argument(
        "--skip-validation", action="store_true",
        help="Skip Stage 2 audio validation (use existing audio as-is)",
    )
    parser.add_argument(

External Script Fetching

High
Category
Supply Chain
Confidence
90% confidence
Finding

Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Content

Scanner excerpt · scripts/restart_tts.sh (reported line 65)May include surrounding context.

sh
while [ $WAITED -lt $HEALTH_TIMEOUT ]; do
    RESP=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:$PORT/health" 2>/dev/null || echo "000")
    if [ "$RESP" = "200" ]; then
        MODEL_LOADED=$(curl -s "http://localhost:$PORT/health" 2>/dev/null | python3 -c "import sys,json; print(json.load(sys.stdin).get('model_loaded', False))" 2>/dev/null || echo "False")
        if [ "$MODEL_LOADED" = "True" ]; then
            echo "  ✅ TTS server is ready!"
            echo ""

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill advertises and instructs use of capabilities equivalent to file read/write, network access, and shell execution, but does not declare any explicit tool scope or permissions. This weakens least-privilege controls and can cause the agent to use broader capabilities than users or hosting systems expect.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill makes Edge TTS the default, which transmits slide text or speaker notes to an external online service, but the description does not present a prominent privacy warning. Users may unknowingly send confidential presentation content off-device, creating data exposure and compliance risks.

Content

No source excerpt is available for this finding.

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Content

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

md
python scripts/pipeline.py --force-audio

# Skip audio validation (use existing audio as-is)
python scripts/pipeline.py --skip-validation

# Custom validation threshold
python scripts/pipeline.py --threshold 0.7 --max-retries 3

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The file sets lang_code to zh and uses a zh-CN voice, which imposes a specific language/locale choice. There is no indication here that users can opt in to other languages or that the locale restriction is justified as region-specific.

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

python
Returns dict with keys: width, height, r_frame_rate, pix_fmt, codec_name.
    """
    try:
        result = subprocess.run(
            [
                "ffprobe", "-v", "quiet",
                "-select_streams", "v:0",

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
82% confidence
Finding

The concat-demuxer file list is built by embedding absolute paths inside single quotes without escaping embedded quote characters. A crafted filename containing quote characters or concat-directive syntax could break the file list format and potentially cause FFmpeg to read unintended files or behave unexpectedly, which is risky in a pipeline that may process attacker-controlled filenames.

Content

Scanner excerpt · scripts/merge_videos.py (reported line 224)May include surrounding context.

python
]
            print(f"[INFO] Running: {' '.join(cmd[:6])} ... {output_path.name}")

            result = subprocess.run(
                cmd,
                capture_output=True,
                text=True,

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

python
"-movflags", "+faststart+negative_cts_offsets",
                str(output_path),
            ]
            fix_result = subprocess.run(fix_cmd, capture_output=True, text=True)
            tmp_output.unlink(missing_ok=True)

            if fix_result.returncode != 0:

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

python
]
        print(f"[INFO] Running ffmpeg with concat filter...")

        result = subprocess.run(
            cmd,
            capture_output=True,
            text=True,

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

python
# Get duration via ffprobe
        try:
            probe = subprocess.run(
                ["ffprobe", "-v", "quiet",
                 "-show_entries", "format=duration",
                 "-of", "default=noprint_wrappers=1:nokey=1",

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

Edge TTS mode sends slide text to Microsoft's online service, but the pipeline does not provide an explicit privacy disclosure or confirmation before transmitting potentially sensitive presentation content off-host. In a slide-to-video skill, speaker notes often contain proprietary or internal material, so silent network exfiltration to a third party is materially risky.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

HTTP TTS mode POSTs full slide text to a network endpoint and defaults to plain HTTP on localhost, with no transport-security requirements or explicit disclosure to the operator that content is leaving the current process boundary. If the URL is changed to a remote host or traffic is intercepted, sensitive presentation text may be exposed.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The STT validation call forces language="zh", which imposes a specific language/locale behavior regardless of user input or configuration. This is a natural-language policy concern because the file does not offer a language choice or explain why Chinese-only transcription is required.

Content

No source excerpt is available for this finding.

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Content

Scanner excerpt · scripts/pipeline.py (reported line 361)May include surrounding context.

python
threshold: float = DEFAULT_THRESHOLD,
    max_retries: int = DEFAULT_MAX_RETRIES,
    force: bool = False,
    skip_validation: bool = False,
) -> bool:
    """
    Stage 1: Big loop — for each slide, generate audio then immediately validate.

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Content

Scanner excerpt · scripts/pipeline.py (reported line 384)May include surrounding context.

python
threshold: float = DEFAULT_THRESHOLD,
    max_retries: int = DEFAULT_MAX_RETRIES,
    force: bool = False,
    skip_validation: bool = False,
) -> bool:
    """
    Stage 1: Big loop — for each slide, generate audio then immediately validate.

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Content

Scanner excerpt · scripts/pipeline.py (reported line 391)May include surrounding context.

python
threshold: float = DEFAULT_THRESHOLD,
    max_retries: int = DEFAULT_MAX_RETRIES,
    force: bool = False,
    skip_validation: bool = False,
) -> bool:
    """
    Stage 1: Big loop — for each slide, generate audio then immediately validate.

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Content

Scanner excerpt · scripts/pipeline.py (reported line 965)May include surrounding context.

python
threshold: float = DEFAULT_THRESHOLD,
    max_retries: int = DEFAULT_MAX_RETRIES,
    force: bool = False,
    skip_validation: bool = False,
) -> bool:
    """
    Stage 1: Big loop — for each slide, generate audio then immediately validate.

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
94% confidence
Finding

This branch explicitly accepts audio as valid without transcription or similarity checks whenever skip_validation is set. In this skill, which converts presentation content into publishable videos, accepting unverified audio weakens integrity guarantees and can conceal content substitution or accidental mismatches.

Content

Scanner excerpt · scripts/pipeline.py (reported line 438)May include surrounding context.

python
raise
                
                # Step B: Skip validation if requested
                if skip_validation:
                    audio_dur = result.get("duration_seconds", 0) if need_generate else get_audio_duration(str(audio_path))
                    flush_print(f"    ⏭️  Validation skipped, audio accepted ({audio_dur:.1f}s)")
                    passed = True

Static analysis

No suspicious patterns detected.