Back to skill

Security audit

IMA Nano Banana Image Generator

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly consistent with its image-generation purpose, but failures can persist prompts, image URLs, and local file paths in local logs, so it needs user review before installation.

Install only if you are comfortable sending prompts, image URLs, local image uploads, and your IMA API key to the documented IMA services. Avoid confidential prompts or private image paths unless logs are acceptable on your machine, and periodically delete ~/.openclaw/logs/ima_skills/ and ~/.openclaw/memory/ima_prefs.json if you do not want retained history.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/ima_image_create.py:747
Finding
Sensitive generation data is persisted in operational logs<![CDATA[ ## Vulnerability Details **File Location**: `scripts/ima_image_create.py:747-753`, `scripts/ima_image_create.py:1368-1381`, `scripts/ima_image_create.py:1438-1445`, and `scripts/ima_image_create.py:266-269` **Vulnerability Type**: Sensitive information exposure through persistent logging **Risk Level**: Medium ### Vulnerable Code ```python if code not in (0, 200): logger.error(f"Task create failed: code={code}, msg={data.get('message')}, " f"attribute_id={attribute_id}, credit={credit}") raise RuntimeError( f"Create task failed — code={code} " f"message={data.get('message')} " f"request={json.dumps(payload, ensure_ascii=False)}" ) ``` The resulting exception is incorporated into persistent retry diagnostics: ```python except Exception as e: error_info = extract_error_info(e) attempt_log.append({ "attempt": attempt, "result": "failed", "params": current_params.copy(), "error": error_info }) logger.error(f"❌ Attempt {attempt} failed: {error_info['type']} - {error_info['message']}") ``` After all attempts fail, the accumulated data is written to the operational log: ```python logger.error( "Attempt log (debug only): %s", json.dumps(attempt_log, ensure_ascii=False), ) ``` Local input paths are also logged without redaction: ```python with open(source, "rb") as f: image_bytes = f.read() content_type = mimetypes.guess_type(source)[0] or "image/jpeg" logger.info(f"Read local file: {source} ({len(image_bytes)} bytes)") ``` The log sink is enabled by default in `scripts/ima_logger.py:61-74`: ```python file_handler = RotatingFileHandler( log_file, maxBytes=max_bytes, backupCount=backup_count, encoding='utf-8' ) file_handler.setLevel(log_level) file_handler.setFormatter(formatter) logger.addHandler(file_handler) ``` ### Technical Analysis The task-creation payload contains the complete user prompt and all input-image URLs ...[truncated 2746 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the serialized request payload from exceptions: ```python raise RuntimeError( f"Create task failed — code={code}, " f"message={sanitize_error_message(data.get('message'))}" ) ``` 2. Log only the minimum diagnostic fields required for troubleshooting, such as: - Error code. - Task type. - Model ID. - Attribute ID. - Correlation or task identifier. - Retry count. 3. Never persist raw prompts, local paths, complete media URLs, URL query strings, or request bodies. Introduce centralized redaction before any value reaches the logger: ```python from urllib.parse import urlsplit, urlunsplit def redact_url(value: str) -> str: parts = urlsplit(value) return urlunsplit((parts.scheme, parts.netloc, parts.path, "", "")) def redact_path(value: str) -> str: return os.path.basename(value) ``` 4. Ensure `extract_error_info()` and retry diagnostics retain structured, sanitized error fields rather than the original exception string. 5. Remove `error_info["message"]` from `attempt_log`, or replace it with a bounded and redacted error category. 6. Make verbose diagnostic logging opt-in rather than enabled by default. Keep production logs at a minimal level. 7. Create the log directory and files with restrictive permissions, such as directory mode `0700` and file mode `0600`, and verify permissions after handler creation. 8. Reduce retention where practical and provide a documented mechanism to disable file logging or immediately delete logs containing user content. 9. Add automated tests asserting that representative secrets, prompts, query parameters, local paths, and image URLs never appear in log output during failed requests and exhausted retries. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (17)

Tainted flow: 'task_id' from os.getenv (line 1675, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
"Check the IMA dashboard for status."
            )

        resp = requests.post(url, json={"task_id": task_id},
                             headers=headers, timeout=30)
        resp.raise_for_status()
        data = resp.json()
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The skill description understates important behaviors: sending data to a second domain, persisting user state, and using additional authentication/signing flows. That creates a transparency and consent problem, and could cause users or reviewers to approve a skill without understanding where credentials and local images are sent or what state is retained.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The skill description understates important behaviors: sending data to a second domain, persisting user state, and using additional authentication/signing flows. That creates a transparency and consent problem, and could cause users or reviewers to approve a skill without understanding where credentials and local images are sent or what state is retained.

Credential Access

High
Category
Privilege Escalation
Content
args   = build_parser().parse_args()
    base   = DEFAULT_BASE_URL
    
    # Get API key from args or environment variable
    apikey = args.api_key or os.getenv("IMA_API_KEY")
    if not apikey:
        logger.error("API key is required. Use --api-key or set IMA_API_KEY environment variable")
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 declares sensitive capabilities via metadata and behavior (environment credential use, local file writes, and outbound network access) but does not define an explicit tool/permission scope. That weakens sandboxing and reviewability, making it easier for an agent runtime to grant broader access than users expect.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The mandatory Step 1-4 notification templates are written only in Chinese, while the document instructs the agent to use this messaging flow authoritatively. Although Step 0 mentions replying in the user's language, the required later steps do not provide an opt-in or explicit alternative, which can violate language/locale policy by forcing a specific language.

External Transmission

Medium
Category
Data Exfiltration
Content
f"credit={credit}, attribute_id={attribute_id}")

    try:
        resp = requests.post(url, json=payload, headers=headers, timeout=30)
        resp.raise_for_status()
        data = resp.json()
Confidence
80% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
f"credit={credit}, attribute_id={attribute_id}")

    try:
        resp = requests.post(url, json=payload, headers=headers, timeout=30)
        resp.raise_for_status()
        data = resp.json()
