Back to skill

Security audit

Nano Banana Pro Image Gen(基于API易代理站)

Security checks for vulnerabilities and agentic risk

Overview

This image-generation skill matches its stated purpose, but it gives agents unsafe command templates and can upload arbitrary readable local files to a third-party API.

Review before installing. Use it only for prompts and images you are willing to send to API易/api.apiyi.com and any upstream provider. Do not pass confidential documents, secrets, private keys, or unrelated local paths as input images. Prefer environment-variable API keys over command-line keys, and run the helper with shell-free argument passing or careful escaping.

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)

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:17
Finding

Shell Command Injection Through Direct Prompt Interpolation

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:17-17, SKILL.md:46-57
Vulnerability Type: Shell command injection through unsafe command construction
Risk Level: High

Vulnerable Code

markdown
- **Use the user's complete original input**: Pass the user's complete original request directly as the main body of the `-p` prompt.
bash
node scripts/generate_image.js -p "{prompt}" -f "{filename}" [-a {ratio}] [-r {res}]
node scripts/generate_image.js -p "{edit_instruction}" -i "{input_path}" -f "{output_filename}" [-r {res}]

python scripts/generate_image.py -p "{prompt}" -f "{filename}" [-a {ratio}] [-r {res}]
python scripts/generate_image.py -p "{edit_instruction}" -i "{input_path}" -f "{output_filename}" [-r {res}]

Technical Analysis

The Skill directs the Agent to preserve the user's raw input and interpolate it into a textual shell command enclosed in double quotes. Double quotes do not neutralize every shell metacharacter. If the Agent executes the generated command through a shell, a malicious prompt containing a closing quote, command substitution, or another shell expression can alter the command's syntax.

The underlying Python and Node.js programs parse arguments without invoking a shell and are not independently vulnerable when launched through a safe argument-array API. The vulnerability arises from the Skill-level execution instructions, which encourage construction of a command string from untrusted input without specifying shell-free invocation or robust argument escaping.

Attack Path

  1. An attacker submits an image-generation prompt containing shell syntax.
  2. Following SKILL.md:17, the Agent preserves the attacker's complete input.
  3. The Agent substitutes that input into one of the command templates at SKILL.md:46-57.
  4. If the resulting string is passed to a shell, the shell interprets the injected syntax rather than treating the entire prompt as one litera ...[truncated 750 chars]
Remediation
View remediation

Remediation Suggestions

  • Do not construct a shell command by interpolating the prompt, filename, or input path into a string.

  • Invoke the program through a shell-free argument-array interface, such as Node.js spawn or execFile with shell: false, or Python subprocess.run([...], shell=False).

  • Update SKILL.md to explicitly prohibit shell=True, exec, system, and equivalent shell-string execution.

  • Pass each value as a distinct argument, for example:

    javascript
    spawn('node', [
      'scripts/generate_image.js',
      '--prompt',
      prompt,
      '--filename',
      filename
    ], { shell: false });
    
  • Validate filenames, ratios, resolutions, and input paths independently. Validation must be supplemental; it must not replace shell-free invocation.

  • Add regression tests using prompts containing quotes, semicolons, newlines, dollar signs, backticks, and command-substitution syntax to confirm that they remain literal prompt data.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/generate_image.py:82
Finding

Arbitrary Local File Read and Upload Through Unrestricted Input Image Paths

Content
View full analysis

Vulnerability Details

File Location: scripts/generate_image.py:82-88, scripts/generate_image.py:135-154, scripts/generate_image.py:201-201; equivalent behavior in scripts/generate_image.js:134-139, scripts/generate_image.js:363-376, and scripts/generate_image.js:430-430
Vulnerability Type: Unrestricted local file upload to a third-party service
Risk Level: High

Vulnerable Code

python
def encode_image_to_base64(image_path):
    """Convert an image file to Base64."""
    try:
        with open(image_path, "rb") as f:
            return base64.b64encode(f.read()).decode("utf-8")
    except Exception as e:
        print(f"Error: unable to read image file {image_path} - {e}")
        sys.exit(1)
