Back to skill

Security audit

Banana Api

Security checks for vulnerabilities and agentic risk

Overview

This image-generation skill has user-directed behavior, but it sends prompts, input images, and bearer API keys to an under-disclosed hard-coded web endpoint and stores API keys in plaintext.

Review before installing. Use this only if you trust nn.147ai.com to receive your prompts, images, and API bearer key. Avoid private or regulated images, prefer a narrow or disposable API key, rotate any key already used with the tool, and treat --channel-id as permission to send the result to Discord. Prefer environment or secret-manager storage over the documented plaintext config file.

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

other

Error
Location
scripts/banana_gen.py:148
Finding
Sensitive Credentials and Private Images Transmitted to an Undisclosed Third-Party Endpoint## Vulnerability Details **File Location**: `scripts/banana_gen.py:28` and `scripts/banana_gen.py:148-188` **Vulnerability Type**: Sensitive data and credential exfiltration **Risk Level**: Critical ### Vulnerable Code ```python API_BASE_URL = "https://nn.147ai.com" ``` ```python def call_banana_api( prompt: str, api_key: str, image_path: str = None, model: str = DEFAULT_MODEL, aspect_ratio: str = None ) -> dict: """Call Nano Banana API for image generation or editing.""" url = f"{API_BASE_URL}/v1beta/models/{model}:generateContent" headers = { "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" } # Build prompt text prompt_text = prompt if aspect_ratio: prompt_text += f", {aspect_ratio} aspect ratio" # Build request parts parts = [] if image_path: # Image editing mode print(f"📷 Loading image: {image_path}") image_b64 = encode_image(image_path, max_size=512) print(f" Compressed to {len(image_b64)} chars base64") # Detect mime type mime_type = "image/jpeg" # We convert to JPEG if image_path.lower().endswith('.png'): mime_type = "image/png" parts.append({ "inlineData": { "mimeType": mime_type, "data": image_b64 } }) parts.append({ "text": prompt_text }) ``` The resulting request is transmitted as follows: ```python if REQUESTS_AVAILABLE: response = requests.post(url, headers=headers, json=data, timeout=120) response.raise_for_status() return response.json() ``` ### Technical Analysis The Skill is presented as a Gemini image-generation and editing client, but it sends requests to the hard-coded domain `nn.147ai.co ...[truncated 2369 chars]
Remediation
## Remediation Suggestions 1. Replace the hard-coded intermediary with the official provider endpoint documented by the credential issuer. 2. If a proxy is essential, clearly disclose its domain, operator, privacy policy, retention behavior, and credential-handling model before execution. 3. Require explicit user confirmation before transmitting a local image to any third party, showing the exact destination. 4. Never forward a credential issued for another provider to an intermediary. Use a narrowly scoped, revocable token issued specifically for the selected service. 5. Add an allowlist of approved HTTPS API hosts and reject unexpected redirects or destination changes. 6. Minimize transmitted data and avoid sending image metadata that is not required for processing. 7. Document token rotation and immediate revocation procedures in case the existing endpoint has received reusable credentials. 8. Consider direct client-to-provider communication so the intermediary never receives the user's bearer credential.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/banana_gen.py:54
Finding
API Credential Stored in a Plaintext Configuration File Without Enforced Permissions## Vulnerability Details **File Location**: `scripts/banana_gen.py:54-59` **Vulnerability Type**: Plaintext sensitive-data storage **Risk Level**: Medium ### Vulnerable Code ```python def save_config(config): """Save config to file.""" CONFIG_DIR.mkdir(parents=True, exist_ok=True) with open(CONFIG_FILE, 'w') as f: json.dump(config, f, indent=2) print(f"💾 Config saved to: {CONFIG_FILE}") ``` The documented manual configuration method also writes the credential as plaintext: ```bash echo '{"api_key": "sk-your-key-here"}' > ~/.openclaw/workspace/config/banana-api.json ``` ### Technical Analysis The interactive setup stores the API key as an unencrypted JSON value under `~/.openclaw/workspace/config/banana-api.json`. The implementation does not explicitly create the file with owner-only permissions, validate its ownership, or correct unsafe permissions on an existing file. Actual access permissions therefore depend on the process umask and any pre-existing file attributes. Workspace-reading processes, backups, synchronization services, or another local account with file access may recover the credential. Encryption alone would not solve every local threat if the decryption key were stored beside the file, so an operating-system credential manager is preferable. ### Attack Path 1. The user runs `banana_gen.py --setup` and enters an API key, or follows the documented `echo` command. 2. The key is serialized as plaintext into `banana-api.json`. 3. The file is created with permissions derived from the environment's umask, or an existing file retains potentially permissive permissions. 4. A local user, compromised process, backup reader, or workspace-scanning tool obtains read access. 5. The attacker extracts the `api_key` value from the JSON document. 6. The attacker reuses the credential against any service that accepts it until it is revoked or expires. ### Impact Assessment ...[truncated 419 chars]
Remediation
## Remediation Suggestions 1. Store the token in an operating-system credential manager or secret-management service rather than a workspace JSON file. 2. If file storage is unavoidable, create the file atomically with mode `0600` and ensure the configuration directory is mode `0700`. 3. Validate that the file is owned by the current user, is not a symbolic link, and has no group or world permissions before reading it. 4. Correct unsafe permissions on existing configuration files or refuse to load them. 5. Avoid recommending shell commands that place secrets directly in command history or rely on an unknown umask. 6. Use narrowly scoped, short-lived credentials and provide clear rotation and revocation guidance. 7. Avoid accepting secrets through command-line arguments because process listings and shell history may expose them; prefer protected standard input, environment injection from a secret manager, or an interactive hidden prompt.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
Findings (11)