Confidence
80% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
87% confidence
Finding
The script writes per-user preference data to local disk without any user-facing disclosure or consent in this file. While the data is not highly sensitive, undisclosed persistence can create privacy risk, especially on shared systems or multi-user agent environments where local state may be accessible to others.

Description-Behavior Mismatch

Medium
Confidence
84% confidence
Finding
The manifest describes a narrowly scoped image-generation skill, but this module creates a dedicated directory in ~/.openclaw and persists logs there. Local file creation and retention are not mentioned in the manifest description, so the implemented behavior exceeds the stated scope at the description level.

Description-Behavior Mismatch

Medium
Confidence
86% confidence
Finding
The manifest presents the skill as a Nano Banana image generator, but this code also removes files from the user's home-directory log store based on age. File deletion is a side effect beyond straightforward image generation and is not disclosed by the manifest description.

Natural-Language Policy Violations

Low
Confidence
92% confidence
Finding
The manifest description contains both Chinese and English text, which implies a language presentation choice but does not indicate whether users can select their preferred language. Under the policy criteria, forcing or assuming a language/locale without opt-in can be a natural-language policy issue.

Unpinned Dependencies

Low
Category
Supply Chain
Content
# Python dependencies for ai-nano-banana-ima (Nano Banana image generation)
# Install with: pip install -r requirements.txt

requests>=2.25.0
Confidence
96% confidence
Finding
The dependency is specified as `requests>=2.25.0`, which allows any future version and does not guarantee a reproducible or reviewed install. This creates supply-chain risk and makes it possible to unintentionally install a vulnerable or incompatible release, especially in automation or fresh environments.

Unverifiable Dependency: requests has 16 known advisory(ies) (CVE-2014-1830 (Exposure of Sensitive Information to an Unauthorized Actor in Requests); CVE-2024-47081 (Requests vulnerable to .netrc credentials leak via malicious URLs); CVE-2024-35195 (Requests `Session` object does not verify requests after making first request wi) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
91% confidence
Finding
`requests` has multiple known advisories, and because the manifest does not pin a specific version, there is no way to verify whether installed environments will receive a fixed or vulnerable release. In a skill that interacts with external APIs using an API key, uncertainty around HTTP client security increases the risk of credential leakage or unsafe request handling if an affected version is resolved.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
The header builder defaults `language` to `"en"` and always sends `x_app_language` with that value. This imposes a specific language/locale unless the caller explicitly overrides it, which is a natural-language policy concern because there is no opt-in before choosing English as the default.

Description-Behavior Mismatch

Low
Confidence
90% confidence
Finding
The manifest describes an image generation skill focused on IMA Open API operations, but this file also implements a user preference memory subsystem that reads and writes ~/.openclaw/memory/ima_prefs.json. Persisting user-specific history is not disclosed in the manifest description and goes beyond the core generation/polling workflow.

Context-Inappropriate Capability

Low
Confidence
82% confidence
Finding
Saving model usage by user ID to a local memory file introduces stateful tracking behavior unrelated to the manifest's stated role of generating images via the IMA API. This is not an obvious requirement for text_to_image or image_to_image execution itself.

Static analysis

No suspicious patterns detected.