Back to skill

Security audit

OpenRouter Image Generation

Security checks for vulnerabilities and agentic risk

Overview

This image-generation skill is mostly coherent, but its reference-image option can upload any readable local file to OpenRouter if given that path.

Review before installing. Use it only with non-sensitive prompts and reference images, keep outputs in an intended workspace path, and do not pass arbitrary local paths as --ref. Prefer setting OPENROUTER_API_KEY through the environment, and consider adding image validation, file-size limits, path restrictions, and a clear external-upload warning before broad use.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/generate.py:24
Finding

Arbitrary Local File Disclosure Through Unvalidated Reference Image Path

Content
View full analysis
dict: """Read an image file and return an OpenAI-style image_url content part.""" mime, _ = mimetypes.guess_type(path) if mime is None: mime = "image/png" with open(path, "rb") as f: b64 = base64.b64encode(f.read()).decode() return { "type": "image_url", "image_url": {"url": f"data:{mime};base64,{b64}"}, } def generate( prompt: str, output: str, ref_image: str | None = None, model: str = "google/gemini-3.1-flash-image-preview", api_key: str | None = None, base_url: str = "https://openrouter.ai/api/v1", ) -> str: """Generate an image and save to *output*. Returns the output path.""" api_key = api_key or os.environ.get("OPENROUTER_API_KEY") if not api_key: sys.exit("Error: OPENROUTER_API_KEY not set and --api-key not provided.") # Build message content content: list[dict] = [] if ref_image: content.append(encode_image(ref_image)) content.append({"type": "text", "text": prompt}) payload = { "model": model, "modalities": ["text", "image"], "messages": [{"role": "user", "content": content}], "max_tokens": 4096, } data = json.dumps(payload).encode() req = urllib.request.Request( f"{base_url}/chat/completions", data=data, headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json", }, method="POST", ) ``` ### Technical Analysis The `--ref` argument is documented as a reference image, but `encode_image()` accepts any readable path. The implementation relies on the filename extension to infer a MIME type and defaults unknown files to `im ...[truncated 2203 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (6)

Tainted flow: 'req' from os.environ.get (line 66, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/generate.py (reported line 77)May include surrounding context.

python
)

    try:
        with urllib.request.urlopen(req, timeout=120) as resp:
            result = json.loads(resp.read())
    except urllib.error.HTTPError as e:
        body = e.read().decode(errors="replace")

Missing User Warnings

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The documentation explains that prompts and optional reference images are sent to OpenRouter/Gemini but does not clearly warn users that their content is transmitted to an external third-party API. This creates a meaningful privacy and data-handling risk, especially if users provide sensitive prompts, personal images, or proprietary material.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill invokes code that can access environment variables, write files, and make network requests, but the manifest does not declare any tool scope or permissions boundaries. This weakens reviewability and least-privilege controls, making it easier for a broadly-triggered skill to exfiltrate secrets or write unexpected files without clear operator awareness.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The trigger description uses very broad phrases like generate, create, draw, or design images, illustrations, covers, and avatars, which can cause the skill to activate for many ordinary user requests. In combination with external network calls and file output, over-broad routing increases the chance that user content is sent to a third party unexpectedly.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
83% confidence
Finding

The text states that English text works reasonably well and advises users to avoid Chinese/Japanese because the model usually garbles those characters. This imposes a language-specific preference in the skill guidance without offering a user choice or framing it as a documented, justified technical limitation with neutral alternatives.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script transmits user prompts and optional reference images to a third-party service, which can expose sensitive text or image content if users assume processing is local. In this skill context, reference images may contain personal, proprietary, or confidential material, so the lack of an explicit disclosure or consent step increases privacy and data handling risk.

Content

No source excerpt is available for this finding.