Back to skill

Security audit

Nano Banana 2 Direct

Security checks for vulnerabilities and agentic risk

Overview

This skill does what it claims: it calls Google's Gemini image API to generate or edit images, with some privacy and operational risks users should understand.

Install only if you are comfortable sending image prompts and any input images to Google's Gemini API. Prefer setting GEMINI_API_KEY outside chat and command-line history, keep output filenames inside the current project or a dedicated image folder, avoid overwriting existing files, and be aware that dependencies are resolved from the package registry at install/run time.

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

T08 · Insecure Dependencies

Warning
Location
SKILL.md:18
Finding
Unpinned Third-Party Dependencies Create a Supply-Chain Risk<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:18`; `scripts/generate_image.py:3-8` **Vulnerability Type**: Unpinned and unverifiable third-party dependencies **Risk Level**: Medium ### Vulnerable Code From `SKILL.md:18`: ```yaml "command": "uv pip install google-genai pillow", ``` From `scripts/generate_image.py:3-8`: ```python # requires-python = ">=3.10" # dependencies = [ # "google-genai>=1.0.0", # "pillow>=10.0.0", # ] # /// ``` ### Technical Analysis The installation instruction does not specify any versions, while the inline Python dependency metadata only specifies minimum versions. The project also contains no reviewed lockfile or package hashes. Consequently, dependency resolution can select any future release satisfying these constraints. This does not prove that the current packages are malicious. However, it prevents reproducible installation and expands the trust boundary to include future package releases and the availability and integrity of the package registry at installation time. A compromised maintainer account, malicious future release, or registry compromise could introduce code that executes when imported or used by the script. ### Attack Path 1. An attacker compromises a dependency publisher account, package release process, or relevant package-registry infrastructure. 2. The attacker publishes a malicious version of `google-genai` or `pillow` that satisfies the unconstrained or minimum-version dependency declaration. 3. A user installs or runs the skill after that version becomes available. 4. `uv` resolves and installs the malicious release because no exact version, lockfile, or hash prevents selection. 5. Malicious package code executes with the privileges of the user running the skill, either during installation or when imported by `generate_image.py`. ### Impact Assessment Successful exploitation could execute arbitrary code with the privileges of the Agent user. This may expose the `GEMINI_API_K ...[truncated 304 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin every runtime dependency to an audited exact version, for example: ```python # dependencies = [ # "google-genai==<reviewed-version>", # "pillow==<reviewed-version>", # ] ``` 2. Generate and commit a lockfile that records all transitive dependencies. 3. Require package hashes during installation so altered artifacts are rejected. 4. Make the installation command consume the reviewed lockfile rather than resolving the newest available releases. 5. Use automated dependency scanning and update packages only through a reviewed change process. 6. Where supported, use a trusted internal package mirror and provenance or signature verification. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/generate_image.py:52
Finding
Gemini API Key Can Be Exposed Through Command-Line Arguments<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate_image.py:52-62`; documented in `SKILL.md:30-35,64-65` **Vulnerability Type**: Sensitive credential passed through process arguments **Risk Level**: Medium ### Vulnerable Code From `scripts/generate_image.py:52-62`: ```python parser.add_argument( "--api-key", "-k", help="Gemini API key (overrides GEMINI_API_KEY env var)" ) args = parser.parse_args() # Get API key api_key = get_api_key(args.api_key) ``` The documentation explicitly promotes this mechanism: ```markdown [--api-key KEY] ``` ```markdown 1. `--api-key` argument (use if user provided key in chat) 2. `GEMINI_API_KEY` environment variable ``` ### Technical Analysis Command-line arguments are not an appropriate transport for long-lived credentials. Depending on the operating system and execution environment, process arguments may be visible to other local users through process inspection facilities. They may also be captured by shell history, terminal logs, process monitoring, diagnostic tooling, orchestration logs, or Agent execution transcripts. The documentation further recommends using a key provided in chat. That practice can unnecessarily place the credential in conversation records before it is copied into a command line, increasing the number of locations in which the secret may persist. The script does not print the key directly, but accepting and recommending `--api-key` creates an avoidable disclosure channel. ### Attack Path 1. A user or Agent invokes the script with `--api-key <secret>`. 2. The complete command is retained in shell history, an Agent transcript, execution logs, or process-monitoring telemetry, or is exposed through process inspection while the process is running. 3. A local user, log reader, support operator, or other principal with access to one of those sources retrieves the credential. 4. The exposed key is used to call Gemini APIs under the victim's acco ...[truncated 460 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the `--api-key` and `-k` command-line options. 2. Retrieve the credential from a protected secret manager or credential store. If environment variables must be supported, configure them outside command history and restrict access to the process environment. 3. For interactive use, accept the secret through hidden terminal input using `getpass`, while preferring a credential store for automation. 4. Revise `SKILL.md` so users are explicitly instructed not to paste API keys into chat or command-line arguments. 5. Restrict the Gemini key by API, project, quota, and any supported source controls; use a dedicated key for this skill. 6. Ensure execution logs and Agent transcripts redact credential-like values. 7. Rotate any API key previously supplied through chat or a command line if those records may be accessible to unauthorized parties. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/generate_image.py:75
Finding
Caller-Controlled Output Path Allows Arbitrary File Overwrite Within User Privileges<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate_image.py:75-77,137-143` **Vulnerability Type**: Unrestricted file path and unsafe overwrite **Risk Level**: Medium ### Vulnerable Code Path creation from `scripts/generate_image.py:75-77`: ```python # Set up output path output_path = Path(args.filename) output_path.parent.mkdir(parents=True, exist_ok=True) ``` Unconditional writes from `scripts/generate_image.py:137-143`: ```python if image.mode == 'RGBA': rgb_image = PILImage.new('RGB', image.size, (255, 255, 255)) rgb_image.paste(image, mask=image.split()[3]) rgb_image.save(str(output_path), 'PNG') elif image.mode == 'RGB': image.save(str(output_path), 'PNG') else: image.convert('RGB').save(str(output_path), 'PNG') ``` ### Technical Analysis The `--filename` value is converted directly into a `Path` without validating whether it is absolute, contains traversal components, resolves through a symbolic link, or remains inside an approved output directory. The script creates missing parent directories and saves with normal overwrite behavior, without checking whether the destination already exists. As a result, any party able to influence the filename passed by the Agent can cause PNG data to be written to any destination writable by the process. Relative traversal such as `../../target`, an absolute path, or a path involving a symbolic link can escape the intended current working directory. Although the written content is constrained to a generated PNG rather than arbitrary attacker-selected bytes, replacing configuration, source, document, or application files can still cause corruption or denial of service. The documentation's instruction to save in the user's current working directory is not enforced by the implementation. ### Attack Path 1. An attacker supplies an image ...[truncated 1260 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Define a trusted output root, such as the current workspace or a dedicated generated-images directory. 2. Resolve both the output root and candidate destination to canonical paths and verify that the destination remains within the trusted root: ```python output_root = Path.cwd().resolve() output_path = (output_root / args.filename).resolve() if output_path != output_root and output_root not in output_path.parents: parser.error("Output path must remain inside the current workspace") ``` 3. Reject absolute filenames and path components such as `..` before resolving the destination. 4. Permit only expected image extensions and normalize the final extension to `.png`. 5. Refuse to overwrite an existing destination by default. Require a separate explicit `--overwrite` option or generate a collision-resistant filename. 6. Defend against symbolic-link races by opening the output atomically with no-follow and exclusive-create semantics where supported, then writing through the validated file descriptor. 7. Avoid automatically creating arbitrary parent directory trees; limit directory creation to validated descendants of the approved output root. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Memory PoisoningPersistent Context Injection, Context Window Stuffing, Memory Manipulation
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (6)

