Back to skill

Security audit

Image Generator

Security checks for vulnerabilities and agentic risk

Overview

This image-generation skill mostly matches its stated purpose, but it has under-disclosed local credential-file access and weak safeguards around downloaded remote content.

Review before installing. Use only with non-sensitive prompts, provide the API key explicitly through the declared environment variable, and be aware that the current script may read local TOOLS.md files and save downloaded content to disk. A safer version should remove ambient credential lookup and restrict downloaded image URLs and file sizes.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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)

T05 · Unauthorized Access and Privilege Escalation

Note
Location
scripts/generate.py:17
Finding
Undocumented Access to Workspace Configuration Files<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate.py`, lines 17-39 **Vulnerability Type**: Undeclared access to potentially sensitive workspace configuration **Risk Level**: Low ### Vulnerable Code ```python def get_api_key() -> str: """从环境变量或 TOOLS.md 获取 API Key""" # 1. 环境变量 key = os.environ.get("ZHIPU_API_KEY") if key: return key # 2. 从 TOOLS.md 读取 possible_paths = [ Path(__file__).parent.parent.parent.parent / "TOOLS.md", Path.cwd() / "TOOLS.md", Path("~/.openclaw/workspace/TOOLS.md"), ] for path in possible_paths: try: if path.exists(): content = path.read_text(encoding="utf-8") match = re.search(r'ZHIPU_API_KEY:\s*(\S+)', content) if match: key = match.group(1) if key and not key.startswith('请在这里'): return key except Exception: continue return None ``` ### Technical Analysis The skill metadata declares `ZHIPU_API_KEY` as a required environment variable, but the implementation also searches several `TOOLS.md` locations outside the skill directory. This behavior is not disclosed as a required permission or configuration source in the metadata. If the environment variable is absent, the script checks and reads workspace-level files using the privileges of the invoking agent. Such files may contain credentials or unrelated sensitive configuration. Reading broader workspace configuration violates least privilege because image generation only requires access to the explicitly supplied environment variable. The current source does not import the `re` module. Consequently, the regular-expression call raises `NameError`, which is silently suppressed by the broad exception handler. The file is nevertheless opened and read before that exception occurs. The current version therefore performs the undeclared file acces ...[truncated 1626 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the `TOOLS.md` fallback and require `ZHIPU_API_KEY` exclusively through the declared environment variable or an approved secret-management interface. 2. If file-based configuration is genuinely required, document it in the skill metadata and request explicit user approval for one fixed configuration path. 3. Do not search parent directories or the current working directory for credentials. 4. Validate ownership and restrictive permissions before reading any credential file. 5. Catch specific expected exceptions instead of suppressing all exceptions. Avoid hiding programming errors such as the missing `re` import. 6. Never log API keys, file contents, or authorization headers. 7. Add tests confirming that the skill does not access files outside its package and explicitly approved output locations. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/generate.py:118
Finding
Unvalidated Server-Provided URL Enables Blind SSRF and Unbounded Downloads<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate.py`, lines 118-129 and 200-212 **Vulnerability Type**: Server-Side Request Forgery and uncontrolled resource consumption **Risk Level**: Medium ### Vulnerable Code ```python def download_image(url: str, output: str) -> str: if not output: timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") output = f"image_{timestamp}.png" resp = requests.get(url, stream=True, timeout=60) resp.raise_for_status() with open(output, "wb") as f: for chunk in resp.iter_content(chunk_size=8192): if chunk: f.write(chunk) return os.path.abspath(output) ``` The URL reaches this function directly from the API response: ```python data = response.json() if "data" not in data or not data["data"]: print(f"❌ 返回结果中未找到 data 字段或为空: {json.dumps(data, ensure_ascii=False)}") sys.exit(1) first = data["data"][0] image_url = first.get("url") if not image_url: print(f"❌ 返回结果中未找到图片 url: {json.dumps(data, ensure_ascii=False)}") sys.exit(1) print("⬇️ 正在下载图片...") saved_path = download_image(image_url, output) ``` ### Technical Analysis The script treats `data[0].url` from the remote API as trusted and passes it directly to `requests.get()`. It does not validate: - The URL scheme - The destination hostname or resolved IP address - Whether the destination is loopback, private, link-local, or otherwise internal - Redirect destinations - The response content type - The maximum response size - Whether the response is actually an image The `requests` library follows HTTP redirects by default. Validating only an initial URL would therefore be insufficient unless every redirect target is also checked. This creates a blind SSRF primitive if the upstream API, its response path, or an intermediary can cause an arbitrary URL to be returned. The process can t ...[truncated 2225 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Permit only `https` image URLs and reject URLs containing embedded credentials or unsupported schemes. 2. Maintain an allowlist of documented BigModel image-delivery domains. If stable host allowlisting is unavailable, validate the resolved destination against a denylist covering loopback, private, link-local, multicast, reserved, and unspecified address ranges for both IPv4 and IPv6. 3. Resolve and validate all returned addresses immediately before connecting, accounting for DNS rebinding. 4. Disable automatic redirects with `allow_redirects=False`, or validate every redirect target before following it and impose a small redirect limit. 5. Require an expected image media type and verify the downloaded file signature rather than trusting the extension or `Content-Type` header alone. 6. Check `Content-Length` where available and enforce an independent streaming byte limit. Abort and delete the partial file when the limit is exceeded. 7. Download into a securely created temporary file, then atomically move it to the requested destination only after validation succeeds. 8. Apply an overall request deadline in addition to connect and read timeouts. 9. Consider using a restricted network client or egress policy that cannot reach local, metadata, or private-network services. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (8)

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
The documented behavior and the analyzed behavior diverge in security-relevant ways: the skill reportedly reads credentials from TOOLS.md beyond the declared environment variable, writes files locally, and does not actually implement the claimed chat-image delivery. This mismatch can mislead users and orchestration systems about what data sources and side effects exist, increasing the risk of credential exposure, unintended file writes, and unsafe automation assumptions.

