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

Content
View full analysis

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

Content
View full analysis

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
View 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
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/banana_gen.py (reported line 69)May include surrounding context.

python
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

Tool Parameter Abuse

High
Category
Tool Misuse
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).

Content

Scanner excerpt · scripts/banana_gen.py (reported line 208)May include surrounding context.

python
response.raise_for_status()
        return response.json()
    else:
        # Fallback using curl
        import subprocess
        import tempfile

Undeclared Tool Scope

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.

Content

No source excerpt is available for this finding.

Missing User Warnings

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

Content

No source excerpt is available for this finding.

Missing User Warnings

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

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
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.

Content

Scanner excerpt · SKILL.md (reported line 53)May include surrounding context.

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

text

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/banana_gen.py (reported line 204)May include surrounding context.

python
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:

Context-Inappropriate Capability

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

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/banana_gen.py (reported line 223)May include surrounding context.

python
'-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:

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/banana_gen.py (reported line 270)May include surrounding context.

python
]
    
    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

Missing User Warnings

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

Content

No source excerpt is available for this finding.