Back to skill

Security audit

Video Skill

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its video-processing purpose, but its deployment examples can expose unauthenticated model services and send sensitive video data over plaintext HTTP.

Install only if you are comfortable processing the video through the configured AI endpoints. Before running the Docker model stack, bind ports to localhost or put the services behind authentication, TLS, firewall rules, and rate limits. Prefer HTTPS for any non-local provider, never send API keys over plaintext HTTP, and avoid processing private or regulated videos unless the provider and retention controls are acceptable.

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

T09 · Insecure Skill Coding Practices

Warning
Location
config.example.json:2
Finding
Plaintext HTTP Configuration Permits Exposure of Sensitive Video Data and API Credentials<![CDATA[ ## Vulnerability Details **File Location**: `config.example.json:2-21`; related network operations in `src/video_skill_extractor/transcribe.py:16-31` and `src/video_skill_extractor/ai_adapter.py:48-55, 122-130` **Vulnerability Type**: Sensitive data transmitted over an unencrypted network connection **Risk Level**: Medium ### Vulnerable Code ```json { "transcription": { "provider": "whisper-local", "base_url": "http://YOUR_SERVER_IP:8003", "model": "faster-whisper-large-v3", "api_key_env": null, "timeout_s": 60 }, "reasoning": { "provider": "openai-compatible", "base_url": "http://YOUR_SERVER_IP:8001", "model": "qwen35-a3b", "api_key_env": null, "timeout_s": 60 }, "vlm": { "provider": "openai-compatible", "base_url": "http://YOUR_SERVER_IP:8002", "model": "gemma3-vlm", "api_key_env": null, "timeout_s": 60 } } ``` The transcription client uploads the source media and an optional bearer credential to the configured endpoint: ```python endpoint = str(provider.base_url).rstrip("/") + "/v1/audio/transcriptions" headers: dict[str, str] = {} api_key = provider.api_key() if api_key: headers["Authorization"] = f"Bearer {api_key}" with httpx.Client(timeout=provider.timeout_s) as client: with video_path.open("rb") as f: files = {"file": (video_path.name, f, "video/mp4")} data = { "model": provider.model, "response_format": response_format, "timestamp_granularities": timestamp_granularities, } res = client.post(endpoint, files=files, data=data, headers=headers) res.raise_for_status() payload = res.json() ``` The AI adapter similarly uses the configured URL and credential: ```python model = OpenAIChatModel( provider.model, provider=OpenAIProvider( base_url=str(provider.base_url).rstrip("/"), api_key=provider.api_key() or "dummy-local-key", ), ) ``` ### Technical Anal ...[truncated 2150 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Require HTTPS for every non-loopback provider endpoint. 2. Add configuration validation that rejects plaintext HTTP unless the hostname is an explicit loopback address such as `127.0.0.1`, `localhost`, or `::1`. 3. If isolated LAN deployments must remain supported, require an explicit security override such as `allow_insecure_http: true` and display a prominent warning. 4. Never send an API key over HTTP. Reject configurations combining `api_key_env` with an insecure endpoint. 5. Change `config.example.json` to use `https://` placeholders or loopback-only HTTP addresses. 6. Configure certificate verification normally and provide a documented custom-CA option for internal deployments rather than disabling TLS verification. 7. Document that video files, transcripts, and frame images are transmitted to the selected providers. 8. Consider adding provider-level data-sharing confirmation before transmitting media to a non-local host. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
deploy/docker-compose.models.yml:21
Finding
Unauthenticated Model Services Are Published on All Host Network Interfaces<![CDATA[ ## Vulnerability Details **File Location**: `deploy/docker-compose.models.yml:21-29, 54-64, 89-90` **Vulnerability Type**: Unauthenticated network service exposure **Risk Level**: High ### Vulnerable Code The reasoning service listens on all interfaces and is published through a host port: ```yaml ports: - "8080:8080" command: > -m /models/reasoning/Qwen3.5-35B-A3B/Qwen3.5-35B-A3B-Q4_K_M.gguf --host 0.0.0.0 --port 8080 --ctx-size 16384 --temp 1.0 --top-p 0.95 --top-k 20 --min-p 0.00 ``` The VLM is also published without a host-interface restriction: ```yaml ports: - "8081:8080" command: > -m /models/vlm/gemma-3-27b-it/gemma-3-27b-it-Q4_K_M.gguf --mmproj /models/vlm/gemma-3-27b-it/mmproj-F16.gguf --host 0.0.0.0 --port 8080 --ctx-size 8192 --n-gpu-layers 99 --seed 3407 --prio 2 --temp 1.0 --repeat-penalty 1.0 --min-p 0.01 --top-k 64 --top-p 0.95 ``` The transcription service is likewise published on every host interface: ```yaml ports: - "8000:8000" volumes: - ../models/whisper:/home/ubuntu/.cache/huggingface/hub ``` ### Technical Analysis Docker Compose short-form mappings such as `"8080:8080"` publish a service on all host interfaces by default. The reasoning and VLM servers are additionally instructed to listen on `0.0.0.0`. No authentication, TLS termination, reverse proxy, access-control policy, or network-source restriction is configured. The deployment instructions tell users to start this Compose stack directly. If the host is reachable from a LAN, cloud network, or the public Internet, other parties may access the model APIs without credentials. The model endpoints are intentionally necessary for the Skill, but broad unauthenticated host exposure exceeds the minimum network privileges required. The CLI could reach services bound only to loopback when run on the same machine. ### Attack Path 1. An operator follows the documented setup and runs: `docker compose -f de ...[truncated 1224 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Bind host ports to loopback when services are only needed locally: ```yaml ports: - "127.0.0.1:8080:8080" ``` Apply equivalent loopback bindings to ports 8081 and 8000. 2. If remote access is required, do not expose the inference containers directly. Place them behind a reverse proxy that provides: - TLS; - strong authentication; - request-size limits; - rate limiting; - connection and inference timeouts; - source-network allowlisting; - audit logging. 3. Restrict ingress with host firewall rules, cloud security groups, or container network policies. 4. Use an internal Docker network for communication between model services and expose only the minimum required gateway. 5. Add model-server authentication where supported and avoid relying on dummy credentials as an access-control mechanism. 6. Establish request concurrency and resource limits to reduce denial-of-service impact. 7. Update deployment documentation to warn that unrestricted port publication can expose GPU-backed services to other systems. 8. Pin container images to reviewed immutable versions or digests, including replacing `speaches:latest-cuda`, to improve deployment integrity and reproducibility. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (29)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The documented purpose focuses on video processing, but the behavior reportedly includes bootstrap/setup and downloading models into local storage. Hidden or under-disclosed side effects are dangerous because users may invoke the skill expecting only local pipeline execution while it performs network retrievals and persistent filesystem changes, which broadens supply-chain and integrity risk.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The documented purpose focuses on video processing, but the behavior reportedly includes bootstrap/setup and downloading models into local storage. Hidden or under-disclosed side effects are dangerous because users may invoke the skill expecting only local pipeline execution while it performs network retrievals and persistent filesystem changes, which broadens supply-chain and integrity risk.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The documented purpose focuses on video processing, but the behavior reportedly includes bootstrap/setup and downloading models into local storage. Hidden or under-disclosed side effects are dangerous because users may invoke the skill expecting only local pipeline execution while it performs network retrievals and persistent filesystem changes, which broadens supply-chain and integrity risk.

Missing User Warnings

High
Confidence
96% confidence
Finding
The function builds `user_parts` from the text prompt plus image URLs and sends them via `agent.run_sync(user_parts)` to the model provider. Because this may expose image-linked content or metadata to a remote service, the lack of any warning, confirmation, or explanatory comment is a safety-relevant omission.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The README instructs users to send video-derived data, transcripts, frames, and enrichment inputs to external or self-hosted AI endpoints, but it does not warn that these artifacts may contain sensitive personal, proprietary, or regulated information. In this skill context, the pipeline explicitly processes narrated videos and extracted frames, which increases the likelihood of transmitting confidential content off-host without informed user consent or appropriate handling controls.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill declares executable behavior that uses shell commands, filesystem access, environment-dependent configuration, and network connectivity, but it does not declare any explicit tool scope or permissions boundary. That makes the skill harder to sandbox and review, and increases the chance it will be invoked with broader capabilities than necessary, especially because it runs setup, validation, and provider connectivity commands.

Vague Triggers

Medium
Confidence
87% confidence
Finding
The invocation description is broad enough to match generic requests like debugging connectivity or generating markdown, which may cause the skill to be selected outside its intended narrow context. Over-broad routing increases the likelihood of unnecessary shell, file, or network-capable execution in response to ambiguous prompts, expanding attack surface and enabling prompt-triggered overreach.

Description-Behavior Mismatch

Medium
Confidence
87% confidence
Finding
The manifest describes a skill for processing narrated videos into structured step data, debugging provider connectivity, and generating markdown from extracted skills. This script instead provisions local AI model assets by downloading multiple large models from Hugging Face, which is an environment setup operation rather than part of the user-facing video-processing pipeline described in the manifest.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
This code invokes an external OpenAI-compatible model with `agent.run_sync(user_prompt)`, which transmits user-supplied content to a remote provider. The file contains retry/error handling but no confirmation prompt, print/log disclosure, or comment/docstring warning that user data may be sent off-box.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The code unconditionally passes -y to ffmpeg and writes predictable filenames like step_<segment_id>.mp4 into the output directory, causing silent overwrite of existing files. If segment IDs or output directories collide with prior runs or important user data, this can destroy or replace artifacts without warning, which is especially relevant in an automated video-processing skill that routinely writes files to disk.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
`_data_url_for_image` reads arbitrary local image paths and base64-encodes them for later inclusion in provider requests. While this is expected functionality for a VLM pipeline, it becomes a real security/privacy issue because local files are transformed for outbound transmission with no validation that the files are safe to export and no user-facing warning that local content may be disclosed externally.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The code sends image contents to external model providers via `run_structured_with_images`, and those images are constructed from local frame files without any consent, disclosure, or data-classification gate in this module. In a video-processing skill, frames may contain sensitive personal, proprietary, or on-screen credential data, so silent transmission to third-party AI services creates a real privacy and data-governance risk.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The code serializes transcript chunk content, including raw `text`, and sends it to an external AI provider via `run_structured` without any evidence in this file of consent, minimization, redaction, or provider-boundary checks. Because transcripts can contain sensitive spoken data, this creates a real data-exposure/privacy risk if users are unaware their content is being transmitted off-box to a third party.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
"2",
                str(out_path),
            ]
            subprocess.run(cmd, check=True, capture_output=True, text=True)
            frame_paths.append(str(out_path))

        rows.append(
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
"2",
                str(out_path),
            ]
            subprocess.run(cmd, check=True, capture_output=True, text=True)
            frame_paths.append(str(out_path))

        rows.append(
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
This code constructs a remote transcription endpoint and uploads the local video file via an HTTP POST request. The file contains no confirmation prompt, print/log disclosure, or comment/docstring warning that user media will be transmitted off-box, which is a safety-relevant behavior for code files.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The document explicitly recommends optional AI-generated asset creation and asynchronous asset generation in the pipeline, but it does not require disclosure, consent, or data-minimization controls before sending project-derived prompts, transcripts, frames, or brand data to external AI providers. In a video-processing workflow, those inputs can contain proprietary footage, sensitive narration, internal process details, or customer information, so omission of privacy and data-sharing safeguards creates a real risk of unintended third-party disclosure.

Unverifiable Dependency: pydantic has 4 known advisory(ies) (CVE-2021-29510 (Use of "infinity" as an input to datetime and date fields causes infinite loop i); CVE-2024-3772 (Pydantic regular expression denial of service); CVE-2021-29510 (Pydantic is a data validation and settings management using Python type hinting.) +1 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
40% confidence
Finding
Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Unverifiable Dependency: pydantic-ai has 10 known advisory(ies) (CVE-2026-25580 (Pydantic AI has Server-Side Request Forgery (SSRF) in URL Download Handling); CVE-2026-48782 (pydantic-ai: SSRF blocklist bypass via IPv4-compatible, SIIT/IVI, and local NAT6); CVE-2026-46678 (Pydantic AI: SSRF cloud-metadata blocklist bypass via IPv4-mapped IPv6 (Incomple) +7 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
84% confidence
Finding
The project depends on pydantic-ai without an upper bound or lockfile, and the package has multiple SSRF-related advisories. Given this skill processes videos and may interact with provider connectivity or remote resources, an unpinned install could resolve to a vulnerable version and expose internal network access or cloud metadata endpoints if any URL-fetching features are used.

Unverifiable Dependency: pytest has 2 known advisory(ies) (CVE-2025-71176 (pytest has vulnerable tmpdir handling); CVE-2025-71176 (pytest has vulnerable tmpdir handling)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
40% confidence
Finding
Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Intent-Code Divergence

Low
Confidence
93% confidence
Finding
The comment says the script bootstraps model directories for "course-step-extractor," while the manifest identifies this skill as "video-skill." This creates intent ambiguity in the documentation and suggests the file may have been repurposed without aligning its inline documentation to the current skill identity.

Missing User Warnings

Low
Confidence
77% confidence
Finding
`write_enriched_steps_jsonl` creates parent directories and writes output JSONL to disk, which is a filesystem-modifying operation. In this file there is no confirmation, logging, or explanatory comment/docstring indicating that the skill will create directories and overwrite/write output content.

Missing User Warnings

Low
Confidence
78% confidence
Finding
The function creates parent directories and writes JSONL output to the provided path, which can modify the filesystem. In this file there is no confirmation prompt, user-facing log/print, or explanatory comment/docstring disclosing that behavior.

Missing User Warnings

Low
Confidence
84% confidence
Finding
The function creates parent directories and writes JSONL output to the provided path, which modifies the filesystem. In this file there is no confirmation prompt, logging, print statement, or explanatory comment/docstring disclosing that behavior to the user.

Missing User Warnings

Low
Confidence
79% confidence
Finding
This code creates directories and writes extracted JPEG frames and a JSONL manifest to disk, but there is no confirmation prompt, logging, comment, or docstring disclosing that filesystem changes will occur. For a code-file review under this rule, file writes should have some visible warning or explanation unless the behavior is explicitly documented elsewhere.

Static analysis

No suspicious patterns detected.