Back to skill

Security audit

Nanobanana

Security checks for vulnerabilities and agentic risk

Overview

The skill does what it advertises, but it sends prompts, selected images, and a bearer API key to a hard-coded custom third-party endpoint without enough privacy or trust-boundary guidance.

Install only if you trust the operator of claw.cjcook.site with your prompts, any images you explicitly pass with --image, and the API token configured in the script. Use a dedicated, revocable token for this service and avoid sending sensitive or private images unless you have verified the service's privacy and retention practices.

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

other

Error
Location
scripts/nanobanana.js:20
Finding
Untrusted Third-Party Transmission of Prompts, Images, and API Credentials## Vulnerability Details **File Location**: `scripts/nanobanana.js:20-25`, `scripts/nanobanana.js:48-59`, `scripts/nanobanana.js:70-106`, and `scripts/nanobanana.js:137-141` **Vulnerability Type**: Untrusted Third-Party Data Transmission **Risk Level**: High ### Vulnerable Code ```javascript const CONFIG = { baseURL: "https://claw.cjcook.site/v1", apiKey: "YOUR_API_KEY", model: "nanobanana-2pro", maxTokens: 4096, outputDir: path.join(__dirname, "output"), }; ``` ```javascript function fileToBase64(filepath) { const buffer = fs.readFileSync(filepath); const ext = path.extname(filepath).toLowerCase().slice(1); const mimeType = ext === "png" ? "image/png" : ext === "jpg" || ext === "jpeg" ? "image/jpeg" : "image/webp"; return `data:${mimeType};base64,${buffer.toString("base64")}`; } // ============ Core functionality ============ const client = new OpenAI({ baseURL: CONFIG.baseURL, apiKey: CONFIG.apiKey, }); ``` ```javascript async function generateImage(prompt, inputImage = null, options = {}) { const contents = []; // If an input image is provided, put it first if (inputImage) { if (!fs.existsSync(inputImage)) { throw new Error(`Input image does not exist: ${inputImage}`); } contents.push({ type: "image_url", image_url: { url: fileToBase64(inputImage), detail: options.imageDetail || "auto", }, }); } // Add the text prompt contents.push({ type: "text", text: prompt, }); const messages = [ { role: "user", content: contents, }, ]; console.log("Sending request..."); console.log(` Prompt: ${prompt}`); if (inputImage) { console.log(` Input image: ${inputImage}`); } const response = await client.chat.completions.create({ model: CONFIG.model, messages: messages, max_tokens: options.maxTokens || CONFIG.maxTokens, ...options, }); ``` ```javascript async function chat(text) { console.log("Sending reques ...[truncated 2884 chars]
Remediation
## Remediation Suggestions 1. Replace the proxy with the official, documented service endpoint and verify the intended model identifier. 2. Remove the API key and endpoint from source code. Load them from environment variables or a protected secrets manager. 3. Permit only explicitly approved HTTPS endpoints, preferably through a fixed allowlist. Reject malformed or unexpected endpoint overrides. 4. Display the exact destination host and request explicit user confirmation before uploading any local file. 5. Document which fields are transmitted, who operates the destination service, and the applicable retention, deletion, and privacy policies. 6. Use a narrowly scoped, revocable credential dedicated to this service. Never reuse credentials accepted by higher-value services. 7. Validate input files by permitted type and maximum size before reading or transmitting them. 8. Apply request timeouts and response-size limits, and validate returned image data before writing it to disk. 9. Rotate any real credentials previously used with this third-party endpoint if the operator's trustworthiness cannot be established.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (6)

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill explicitly routes user prompts and potentially user-supplied images to a remote third-party API endpoint, but the skill description does not warn users about that data transfer. This creates a privacy and consent risk because users may provide sensitive text or images without realizing they will leave the local environment and be processed by an external service.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
When --image is used, the script reads a local file, converts it to base64, and sends it to a third-party API endpoint without any explicit consent notice, privacy warning, or trust boundary disclosure. This can cause unintentional exfiltration of sensitive local images, especially because the configured endpoint is a non-official custom domain rather than a well-known provider endpoint.

Natural-Language Policy Violations

Low
Confidence
88% confidence
Finding
The activation description is primarily defined using Chinese trigger phrases such as "生图", "生成图片", and "AI画图", which imposes a language-specific invocation model. The file does not indicate that users may choose another language or that the locale restriction is intentional and justified.

Natural-Language Policy Violations

Low
Confidence
80% confidence
Finding
The script's user-facing documentation and CLI messages are written exclusively in Chinese, which can amount to a language policy issue when no language or locale choice is offered. There is no indication that the tool is region-specific or that users can opt into Chinese versus another language.

Description-Behavior Mismatch

Low
Confidence
88% confidence
Finding
The manifest describes the skill as an image-generation/editing tool triggered for image-related intents, with multimodal dialogue as part of that workflow. The separate `chat` function enables general text-only conversation with the model, which goes beyond the image-focused behavior implied by the description.

Intent-Code Divergence

Low
Confidence
81% confidence
Finding
The help text says `node nanobanana.js "提示词" --text "问题"` is for pure text chat, but argument parsing sets `prompt` to the `--text` value and may also accept a positional prompt, making the documented role of the first argument contradictory. This is an intent/documentation mismatch because the usage text implies one behavior while the code actually treats `--text` as the real prompt for chat mode.

Static analysis

No suspicious patterns detected.