Back to skill

Security audit

Image Generation Studio

Security checks for vulnerabilities and agentic risk

Overview

This image-generation skill is mostly coherent, but it deserves Review because it runs external provider calls with user credentials and has an unsafe provider-controlled image URL download path.

Install only if you trust the configured image providers and are comfortable sending prompts and input images to them. Prefer `--response-format b64_json` for OpenAI Images-compatible providers when available, avoid custom/proxy providers you do not control, do not store API keys in `config.json` unless you accept plaintext local storage, and keep generated outputs inside intended workspace paths.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (2)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/generate.py:598
Finding

Provider-Controlled Image URL Enables Server-Side Request Forgery

Content
View full analysis
bytes: headers = { **BROWSER_HEADERS, "Accept": "image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer": "https://x.ai/", } req = urllib.request.Request(url, headers=headers, method="GET") with urllib.request.urlopen(req, timeout=timeout) as r: return r.read() ``` The function is invoked using a URL supplied by the remote image provider: ```python if item.get("b64_json"): img_bytes = base64.b64decode(item["b64_json"]) elif item.get("url"): try: img_bytes = _download_image_url(item["url"]) except Exception as e: die(f"Cannot download image from {item['url']}: {e}") ``` ### Technical Analysis An OpenAI Images-compatible provider controls the `url` field returned in each response item. The application passes this value directly to `urllib.request.urlopen()` without validating: - The URL scheme. - The resolved destination address. - Whether the destination is loopback, private, link-local, reserved, or otherwise internal. - Redirect destinations. - The response size. - The response `Content-Type`. Consequently, a malicious or compromised provider can instruct the host running the Skill to make requests to destinations that are not legitimate image storage services. Potential destinations include localhost services, private network interfaces, container-management APIs, and cloud metadata endpoints. The request does not forward the provider API authorization header to the returned URL, which limits direct API-key disclosure. However, this does not prevent the provider from using the Skill as a network pivot. The response is also read into mem ...[truncated 1635 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Note
Location
scripts/generate.py:2
Finding

Automatically Installed Dependencies Are Not Reproducibly Pinned

Content
View full analysis
=3.10" # dependencies = [ # "google-genai>=1.52.0", # "pillow>=10.0.0", # ] # /// ``` The documented execution method is `uv run`, which installs these dependencies as needed. No lockfile, exact versions, artifact hashes, or upper version bounds are present in the audited project. ### Technical Analysis The dependency specifications use broad lower-bound constraints. Each installation can therefore select any future package release satisfying the constraint. Identical Skill invocations may execute materially different third-party code depending on the package versions available at the time of execution. This is not evidence that either named package is currently malicious. The weakness is the absence of reproducible dependency resolution and artifact-integrity controls. If a future compatible release is compromised, malicious, or unexpectedly incompatible, it can be installed and imported automatically when the Skill runs. Python package installation and import hooks execute with the privileges of the user running the Agent. This makes dependency integrity part of the Skill's effective code-execution boundary. ### Attack Path 1. The Agent follows `SKILL.md` and executes the script using `uv run`. 2. `uv` resolves dependency versions using the broad `>=` constraints. 3. A future compromised or unsafe version satisfies the declared constraint. 4. That version is downloaded and installed because no reviewed lockfile or hash restricts the selected artifact. 5. Package installation or imported runtime code executes with the privileges of the Skill process. ### Impact Assessment A compromised dependency could execute arbitrary Python code with the same operating-system privileges as the Agent process. Depending on ...[truncated 486 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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
Findings (13)

Tainted flow: 'req' from os.environ.get (line 733, 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 588)May include surrounding context.

python
headers = {**BROWSER_HEADERS, **headers}
    req = urllib.request.Request(url, data=body, headers=headers, method="POST")
    try:
        with urllib.request.urlopen(req, timeout=timeout) as resp:
            return json.loads(resp.read().decode())
    except urllib.error.HTTPError as e:
        detail = e.read().decode(errors="replace")

Tainted flow: 'req' from os.environ.get (line 733, 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 740)May include surrounding context.

python
headers = {**BROWSER_HEADERS, **headers}
    req = urllib.request.Request(url, data=body, headers=headers, method="POST")
    try:
        with urllib.request.urlopen(req, timeout=timeout) as resp:
            return json.loads(resp.read().decode())
    except urllib.error.HTTPError as e:
        detail = e.read().decode(errors="replace")

