Back to skill

Security audit

Image Generation

Security checks for vulnerabilities and agentic risk

Overview

The skill is a real image-generation wrapper, but it needs Review because its handling of local files, API keys, and runtime setup creates avoidable credential and data exposure risks.

Review before installing. Use a dedicated, low-quota WeryAI API key, avoid persisting it unless necessary, and do not pass sensitive local files as --ref or in batch files. Prefer a preinstalled/pinned Bun runtime over npx -y bun, and treat generated result URLs and webhook URLs as external network destinations.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/main.ts:170
Finding

API Bearer Token Can Be Disclosed to an Arbitrary Result URL

Content
View full analysis
{ let lastErr = ""; const transientStatus = (status: number) => status === 408 || status === 429 || status === 502 || status === 503 || status === 504 || (status >= 520 && status <= 599); const transientNetwork = (e: unknown) => { const name = e instanceof Error ? e.name : ""; const msg = e instanceof Error ? e.message : String(e); return ( name === "AbortError" || msg.includes("timeout") || msg.includes("Timeout") || msg.includes("fetch failed") || msg.includes("ECONNRESET") || msg.includes("ETIMEDOUT") || msg.includes("EAI_AGAIN") ); }; for (let attempt = 1; attempt <= DOWNLOAD_MAX_ATTEMPTS; attempt++) { let res: Response | null = null; let threw: unknown = null; for (const useAuth of [false, true] as const) { try { const init: RequestInit = { signal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS) }; if (useAuth) init.headers = { Authorization: `Bearer ${getApiKey()}` }; res = await fetch(url, init); threw = null; if (res.ok) break; lastErr = `HTTP ${res.status}`; if (!useAuth && (res.status === 401 || res.status === 403)) continue; break; } catch (e) { threw = e; res = null; lastErr = e instanceof Error ? e.message : String(e); if (!useAuth) continue; break; } } ``` ### Technical Analysis The image download URL is obtained from the gateway's task response and passed directly to `fetchImageBytes`. The code first makes an unauthenticated request and then ...[truncated 1920 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/main.ts:302
Finding

Arbitrary Local Files Can Be Encoded and Uploaded as Reference Images

Content
View full analysis
{ for (const refPath of paths) { const t = refPath.trim(); if (/^https?:\/\//i.test(t)) continue; const fullPath = path.resolve(refPath); try { await access(fullPath); } catch { throw new Error(`Reference image not found: ${fullPath}`); } } } ``` ```ts const body: Record = referenceImages.length > 0 ? { ...baseBody, images: referenceImages.map(toImagePayloadValue) } : baseBody; ``` ### Technical Analysis A reference argument that does not begin with `http://` or `https://` is treated as a local path. The path is resolved, read in full, base64-encoded, and inserted into the request body sent to WeryAI. The validation only establishes that the path is accessible. It does not: - Restrict the file to the project or another approved directory. - Require an actual regular file. - Prevent symbolic-link traversal outside an approved directory. - Verify the file's magic bytes or image format. - Enforce a maximum input size. - Require explicit approval before uploading a local file. The MIME type is inferred only from the extension. A sensitive file can therefore be renamed or supplied directly ...[truncated 1574 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/setup.mjs:114
Finding

API Key Persistence Uses Plaintext Files Without Restrictive Permissions

Content
View full analysis
Project directory to write/read .image-skills config (default: cwd) --workflow Optional focus: general|cover|rednote|infographic|comic|article|compress --force-models Overwrite MODELS.json if it already exists --api-key Write IMAGE_GEN_API_KEY into local skill config --persist-api-key Persist current IMAGE_GEN_API_KEY from env into local skill config --scope Where to write the local .env: project or home (default: project) --json Print JSON output -h, --help Show help ``` ```js for (let i = 0; i < argv.length; i++) { const current = argv[i]; if (current === "--project") args.project = argv[++i] ?? args.project; else if (current === "--workflow") args.workflow = argv[++i] ?? args.workflow; else if (current === "--force-models") args.forceModels = true; else if (current === "--api-key") args.apiKey = argv[++i] ?? null; else if (current === "--persist-api-key") args.persistApiKey = true; ``` ```js function writeApiKeyConfig({ project, homeDir, scope, apiKeyInput }) { const envPath = resolveEnvPath({ project, homeDir, scope }); if (!apiKeyInput.requested) { return { ok: true, wrote: false, path: envPath, status: "not-requested", source: apiKeyInput.source }; } if (!envPath) { return { ok: false, wrote: false, path: null, status: "missing-home-dir", source: apiKeyInput.source }; } if (!apiKeyInput.value) { return { ok: false, wrote: false, path: envPath, stat ...[truncated 2241 chars]
Remediation
View remediation
` option. 2. Accept secrets through a protected environment variable, concealed interactive input, or standard input that is not recorded in command history. 3. Prefer an operating-system credential store where available. 4. Create the configuration directory with mode `0700`. 5. Create the `.env` file atomically with mode `0600`. 6. If the file already exists, verify and correct its ownership and permissions before writing. 7. Use a temporary file in the same private directory, set its permissions before adding secret content, then atomically rename it. 8. Warn when the project configuration directory is inside a version-controlled workspace and ensure `.env` is ignored. 9. Add tests that verify effective permissions and confirm the secret never appears in output or process arguments. 10. Apply the same hardening to the duplicated vendored setup script. ]]>

T08 · Insecure Dependencies

Error
Location
scripts/vendor/weryai-image/run-generate.mjs:35
Finding

Unpinned Remote Bun Package Is Downloaded and Executed Through npx

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (75)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared purpose is specifically about image generation functionality (text-to-image/image-to-image, polling, download handling). The actual code does not generate, poll for, or download images. It only queries the generation balance endpoint and returns credit information. That is a materially different primary purpose and an undeclared capability related to account balance lookup, so this is a mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description says this skill is for generating images through a gateway CLI, including async request handling, polling, and downloads. However, the supplied code only retrieves the model registry and returns available models for text-to-image or image-to-image modes. Its primary purpose is model enumeration, not image creation. This is a material description-behavior mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The declared description presents a broader skill that supports both text-to-image and image-to-image workflows, plus polling and download handling. The supplied code chunk only implements submission for image-to-image generation via POST to /v1/generation/image-to-image. It validates and normalizes input, consults a model registry, supports dry-run request preview, and returns task IDs from the submission response. There is no evidence here of text-to-image generation, asynchronous polling/status checks, or downloading generated images. Because the declared purpose materially overstates the capabilities shown in this code chunk, this is a mismatch.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 29)May include surrounding context.

md
| Base URL | `https://api.weryai.com` (hard-coded in `scripts/main.ts`) |

Credential Access

High
Category
Privilege Escalation
Confidence
89% confidence
Finding

The skill explicitly handles an API key and permits persisting it into local .env files, which creates credential exposure risk if file permissions, repository hygiene, or workspace boundaries are weak. Any skill that reads and stores secrets needs tight scoping, because compromise of the project directory or later tooling can disclose the key.

Content

Scanner excerpt · SKILL.md (reported line 49)May include surrounding context.

md
3. **If `IMAGE_GEN_API_KEY` is missing**, ask the user for permission to configure it now
4. Only after readiness and API key are resolved, continue to model selection / prompt clarification / generation

**Access token**: only use **`IMAGE_GEN_API_KEY`**. It may also live in `.image-skills/image-generation/.env` as `IMAGE_GEN_API_KEY=...`. After the user approves, the agent may persist it there by running `npm run setup -- --project . --workflow <workflow> --persist-api-key` when the key is already in env, or by writing the file locally on the user's behalf instead of asking the user to edit files manually.

**First-use readiness check**: before the first generation run in a new OpenClaw or local instance, the agent must run:

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/doctor.mjs (reported line 90)May include surrounding context.

js
const projectSkillDir = path.join(projectRoot, ".image-skills", skillNamespace);
  const homeSkillDir = homeRoot ? path.join(homeRoot, ".image-skills", skillNamespace) : null;

  const projectEnvPath = path.join(projectRoot, ".image-skills", skillNamespace, ".env");
  const projectEnvFile = pathExists(projectEnvPath);
  let apiKeyInProjectEnv = false;
  if (projectEnvFile) {

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/main.ts (reported line 403)May include surrounding context.

ts
const projectSkillDir = path.join(projectRoot, ".image-skills", skillNamespace);
  const homeSkillDir = homeRoot ? path.join(homeRoot, ".image-skills", skillNamespace) : null;

  const projectEnvPath = path.join(projectRoot, ".image-skills", skillNamespace, ".env");
  const projectEnvFile = pathExists(projectEnvPath);
  let apiKeyInProjectEnv = false;
  if (projectEnvFile) {

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/main.ts (reported line 476)May include surrounding context.

ts
const projectSkillDir = path.join(projectRoot, ".image-skills", skillNamespace);
  const homeSkillDir = homeRoot ? path.join(homeRoot, ".image-skills", skillNamespace) : null;

  const projectEnvPath = path.join(projectRoot, ".image-skills", skillNamespace, ".env");
  const projectEnvFile = pathExists(projectEnvPath);
  let apiKeyInProjectEnv = false;
  if (projectEnvFile) {

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/main.ts (reported line 477)May include surrounding context.

ts
const projectSkillDir = path.join(projectRoot, ".image-skills", skillNamespace);
  const homeSkillDir = homeRoot ? path.join(homeRoot, ".image-skills", skillNamespace) : null;

  const projectEnvPath = path.join(projectRoot, ".image-skills", skillNamespace, ".env");
  const projectEnvFile = pathExists(projectEnvPath);
  let apiKeyInProjectEnv = false;
  if (projectEnvFile) {

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/vendor/shared-image-generation/scripts/doctor.mjs (reported line 90)May include surrounding context.

js
const projectSkillDir = path.join(projectRoot, ".image-skills", skillNamespace);
  const homeSkillDir = homeRoot ? path.join(homeRoot, ".image-skills", skillNamespace) : null;

  const projectEnvPath = path.join(projectRoot, ".image-skills", skillNamespace, ".env");
  const projectEnvFile = pathExists(projectEnvPath);
  let apiKeyInProjectEnv = false;
  if (projectEnvFile) {

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/vendor/shared-image-generation/scripts/main.ts (reported line 403)May include surrounding context.

ts
const projectSkillDir = path.join(projectRoot, ".image-skills", skillNamespace);
  const homeSkillDir = homeRoot ? path.join(homeRoot, ".image-skills", skillNamespace) : null;

  const projectEnvPath = path.join(projectRoot, ".image-skills", skillNamespace, ".env");
  const projectEnvFile = pathExists(projectEnvPath);
  let apiKeyInProjectEnv = false;
  if (projectEnvFile) {

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/vendor/shared-image-generation/scripts/main.ts (reported line 476)May include surrounding context.

ts
const projectSkillDir = path.join(projectRoot, ".image-skills", skillNamespace);
  const homeSkillDir = homeRoot ? path.join(homeRoot, ".image-skills", skillNamespace) : null;

  const projectEnvPath = path.join(projectRoot, ".image-skills", skillNamespace, ".env");
  const projectEnvFile = pathExists(projectEnvPath);
  let apiKeyInProjectEnv = false;
  if (projectEnvFile) {

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/vendor/shared-image-generation/scripts/main.ts (reported line 477)May include surrounding context.

ts
const projectSkillDir = path.join(projectRoot, ".image-skills", skillNamespace);
  const homeSkillDir = homeRoot ? path.join(homeRoot, ".image-skills", skillNamespace) : null;

  const projectEnvPath = path.join(projectRoot, ".image-skills", skillNamespace, ".env");
  const projectEnvFile = pathExists(projectEnvPath);
  let apiKeyInProjectEnv = false;
  if (projectEnvFile) {

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · scripts/main.ts (reported line 602)May include surrounding context.

ts
}

function applyStylePreset(prompt: string, style: StylePreset | null | undefined): string {
  if (!style) return prompt;
  return `${prompt.trim()}\n\nStyle preset (${style}): ${STYLE_PRESETS[style]}.`;
}

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · scripts/vendor/shared-image-generation/scripts/main.ts (reported line 602)May include surrounding context.

ts
}

function applyStylePreset(prompt: string, style: StylePreset | null | undefined): string {
  if (!style) return prompt;
  return `${prompt.trim()}\n\nStyle preset (${style}): ${STYLE_PRESETS[style]}.`;
}

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/doctor.mjs (reported line 284)May include surrounding context.

js
-h, --help            Show help

What this does:
  1) Optionally writes IMAGE_GEN_API_KEY into the local skill .env
  2) Runs doctor (read-only)
  3) Ensures a MODELS.json exists (writes the bundled starter if missing)
  4) Initializes EXTEND.md with Nano Banana 2 if no default model exists yet

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/main.ts (reported line 577)May include surrounding context.

ts
-h, --help            Show help

What this does:
  1) Optionally writes IMAGE_GEN_API_KEY into the local skill .env
  2) Runs doctor (read-only)
  3) Ensures a MODELS.json exists (writes the bundled starter if missing)
  4) Initializes EXTEND.md with Nano Banana 2 if no default model exists yet

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/setup.mjs (reported line 33)May include surrounding context.

js
-h, --help            Show help

What this does:
  1) Optionally writes IMAGE_GEN_API_KEY into the local skill .env
  2) Runs doctor (read-only)
  3) Ensures a MODELS.json exists (writes the bundled starter if missing)
  4) Initializes EXTEND.md with Nano Banana 2 if no default model exists yet

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/vendor/shared-image-generation/scripts/doctor.mjs (reported line 284)May include surrounding context.