Lp3

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding
The skill documents capabilities that require environment access, filesystem interaction, and outbound network calls, but it does not declare an explicit tool scope such as permissions or allowed-tools. This weakens least-privilege controls and makes it easier for an agent runtime to grant broader access than users expect, especially since the skill handles API credentials and writes downloaded content locally.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The skill sends user prompts to an external third-party image generation service and then downloads generated content to local storage, but the description does not clearly warn users about either data transfer or local persistence. This creates a privacy and consent risk because sensitive prompts may leave the environment and downloaded files may remain on disk unexpectedly.

Context-Inappropriate Capability

Medium
Confidence
96% confidence
Finding
The script retrieves ZHIPU_API_KEY not only from the environment but also by searching local TOOLS.md files, which broadens credential access beyond what an image-generation utility needs. This creates unnecessary secret discovery behavior and can silently consume credentials from unrelated workspace files, increasing the risk of unauthorized credential use or accidental exfiltration to the external API.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The code reads credentials from local TOOLS.md files without any user-facing notice or consent, so the skill may access sensitive local data unexpectedly. In this skill’s context, that is more dangerous because the retrieved key is immediately used to authenticate outbound requests, turning hidden credential access into practical secret use.

External Transmission

Medium
Category
Data Exfiltration
Content
try:
        while True:
            response = requests.post(url, json=payload, headers=headers, timeout=120)
            if response.status_code == 429:
                try:
                    err = response.json()
Confidence
80% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Natural-Language Policy Violations

Low
Confidence
84% confidence
Finding
Most of the operational instructions and examples are presented only in Chinese, which can impose a language constraint on users or operators without an explicit opt-in. The file does not indicate that Chinese is optional or provide an alternative language version.

Natural-Language Policy Violations

Low
Confidence
72% confidence
Finding
The argument help text explicitly says the image prompt 'supports Chinese', which introduces a language-specific framing in the user-facing interface. Because there is no accompanying statement that other languages are also accepted or user choice is supported, this can be interpreted as a locale/language policy issue.

Static analysis

No suspicious patterns detected.