Memory Manipulation

High
Category
Memory Poisoning
Content
- Prompt "A serene Japanese garden" → `2025-11-23-14-23-05-japanese-garden.png`
- Prompt "sunset over mountains" → `2025-11-23-15-30-12-sunset-mountains.png`
- Prompt "create an image of a robot" → `2025-11-23-16-45-33-robot.png`
- Unclear context → `2025-11-23-17-12-48-x9k2.png`

## Image Editing
Confidence
80% confidence
Finding
Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.

Credential Access

High
Category
Privilege Escalation
Content
def get_api_key(provided_key: str | None) -> str | None:
    """Get API key from argument first, then environment."""
    if provided_key:
        return provided_key
    return os.environ.get("GEMINI_API_KEY")
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill invokes code and depends on environment access (`GEMINI_API_KEY`) but does not declare an explicit tool/permission scope. That weakens least-privilege controls and can cause the skill to run with broader access than reviewers or users expect.

Vague Triggers

Medium
Confidence
80% confidence
Finding
The name/description are broad enough to match generic image creation or editing requests, which can cause the skill to be selected in situations where users did not intend an external API call. In this skill, overbroad routing matters because prompts and possibly local images may be transmitted to a third-party service.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill does not clearly warn that user prompts and any `--input-image` content are sent to an external Google API. This creates a real data exfiltration/privacy risk, especially if users provide sensitive images, proprietary artwork, or confidential prompt content without informed consent.

Session Persistence

Medium
Category
Rogue Agent
Content
Examples:
- Prompt "A serene Japanese garden" → `2025-11-23-14-23-05-japanese-garden.png`
- Prompt "sunset over mountains" → `2025-11-23-15-30-12-sunset-mountains.png`
- Prompt "create an image of a robot" → `2025-11-23-16-45-33-robot.png`
- Unclear context → `2025-11-23-17-12-48-x9k2.png`

## Image Editing
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.

Static analysis

No suspicious patterns detected.