js
-h, --help            Show help

What this does:
  1) Optionally writes IMAGE_GEN_API_KEY into the local skill .env
  2) Runs doctor (read-only)
  3) Ensures a MODELS.json exists (writes the bundled starter if missing)
  4) Initializes EXTEND.md with Nano Banana 2 if no default model exists yet

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/vendor/shared-image-generation/scripts/main.ts (reported line 577)May include surrounding context.

ts
-h, --help            Show help

What this does:
  1) Optionally writes IMAGE_GEN_API_KEY into the local skill .env
  2) Runs doctor (read-only)
  3) Ensures a MODELS.json exists (writes the bundled starter if missing)
  4) Initializes EXTEND.md with Nano Banana 2 if no default model exists yet

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/vendor/shared-image-generation/scripts/setup.mjs (reported line 33)May include surrounding context.

js
-h, --help            Show help

What this does:
  1) Optionally writes IMAGE_GEN_API_KEY into the local skill .env
  2) Runs doctor (read-only)
  3) Ensures a MODELS.json exists (writes the bundled starter if missing)
  4) Initializes EXTEND.md with Nano Banana 2 if no default model exists yet

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill explicitly requires environment access and outbound network access, but it does not declare a restrictive tool scope such as allowed tools or permissions. In an agent ecosystem, that weakens containment and makes it easier for the skill to access secrets and make external requests beyond what a reviewer or runtime may expect.

