Back to skill

Security audit

Nano Banana Image T8

Security checks for vulnerabilities and agentic risk

Overview

This image tool does what it advertises, but it needs Review because its API-key handling could expose credentials or user images beyond the intended service.

Install only if you trust this publisher and are comfortable with a reusable API key being saved in ~/.whaleclaw/credentials. Use a limited or throwaway API key, avoid passing it via --api-key, do not use a custom --base-url, and consider waiting for a version that removes or validates endpoint overrides, separates authenticated API calls from image downloads, and offers explicit key-save/delete controls.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/test_nano_banana_2.py:84
Finding
Bearer Credential Can Be Disclosed to Response-Controlled Image Hosts## Vulnerability Details **File Location**: `scripts/test_nano_banana_2.py`, lines 84-91 and 358 **Vulnerability Type**: Credential disclosure through authenticated cross-origin requests **Risk Level**: High ### Vulnerable Code ```python def _extract_image_bytes(item: dict[str, Any], client: httpx.Client) -> bytes: if "b64_json" in item and isinstance(item["b64_json"], str): return base64.b64decode(item["b64_json"]) url_value = item.get("url") if isinstance(url_value, str) and url_value: resp = client.get(url_value, timeout=60) resp.raise_for_status() return resp.content ``` The client passed to this function is constructed with the API key as a default header and automatically follows redirects: ```python with httpx.Client(headers=_build_headers(api_key), follow_redirects=True) as client: ``` ### Technical Analysis The same `httpx.Client` is used both for authenticated API requests and for downloading image URLs supplied in the API response. `_build_headers()` installs the API key as the client's default `Authorization: Bearer` header. Because `_extract_image_bytes()` accepts an arbitrary URL from `data[0].url`, the authenticated client may send the bearer credential to a host selected by the API response. Automatic redirect following further increases the exposure surface because an initially trusted image URL may redirect to another origin. Image retrieval does not require the API authorization header and should be isolated from authenticated API traffic. Reusing the client therefore violates least-privilege networking principles. ### Attack Path 1. The user invokes text-to-image or image-to-image generation with a valid API key. 2. The configured API endpoint, a compromised upstream service, or an attacker-controlled endpoint returns a successful JSON response containing an external URL in `data[0].url`. 3. `_extract_image_bytes()` passes that URL to th ...[truncated 857 chars]
Remediation
## Remediation Suggestions - Use one authenticated client exclusively for API calls and a separate client without default authorization headers for image downloads. - Do not copy the API key or any sensitive headers into download requests. - Require image download URLs to use HTTPS. - Validate the parsed hostname and port against an explicit allowlist of trusted image-delivery domains. - Disable redirects for image downloads or validate every redirect destination before following it. - Reject URLs containing user information, unusual ports, loopback addresses, link-local addresses, private network ranges, or non-HTTP schemes. - Prefer base64 image responses where supported so no secondary network request is required. - Add tests confirming that `Authorization` is absent from image-download requests and cross-origin redirects are rejected.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/test_nano_banana_2.py:203
Finding
Reusable API Key Is Persisted in a Plaintext File## Vulnerability Details **File Location**: `scripts/test_nano_banana_2.py`, lines 203-212; `SKILL.md`, lines 26 and 63-65 **Vulnerability Type**: Persistent plaintext credential storage **Risk Level**: Medium ### Vulnerable Code ```python def _load_saved_api_key() -> str: if not _KEY_FILE.exists(): return "" return _KEY_FILE.read_text(encoding="utf-8").strip() def _save_api_key(api_key: str) -> None: _KEY_FILE.parent.mkdir(parents=True, exist_ok=True) _KEY_FILE.write_text(api_key.strip(), encoding="utf-8") os.chmod(_KEY_FILE, 0o600) ``` The Skill metadata and instructions designate the following persistent credential path: ```text ~/.whaleclaw/credentials/nano_banana_api_key.txt ``` ### Technical Analysis The API key is written as unencrypted text and retained across sessions. File mode `0600` limits access by other operating-system users, but it does not protect the secret from processes running under the same user identity, endpoint malware, accidental backups, home-directory synchronization, or unauthorized access after account compromise. Persistent retention is not strictly necessary for the declared image-generation functionality. The API request can be completed using a key supplied transiently through protected environment injection or a secret manager. Persistence expands the credential's exposure duration beyond the active Skill invocation. There is also a behavioral distinction in the implementation: `_save_api_key()` is called for a newly entered interactive key, while Skill metadata may separately cause the hosting framework to save supplied parameters. Both mechanisms should follow the same explicit-consent and secure-storage policy. ### Attack Path 1. A user supplies an API key and the Skill or its parameter framework stores it in the designated file. 2. The plaintext credential remains in the user's home directory after image generation completes. 3. A la ...[truncated 726 chars]
Remediation
## Remediation Suggestions - Make credential persistence optional and require explicit, informed user consent. - Default to transient credential use for each invocation. - Store persistent secrets in an operating-system keychain or dedicated secret manager rather than a plaintext file. - Provide commands to inspect whether a key is saved, delete it, and replace or rotate it. - Ensure the credential directory itself has restrictive permissions before creating the file. - If file storage cannot be avoided, create the file atomically with restrictive permissions from the outset rather than applying `chmod` only after writing. - Document the retention period and ensure uninstall or reset operations remove retained credentials. - Keep logs, errors, and status output limited to key presence and source; never print the key value.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/test_nano_banana_2.py:299
Finding
API Key Can Be Passed Through Process Command-Line Arguments## Vulnerability Details **File Location**: `scripts/test_nano_banana_2.py`, line 299; `SKILL.md`, lines 100-106 **Vulnerability Type**: Secret exposure through process arguments **Risk Level**: Medium ### Vulnerable Code ```python parser.add_argument("--api-key", default=os.getenv("NANO_BANANA_API_KEY", "")) ``` The documented WebChat invocation places the supplied key directly in the `--api-key` argument. ### Technical Analysis Command-line arguments are not an appropriate secret transport mechanism. Depending on the host platform and execution environment, process arguments may be observable through process inspection interfaces, monitoring agents, audit telemetry, command-execution logs, crash reports, shell history, or orchestration metadata. Although the script does not print the key itself, accepting and recommending `--api-key` causes the secret to exist in the process argument vector before Python processes it. This exposure occurs outside the protection offered by `getpass` and cannot be corrected after argument parsing. ### Attack Path 1. The agent constructs the documented command with the user's API key in `--api-key`. 2. The operating system or agent runtime launches the Python process with the key embedded in its argument vector. 3. A local monitoring component, execution logger, shell-history mechanism, or process with sufficient inspection access records the command. 4. An attacker later reads the recorded argument vector and recovers the API key. 5. The attacker reuses the credential against the remote API. ### Impact Assessment Exposure grants possession of the reusable API credential and therefore any remote-service permissions assigned to it. Potential consequences include unauthorized generation requests, quota depletion, billing abuse, and account-level privacy impact. The finding does not directly provide elevated operating-system privileges. The accessible scope depends on local process- ...[truncated 90 chars]
Remediation
## Remediation Suggestions - Remove the documented recommendation to place the API key in `--api-key`. - Prefer protected secret injection from the execution environment or a dedicated secret manager. - For manual interactive use, read the key from standard input with hidden input rather than from argv. - If environment variables are used, ensure the agent runtime does not log the full environment and only exposes the variable to the child process that requires it. - Consider accepting a secret reference or keychain identifier rather than the secret value itself. - Redact secret-bearing arguments in process telemetry and execution logs during migration. - Retain `--api-key` only if backward compatibility requires it, mark it insecure and deprecated, and remove it in a planned release.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/test_nano_banana_2.py:303
Finding
Caller-Controlled Base URL Can Redirect Credentials and User Content to an Arbitrary Server## Vulnerability Details **File Location**: `scripts/test_nano_banana_2.py`, line 303 and lines 126-176 **Vulnerability Type**: Unrestricted authenticated endpoint override **Risk Level**: High ### Vulnerable Code ```python parser.add_argument("--base-url", default="https://ai.t8star.cn") ``` The value is used directly to construct authenticated request destinations: ```python resp = client.post(f"{base_url}/v1/images/generations", json=payload, timeout=300) ``` ```python resp = client.post( f"{base_url}/v1/images/edits", data=form_data, files=files, timeout=300, ) ``` ### Technical Analysis `SKILL.md` states that the API base address is fixed to `https://ai.t8star.cn`, but the implementation accepts an unrestricted `--base-url` value and does not validate its scheme, hostname, port, or destination address. The HTTP client carries the user's bearer credential as a default header. As a result, supplying a different base URL sends the API key to that destination. Text prompts are included in generation requests, while image-editing requests additionally upload user-selected image files. This contradicts the documented trust boundary and creates a direct credential and data-exfiltration primitive if an invocation can be manipulated. ### Attack Path 1. An attacker influences an agent-generated command, copied invocation, wrapper script, or user input so that `--base-url` points to an attacker-controlled HTTPS server. 2. The script accepts the value without validation. 3. The authenticated `httpx.Client` sends `Authorization: Bearer` with the request to the malicious server. 4. For text generation, the server receives the API key and prompt. 5. For image editing, the server also receives all supplied image files and associated metadata. 6. The attacker records the credential and private content, then optionally returns a plausible API response to conceal the exfiltration. ### Im ...[truncated 497 chars]
Remediation
## Remediation Suggestions - Remove the `--base-url` option if endpoint customization is not a required feature. - Otherwise, parse the URL and enforce an exact allowlist containing only `https://ai.t8star.cn`. - Reject non-HTTPS schemes, embedded user information, unexpected ports, fragments, and ambiguous host representations. - Resolve and reject loopback, link-local, private, multicast, and other non-public destination ranges. - Ensure redirects cannot move authenticated requests to a different origin. - Construct endpoint URLs from a trusted constant rather than concatenating an untrusted string. - Add tests showing that alternate domains, subdomain lookalikes, IP literals, scheme changes, and unexpected ports are rejected. - Keep authenticated API traffic and unauthenticated image retrieval in separate clients with separate redirect policies.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • 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 (9)

