Back to skill

Security audit

ai-image-skills

Security checks for vulnerabilities and agentic risk

Overview

This skill appears to be a real skills.video image-generation helper, but unsafe endpoint options could send the user's API key to arbitrary URLs.

Install only if you are comfortable giving this skill access to a skills.video API key and paid generation capability. Use relative open.skills.video endpoints only, avoid arbitrary --base-url or full --sse-endpoint values, do not store the key in shell profile files if you can use a secrets manager or session-only environment variable, and rotate the key if it may have been exposed.

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

Error
Location
scripts/create_and_wait.py:63
Finding

API Key Disclosure Through Unrestricted Credential-Bearing Request Destinations

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}" ``` `scripts/create_and_wait.py:156-170`: ```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", ) ``` `scripts/create_and_wait.py:324-325, 354-363`: ```python parser.add_argument("--sse-endpoint", required=True, help="SSE create endpoint path or full URL") parser.add_argument("--base-url", default="https://open.skills.video/api/v1") ``` ```python payload = load_payload(args) url = endpoint_url(args.base_url, args.sse_endpoint) emit({"event": "start", "url": url, "mode": "sse_then_poll_fallback"}) sse_rc, generation_id, terminal_payload = run_sse( url=url, api_key=api_key, payload=payload, request_timeout=args.sse_request_timeout, ) ``` `scripts/wait_generation.py:79-100`: ```python def fetch_generation( base_url: str, generation_id: str, api_key: str, request_timeout: float, ) -> tuple[int, Any]: url = f"{base_url.rstrip('/')}/generation/{generation_id}" req = request.Request( url, headers={ "Aut ...[truncated 3396 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
scripts/ensure_api_key.py:39
Finding

Setup Guidance Encourages Plaintext Persistence of a Long-Lived API Key

Content
View full analysis
\"", "echo 'export SKILLS_VIDEO_API_KEY=\"\"' >> ~/.zshrc && source ~/.zshrc", ], ``` ### Technical Analysis The setup output recommends appending the API key directly to `~/.zshrc`. This stores a long-lived bearer credential as plaintext in a persistent shell configuration file. The code does not itself modify the shell profile, so this is not covert persistence. Nevertheless, users following the documented command may expose the credential through file backups, profile synchronization, accidental configuration sharing, permissive file permissions, support bundles, or another local process or account capable of reading the file. The persistent storage is not necessary for the Skill's core operation. The scripts only require the credential to be available at runtime. ### Attack Path 1. The user runs `scripts/ensure_api_key.py` without a configured key. 2. The script displays the shell-profile persistence command. 3. The user replaces the placeholder with a real API key and executes the command. 4. The real key is stored in plaintext in `~/.zshrc`. 5. An attacker or local process with read access to the profile, its backups, or synchronized copies retrieves the key. 6. The attacker reuses the key against the Skills Video API. ### Impact Assessment The exposed credential grants the attacker the API privileges associated with the key. Potential consequences include unauthorized generation requests, consumption of paid credits, access to generation results, and use of other API functions available to that credential. This finding does not independently grant system privileges beyond access already available to a party that can read the profile or its co ...[truncated 100 chars]
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 (6)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description says the skill builds and executes skills.video image generation REST requests from OpenAPI specs. The supplied code does not do any request construction, OpenAPI handling, HTTP calling, or image generation work. Its sole function is to verify presence of an API key in an environment variable and print configuration guidance. While API key checking could be a supporting utility for such a skill, this code chunk by itself has a materially different primary purpose than the declared description, so this is a mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The declared description focuses on constructing and executing skills.video image generation REST requests from OpenAPI specifications. The supplied code does something materially different: it accepts an HTTP status and response body, extracts an error message, classifies the failure, prints structured guidance, and exits with a mapped error code. While this could be a supporting debugging utility within the same ecosystem, the code chunk itself neither builds requests, executes API calls, nor works from OpenAPI specs. Its primary purpose is runtime error analysis and recovery guidance, including billing/credits checks, which is not accurately represented by the declared purpose.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill instructs use of shell, file reads, environment access, and outbound network calls but does not declare any explicit tool scope or permission boundaries. This increases the chance that an agent executes sensitive operations without clear least-privilege constraints, including reading secrets from the environment and making authenticated external requests.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The default prompt uses a very broad invocation phrase, 'Use $ai-image-skills to create images of {subject}', which can overlap with ordinary user requests about creating images. This increases the chance the skill is triggered in situations where the user did not explicitly intend to invoke this specific capability, potentially causing unintended external API usage or routing of requests through the skill.

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.