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

Content
View full analysis

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
View 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

Content
View full analysis

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
View 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

Content
View full analysis

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
View 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

Content
View full analysis

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
View 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.

Content

No source excerpt is available for this finding.

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.

Content

No source excerpt is available for this finding.

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.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

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.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.