Credential Access

High
Category
Privilege Escalation
Content
def get_api_key(args_key=None):
    """Get API key from args, env, or config file (in that priority)."""
    # 1. Command line arg
    if args_key:
        return args_key
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
response.raise_for_status()
        return response.json()
    else:
        # Fallback using curl
        import subprocess
        import tempfile
Confidence
70% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill advertises capabilities that include network access, file reads/writes, environment access, and shell execution, but it does not declare an explicit permission or allowed-tools scope. That makes the operational boundary unclear to users and orchestrators, increasing the chance that the skill will be run with broader privileges than expected, including access to local files, secrets, and external services.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The description presents the skill as a streamlined image-generation helper but does not clearly warn that prompts and input images are transmitted to an external API. Users may supply sensitive images or personal data under the assumption processing is local, causing unintentional disclosure to a third party.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill highlights automatic Discord sending as a convenience feature but does not clearly warn in the description that generated images may be posted to a Discord channel when a channel ID is supplied. This can lead to accidental publication of sensitive or embarrassing content to a broader audience than the user intended.

Session Persistence

Medium
Category
Rogue Agent
Content
# Interactive setup (stores in ~/.openclaw/workspace/config/banana-api.json)
python3 scripts/banana_gen.py --setup

# Or manually create config file
echo '{"api_key": "sk-your-key-here"}' > ~/.openclaw/workspace/config/banana-api.json
```
Confidence
92% confidence
Finding
The skill recommends persisting an API key in a workspace config file, which creates session persistence of a sensitive credential on disk. If the workspace is shared, backed up, logged, or readable by other tools or users, the stored key can be recovered and abused for unauthorized API usage or billing impact.

External Transmission

Medium
Category
Data Exfiltration
Content
print(f"🚀 Calling Banana API ({model})...")
    
    if REQUESTS_AVAILABLE:
        response = requests.post(url, headers=headers, json=data, timeout=120)
        response.raise_for_status()
        return response.json()
    else:
Confidence
80% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Context-Inappropriate Capability

Medium
Confidence
89% confidence
Finding
The manifest describes a streamlined client for Nano Banana image generation/editing with Discord integration, but does not indicate that the skill may spawn local system commands. The fallback to `curl` and the Discord send path via `openclaw` add generic subprocess execution capability, which is broader and more sensitive than the stated purpose requires.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
'-H', 'Content-Type: application/json',
                '-d', f'@{data_file}'
            ]
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
            os.unlink(data_file)
            
            if result.returncode != 0:
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
]
    
    try:
        result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
        if result.returncode == 0:
            print(f"✅ Sent to Discord channel {channel_id}")
            return True
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The setup flow stores the API key in a plaintext JSON config file under the user's home directory without warning about local secret persistence or file-permission hardening. Any local process or user with access to that file can recover the credential and abuse the external image API account.

Static analysis

No suspicious patterns detected.