Tainted flow: 'req' from os.environ.get (line 733, 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 606)May include surrounding context.

python
"Referer": "https://x.ai/",
    }
    req = urllib.request.Request(url, headers=headers, method="GET")
    with urllib.request.urlopen(req, timeout=timeout) as r:
        return r.read()

External Model or Provider Selection

High
Category
Excessive Agency
Confidence
90% confidence
Finding

Skill selects an external model or provider that may use a different account or billing plan than the operator expects. Undisclosed model switches can cause unexpected cost or quota consumption.

Content

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

python
Usage examples:
    uv run generate.py -p "prompt" -f out.png                                # Gemini (default)
    uv run generate.py -m gemini-3.1-flash-image-preview -p "prompt" -f out.png -r 2K  # Gemini Flash
    uv run generate.py -p "combine" -f out.png -i a.png -i b.png             # Gemini multi-image
    uv run generate.py -m grok-imagine -p "prompt" -f out.jpg -r 2K          # xAI Grok Imagine
    uv run generate.py -m grok-imagine -p "edit it" -f out.png -i src.jpg    # OpenAI Images edit

External Model or Provider Selection

High
Category
Excessive Agency
Confidence
90% confidence
Finding

Skill selects an external model or provider that may use a different account or billing plan than the operator expects. Undisclosed model switches can cause unexpected cost or quota consumption.

Content

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

python
uv run generate.py -p "combine" -f out.png -i a.png -i b.png             # Gemini multi-image
    uv run generate.py -m grok-imagine -p "prompt" -f out.jpg -r 2K          # xAI Grok Imagine
    uv run generate.py -m grok-imagine -p "edit it" -f out.png -i src.jpg    # OpenAI Images edit
    uv run generate.py -m gpt-image-2 -p "prompt" -f out.png                 # OpenAI Responses
"""

import argparse

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill explicitly instructs the agent to run a local Python CLI, inspect configuration state, and interact with provider endpoints, which implies file access, environment-derived credentials, and network use. Because the manifest declares no tool scope or allowed-tools restrictions, a host agent may grant broader-than-necessary capabilities, increasing the blast radius if the skill is misused or the surrounding runtime interprets the skill permissively.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The trigger text is very broad and includes generic phrases like 'make an image' or 'generate a picture,' which can cause the skill to activate for many ordinary requests. In a system with multiple skills or toolchains, that overmatching can route users into a capability that performs local command execution and external API calls unnecessarily, creating avoidable exposure to credentials, files, or network actions.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The activation guidance is broad enough to trigger on generic mentions like Gemini, streaming, or search grounding even when the user may only be asking informational questions rather than requesting image generation. In an agent setting, overbroad routing can cause unintended tool use, unnecessary external API calls, and accidental processing of user content by third-party services.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The search-grounding feature sends request context beyond the core image model flow to an external Google Search service, but the reference does not warn users about that privacy boundary. If prompts contain sensitive data, enabling search could disclose confidential content or metadata to another external service without informed consent.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This reference explicitly documents that user prompts and input images are sent to a remote Responses-compatible endpoint, but it does not warn users that potentially sensitive text or image content will leave the local environment. In an image-generation skill, users may supply personal photos, internal design assets, or confidential prompts, so omission of a privacy notice can lead to inadvertent data disclosure to third-party providers or proxies.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The file explicitly says to use this reference for casual requests like "Configure this interface for me," which is broad enough to trigger the skill in contexts that may not actually be about image-generation-studio configuration. Over-broad invocation guidance can cause incorrect skill activation, leading the agent to solicit or modify provider settings, endpoints, or credential handling when the user intended something else.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The documentation states that the filename is required and that parent directories are created automatically, but it does not clearly warn that using the skill will write files to the local filesystem. In agent workflows, silent file creation can surprise users, overwrite expected workspace state, or contribute to unsafe chained actions if paths are not surfaced clearly before execution.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

This markdown file describes behavior that writes generated images to user-specified paths, creates parent directories automatically, and may download image data from returned URLs. While the behavior is documented functionally, it does not explicitly warn users about the system-impacting effects of file creation and outbound network retrieval, which this category requires for markdown descriptions.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.exposed_secret_literal

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
scripts/generate.py:931