python
if input_image:
    if isinstance(input_image, (list, tuple)):
        input_images = list(input_image)
    else:
        input_images = [input_image]

    if len(input_images) > 14:
        print(f"Error: at most 14 input images are supported; received {len(input_images)}")
        sys.exit(1)

    for image_path in input_images:
        if not os.path.exists(image_path):
            print(f"Error: input image does not exist: {image_path}")
            sys.exit(1)

        image_base64 = encode_image_to_base64(image_path)
        parts.append({"inlineData": {"mimeType": "image/png", "data": image_base64}})
python
response = requests.post(url, headers=headers, json=payload, timeout=400)

The preferred Node.js implementation has the same data flow:

javascript
function encodeImageToBase64(imagePath) {
  try {
    const bytes = fs.readFileSync(imagePath);
    return bytes.toString('base64');
  } catch (e) {
    exitWithError(`Error: unable to read image file ${imagePath} - ${e.message || String(e)}`);
  }
}
javascript
for (const imgPath of args.inputImages) {
  if (!fs.existsSync(imgPath)) {
    exitWithError(`
...[truncated 2895 chars]
Remediation
View remediation

Remediation Suggestions

  • Resolve every input path to a canonical absolute path and require it to remain within an explicitly configured, user-approved upload directory.
  • Reject path traversal, symbolic links, non-regular files, devices, pipes, sockets, and files outside the permitted root.
  • Verify actual file signatures using a trusted image decoder rather than relying on extensions or caller-provided MIME types.
  • Accept only explicitly supported formats and send the corresponding verified MIME type instead of always using image/png.
  • Enforce conservative per-file and total-request size limits before reading files into memory.
  • Present the canonical path, file size, and destination host to the user and obtain explicit confirmation before transmitting local files.
  • Open files in a manner that resists symbolic-link races where supported, and revalidate metadata after opening.
  • Run the script under a restricted account or sandbox that can read only the intended workspace and cannot access credential or system directories.
  • Document clearly that prompts and selected images are transmitted to a third-party API provider.
  • Apply the same controls to both the Python and Node.js implementations to prevent users from bypassing validation by selecting the alternate runtime.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • 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 (22)

Tainted flow: 'headers' from os.environ.get (line 126, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/generate_image.py (reported line 201)May include surrounding context.

python
print(f"输出请求参数: {json.dumps(payload_log, indent=2, ensure_ascii=False)}")
    print(f"image generation in progress...")
    try:
        response = requests.post(url, headers=headers, json=payload, timeout=400)
        response.raise_for_status()

        data = response.json()

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- **优先尝试 Node.js 版本**:如果环境有 Node(`node` 命令可用),优先使用 `scripts/generate_image.js`(零依赖,参数与 Python 保持一致)。

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- **优先尝试 Node.js 版本**:如果环境有 Node(`node` 命令可用),优先使用 `scripts/generate_image.js`(零依赖,参数与 Python 保持一致)。

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- **优先尝试 Node.js 版本**:如果环境有 Node(`node` 命令可用),优先使用 `scripts/generate_image.js`(零依赖,参数与 Python 保持一致)。

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- **优先尝试 Node.js 版本**:如果环境有 Node(`node` 命令可用),优先使用 `scripts/generate_image.js`(零依赖,参数与 Python 保持一致)。

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- **优先尝试 Node.js 版本**:如果环境有 Node(`node` 命令可用),优先使用 `scripts/generate_image.js`(零依赖,参数与 Python 保持一致)。

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- **优先尝试 Node.js 版本**:如果环境有 Node(`node` 命令可用),优先使用 `scripts/generate_image.js`(零依赖,参数与 Python 保持一致)。

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- **优先尝试 Node.js 版本**:如果环境有 Node(`node` 命令可用),优先使用 `scripts/generate_image.js`(零依赖,参数与 Python 保持一致)。

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill instructs the agent to access environment variables and communicate with an external service, but it does not declare any explicit tool scope or permission boundaries. This creates an authorization and review gap: operators and users cannot clearly see that the skill can read secrets and transmit prompts/images over the network.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
94% confidence
Finding

The skill is explicitly designed to transmit prompts and possibly user-supplied images to an external proxy service. In this context, external transmission is inherently security-relevant because the content may include sensitive personal data, proprietary material, or hidden metadata, and the use of a proxy adds an additional trust boundary.

Content

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

md
---
name: nano-banana-pro-image-gen
description: 图片生成技能,当用户需要生成图片、视觉信息图、创建图像、编辑/修改/调整已有图片时使用此技能。基于中国的API易代理站(https://api.apiyi.com/)的NanoBananaPro模型的图片生成服务,无需访问外网。支持10种宽高比的图片比例(`1:1`、`16:9`、`9:16`、`4:3`、`3:4`、`3:2`、`2:3`、`5:4`、`4:5`、`21:9`等)和3种分辨率(1K、2K、4K),支持文生图和图生图编辑。基于谷歌的NanoBananaPro模型(快速模型),使用API易国内代理服务访问。
---

# 图片生成与编辑

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The trigger description is very broad and can match common user requests about images, editing, or visual content. Over-broad activation increases the chance that sensitive prompts or files are routed to this skill and then sent to a third-party service without sufficiently specific user intent.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill states that it uses a domestic proxy service and external model backend, but it does not prominently warn that user prompts and uploaded images are transmitted to a third party. Because image editing may involve personal, confidential, or regulated data, inadequate disclosure materially increases privacy and compliance risk.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

文档整体以中文直接规定技能说明与交互示例,且没有表明可根据用户偏好切换语言或先征得用户同意。按语言/地区政策要求,若技能默认强制特定语言而不提供选择,可能构成自然语言层面的语言策略违规。

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The script's natural-language interface, help text, status messages, and error messages are entirely in Chinese, which imposes a specific language on all users. There is no indication that the skill is region-specific or that users can select another language, so this appears to violate the language/locale choice policy.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
86% confidence
Finding

The script transmits user prompts, API credentials, and optionally full local image contents to a third-party proxy endpoint (api.apiyi.com). In this skill context, that is expected for image generation, but it still creates a real data-exposure and trust-boundary risk because sensitive prompts or images may leave the local environment and be handled by an intermediary service rather than the model provider directly.

Content

Scanner excerpt · scripts/generate_image.js (reported line 336)May include surrounding context.

js
const apiKey = getApiKey(args.apiKey);
  const url =
    'https://api.apiyi.com/v1beta/models/gemini-3-pro-image-preview:generateContent';

  const headers = {
    Authorization: `Bearer ${apiKey}`,

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script uploads user prompts and optional local images to an external proxy API, but it does not prominently warn users at execution time that their content leaves the local environment. In a skill context handling potentially sensitive images or text, this can cause unintended disclosure of private or regulated data to a third party.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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/generate_image.py (reported line 123)May include surrounding context.

python
api_key = get_api_key(api_key)
    url = (
        "https://api.apiyi.com/v1beta/models/gemini-3-pro-image-preview:generateContent"
    )

    headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}

External Transmission

Medium
Category
Data Exfiltration
Confidence
88% confidence
Finding

This code transmits user-supplied text and base64-encoded image contents to an external service. In an image-generation skill this is expected functionality, but it is still security-relevant because sensitive local files selected as input may be exfiltrated to a third-party proxy service without strong consent or minimization controls.

Content

Scanner excerpt · scripts/generate_image.py (reported line 201)May include surrounding context.

python
print(f"输出请求参数: {json.dumps(payload_log, indent=2, ensure_ascii=False)}")
    print(f"image generation in progress...")
    try:
        response = requests.post(url, headers=headers, json=payload, timeout=400)
        response.raise_for_status()

        data = response.json()

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

L034-L035 明确写默认图片分辨率使用 2K,而 L152 又写“不传则不在请求中指定,由 API 侧决定”。这不是单纯信息不全,而是对未传分辨率时实际行为的相互矛盾描述,会误导调用方对技能实际输出的预期。

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The documentation alternates between checking only an environment variable and supporting a command-line API key parameter. Allowing secrets on the command line is security-sensitive because command arguments are often exposed in shell history, process listings, logs, and telemetry, increasing the risk of API key disclosure.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

This markdown file presents all usage guidance exclusively in Chinese, which can constitute a language/locale policy issue when no user opt-in or region-specific justification is provided. The content does not indicate that the skill is intentionally limited to Chinese-speaking users or offer alternative language support.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

Natural-language policy violations apply to all file types, including code comments, docstrings, and help text. Here the script presents its primary instructions exclusively in Chinese, and there is no indication that the tool is region-specific or that users can opt into another language.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.