Tp2

High
Category
MCP Tool Poisoning
Confidence
85% confidence
Finding
Mixing characters from multiple Unicode scripts in a single identifier is a common technique to create visually ambiguous tool names.

Tp2

High
Category
MCP Tool Poisoning
Confidence
85% confidence
Finding
Mixing characters from multiple Unicode scripts in a single identifier is a common technique to create visually ambiguous tool names.

Tp2

High
Category
MCP Tool Poisoning
Confidence
85% confidence
Finding
Mixing characters from multiple Unicode scripts in a single identifier is a common technique to create visually ambiguous tool names.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill invokes bash and reads/writes credential files and also makes networked API calls, but it declares no explicit tool scope or permissions boundary. That increases the blast radius if the skill is triggered unexpectedly or later modified, because the runtime has more capability than the manifest transparently communicates.

Vague Triggers

Medium
Confidence
92% confidence
Finding
Broad test-oriented triggers such as 'image generation test' and 'image edit test' can activate the skill in unrelated conversations, especially because the skill can handle API keys and execute shell-backed workflows. Unintended activation increases the chance of credential capture prompts, script execution, or confusing cross-task behavior.

Natural-Language Policy Violations

Medium
Confidence
86% confidence
Finding
The parameter prompts and most operational instructions are written only in Chinese, and the skill presentation appears to assume Chinese-language interaction without stating that users may choose another language. This can violate language or locale policy when a skill effectively forces a specific language without opt-in.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill persists API keys to a local file and reuses them later, but the user-facing flow does not clearly require informed consent at the moment of storage or reuse. This creates a credential-handling risk: users may not realize secrets are being written to disk and retained across sessions.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The script's natural-language interface, errors, and prompts are written in Chinese throughout, which imposes a specific language on users without opt-in. Under the stated policy, a fixed locale is a violation unless the skill offers a language choice or clearly documents a justified region-specific constraint.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The script persists the API key to a predictable plaintext file under the user's home directory and does so automatically after interactive entry. Although the file mode is restricted to 0600, local plaintext secret storage still increases exposure to compromise from local malware, backups, misconfigured home-directory sharing, or accidental disclosure, and the UX does not clearly obtain informed consent before saving.

Static analysis

No suspicious patterns detected.