Content

No source excerpt is available for this finding.

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 · SKILL.md (reported line 3)May include surrounding context.

md
---
name: image-generation
description: Single-gateway image generation CLI for async text-to-image and image-to-image, with polling, download handling, and request alignment to the current gateway OpenAPI. Use when the user asks to generate an image, create a picture, draw something, or make a visual from a text prompt.
version: 0.5.0
metadata: { "pattern": ["tool-wrapper"], "openclaw": { "emoji": "🎨", "primaryEnv": "IMAGE_GEN_API_KEY", "requires": { "env": ["IMAGE_GEN_API_KEY"], "anyBins": ["bun", "npx"], "bins": ["node", "npm"] } } }
---

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The trigger phrases are broad enough to match many ordinary user requests, which can cause the skill to activate in contexts where users did not intend external network use or secret-dependent tooling. Over-broad activation increases the chance of surprise API calls, unintended secret handling, or unnecessary environment modification.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
84% confidence
Finding

The skill instructs the agent to automatically run readiness/bootstrap behavior, which can modify the environment before the user fully understands what will happen. Autonomous setup actions are risky because they may install dependencies or change local state in a way that expands the trust boundary.

Content

Scanner excerpt · SKILL.md (reported line 57)May include surrounding context.

npm run ensure-ready -- --project . --workflow

text

This readiness step is not optional. It checks the local toolchain, reads the local doctor report, and automatically runs `bootstrap` when local script dependencies are missing.

**First-trigger user behavior**: