Back to skill

Security audit

Gemini Painter

Security checks for vulnerabilities and agentic risk

Overview

This skill is a narrowly scoped image-generation helper that uses a documented local API and saves generated images, with some configuration and disclosure gaps users should understand.

Install this only if you trust the local service listening on 127.0.0.1:8317, because your image prompts are sent there and generated images are saved under your .openclaw workspace. Avoid putting private information in prompts unless that backend is trusted, and treat the embedded OpenClaw bearer value as non-secret or rotate it if the service relies on it for access control.

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/painter.py:12
Finding
Hardcoded Bearer Credential for Local Image API## Vulnerability Details **File Location**: `scripts/painter.py`, lines 12–13 and 20–23 **Vulnerability Type**: Hardcoded credential **Risk Level**: Medium ### Vulnerable Code ```python BASE_URL = "http://127.0.0.1:8317/v1" API_KEY = "OpenClaw" ``` ```python headers = { "Content-Type": "application/json", "Authorization": f"Bearer {API_KEY}" } ``` ### Technical Analysis The source code embeds the static bearer credential `OpenClaw` and sends it in the `Authorization` header when accessing the local image-generation API. Any user or process capable of reading the distributed Skill can recover and reuse this credential. The loopback destination limits exposure to the local host, and the audited code does not transmit the credential to an external server. Nevertheless, a hardcoded shared token provides no meaningful secrecy, rotation, revocation, or per-user isolation. Its effective scope depends on the permissions granted by the service listening on TCP port 8317. ### Attack Path 1. An attacker obtains read access to the Skill package or its source code. 2. The attacker reads `scripts/painter.py` and extracts the bearer token `OpenClaw`. 3. From the same host, the attacker connects to `127.0.0.1:8317`. 4. The attacker submits requests with `Authorization: Bearer OpenClaw`. 5. If the local service accepts the token, the attacker invokes any API operations authorized for that credential. This path requires local access to the API because the configured endpoint is bound to the loopback address. Whether the service is independently exposed through another interface is outside the reviewed project. ### Impact Assessment A local attacker may submit unauthorized image-generation requests, consume model or computational resources, and invoke other operations exposed by the local API if the shared credential authorizes them. The reviewed code does not establish system-level privilege escalation, external credential exfiltration, or remote code executio ...[truncated 289 chars]
Remediation
## Remediation Suggestions 1. Remove the bearer credential from source code and version control. 2. Load the credential from a protected environment variable or operating-system secret store. 3. Fail closed with a clear configuration error when a required credential is absent. 4. Issue a unique, revocable token scoped only to image generation and apply rate limits where supported. 5. Restrict access to the secret and the local API to the specific account or process that runs the Skill. 6. Rotate or revoke the embedded `OpenClaw` credential because it must be treated as disclosed. 7. If the loopback service intentionally requires no authentication, remove the ineffective bearer-token mechanism rather than distributing a shared token. 8. Prefer authenticated local IPC or enforce a strict loopback binding and service-level authorization to reduce unauthorized local use.
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
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (7)

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill advertises networked code execution behavior via a local HTTP endpoint and likely environment access, but it does not declare any explicit tool scope or permissions boundary. This creates a capability mismatch: users and the host system cannot clearly constrain or review what external access the skill requires, increasing the risk of unintended network use, secret exposure, or privilege creep if the backing script evolves.

Vague Triggers

Medium
Confidence
90% confidence
Finding
The invocation examples are framed as natural everyday requests without clear trigger boundaries, exclusions, or confirmation requirements. In an agentic environment, this can cause over-broad activation or accidental invocation during normal conversation, which may lead to unintended image generation, unnecessary network calls, and unreviewed file writes to the archive directory.

Intent-Code Divergence

Medium
Confidence
92% confidence
Finding
The function docstring states it uses the Gemini Imagen 3 interface to generate images, but the implementation targets `/chat/completions` and sets `MODEL = "gemini-3-pro-image"` rather than an Imagen 3-specific API/model. This is an active documentation-to-code mismatch about the underlying service being used, not merely an omitted detail.

External Transmission

Medium
Category
Data Exfiltration
Content
}
    
    try:
        response = requests.post(url, json=payload, headers=headers, timeout=120)
        if response.status_code != 200:
            return {"status": "error", "message": f"API returned status {response.status_code}"}
Confidence
88% confidence
Finding
The skill transmits the full user prompt to an HTTP API endpoint, creating an external data exposure path for potentially sensitive user input. Although the endpoint is localhost, the use of plain HTTP and dependence on a local service means prompts can still be disclosed to an untrusted local proxy/service or logged by that backend without user awareness.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The code creates directories and writes generated image bytes to a persistent path under the user's profile, but there is no confirmation prompt, warning print, or user-facing disclosure around this file write. The docstring describes image generation but does not clearly warn that files will be saved automatically to disk in a default location.

Tainted flow: 'output_path' from os.environ.get (line 57, credential/environment) → open (file write)

Medium
Category
Data Flow
Content
# 确保目录存在
                    os.makedirs(os.path.dirname(output_path), exist_ok=True)
                    
                    with open(output_path, "wb") as f:
                        f.write(image_bytes)
                    
                    return {
Confidence
92% confidence
Finding
The file write path is derived from the USERPROFILE environment variable and then used directly in os.makedirs/open without validating that it stays within an expected archive directory. In an agent or launcher context where environment variables can be influenced, this can redirect writes to unintended filesystem locations and enable overwriting or planting files outside the intended workspace.

Natural-Language Policy Violations

Low
Confidence
85% confidence
Finding
The function docstring is written only in Chinese, which indicates a language-specific presentation without offering user choice or documenting a locale-specific requirement. This can violate language or locale policy when a skill imposes one language by default without opt-in.