Back to skill

Security audit

Nano Banana Cut 图片生成切割,用于短视频创作,解决角色一致性问题和故事叙事

Security checks for vulnerabilities and agentic risk

Overview

This is a real image-generation and cutting tool, but it exposes powerful unauthenticated web APIs that can disclose local files, alter/delete data, save credentials, and stop the service.

Only run this in a tightly controlled local environment, not on a shared or exposed network. Before installing or using it, remove or protect the shutdown/admin/config routes, bind to localhost, add authentication/CSRF protection, restrict all file serving and crop/upload paths to a dedicated workspace, stop logging Authorization headers, and rotate any API keys used with this version if logs or the service were exposed.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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 (6)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
server.py:758
Finding
Arbitrary Local File Disclosure Through Unrestricted Catch-All Route<![CDATA[ ## Vulnerability Details **File Location**: `server.py:758-764` **Vulnerability Type**: Arbitrary local file read **Risk Level**: Critical ### Complete Code Snippet ```python @app.route('/<path:filepath>') def serve_file(filepath): if '..' in filepath or filepath.startswith('/'): return "Invalid path", 403 full_path = os.path.join('/', filepath) if os.path.exists(full_path) and os.path.isfile(full_path): return send_from_directory(os.path.dirname(full_path), os.path.basename(full_path)) return "File not found", 404 ``` ### Technical Analysis The catch-all route treats the URL path as a filesystem path rooted at `/`. The check for `..` does not provide confinement because an attacker does not need directory traversal sequences. For example, the URL path `etc/passwd` is converted into `/etc/passwd`. The route then returns any file for which the Flask process has read permission. It is not restricted to the configured image output directory, project directory, or records associated with a valid work item. On Windows, behavior differs according to drive and path handling, but known paths on the current drive may still be exposed. The application must not rely on the operating system to prevent disclosure. ### Attack Path 1. An attacker connects to the service on port 697. 2. The attacker requests a known local path without a leading slash in the route parameter, such as `/etc/passwd`. 3. The handler constructs `/etc/passwd`. 4. If the service account can read the file, Flask sends it to the attacker. 5. The attacker repeats the process for application files, database files, configuration, credentials, or user documents. ### Impact Assessment A remote, unauthenticated attacker may read any file available to the server account. Potential targets include: - The `.env` file containing `API_KEY` and `PLATFORM_TOKEN` - `data/works.db`, including prompts, task IDs, output paths, and API responses - Source code and config ...[truncated 281 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the catch-all filesystem-serving route. 2. Serve generated images only through a dedicated route that accepts an opaque work ID and validates the corresponding database record. 3. Restrict all served files to `SAVE_BASE_PATH` or another dedicated content directory. 4. Resolve and canonicalize the requested path, then verify it remains inside the approved directory. 5. Use Flask/Werkzeug safe-path facilities such as `safe_join` and reject absolute paths. 6. Require authentication and authorization before returning private generated content. 7. Run the process under a dedicated account with minimal filesystem permissions. 8. Rotate API credentials if the vulnerable service has been exposed to untrusted networks. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
server.py:716
Finding
Unauthenticated Network Exposure of Administrative and Privileged APIs<![CDATA[ ## Vulnerability Details **File Location**: `server.py:28, 346-462, 662-741, 716-721, 794` **Vulnerability Type**: Missing authentication and unrestricted network exposure **Risk Level**: Critical ### Complete Code Snippets ```python app = Flask(__name__, static_folder='static', static_url_path='/static') CORS(app) ``` ```python @app.route('/api/admin/works', methods=['GET']) def admin_get_works(): try: conn = get_db_connection() works = conn.execute('SELECT * FROM works ORDER BY id DESC').fetchall() conn.close() result = [dict(work) for work in works] return jsonify({"success": True, "data": result}) except Exception as e: return jsonify({"success": False, "msg": str(e)}), 500 ``` ```python @app.route('/api/config/save', methods=['POST']) def save_config(): try: data = request.get_json() api_key = data.get('api_key', '').strip() platform_token = data.get('platform_token', '').strip() if not api_key: return jsonify({"success": False, "msg": "API_KEY为必填项,请填写"}), 400 env_path = os.path.join(BASE_DIR, '.env') with open(env_path, 'w', encoding='utf-8') as f: f.write(f"API_KEY={api_key}\n") f.write(f"PLATFORM_TOKEN={platform_token}\n") global API_KEY, PLATFORM_TOKEN API_KEY = api_key PLATFORM_TOKEN = platform_token return jsonify({"success": True, "msg": "配置保存成功,请刷新页面生效"}) except Exception as e: return jsonify({"success": False, "msg": str(e)}), 500 ``` ```python @app.route('/api/shutdown', methods=['POST']) def shutdown(): try: os._exit(0) except Exception as e: return jsonify({"success": False, "msg": str(e)}), 500 ``` ```python app.run(host='0.0.0.0', port=PORT, debug=False) ``` ### Technical Analysis The application listens on all network interfaces and does not implement user authentication, authorization, or CSRF protection. Unrest ...[truncated 1957 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Bind to `127.0.0.1` by default unless remote access is explicitly configured. 2. Require strong authentication for all API endpoints. 3. Implement role-based authorization for configuration, administration, file processing, downloads, and shutdown operations. 4. Remove the shutdown endpoint in production or restrict it to a protected local management channel. 5. Replace unrestricted CORS with an explicit allowlist of trusted origins and methods. 6. Add CSRF protection to state-changing browser requests. 7. Reject requests with unexpected `Origin` or `Host` values. 8. Place remote deployments behind TLS and an authenticated reverse proxy. 9. Avoid returning complete database records where only limited display fields are required. 10. Log administrative actions without logging credentials or sensitive payloads. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
server.py:412
Finding
Arbitrary File Overwrite and Deletion via Uploaded Filename Traversal<![CDATA[ ## Vulnerability Details **File Location**: `server.py:412-436` **Vulnerability Type**: Unsafe temporary-file handling and path traversal **Risk Level**: Critical ### Complete Code Snippet ```python @app.route('/api/upload', methods=['POST']) def upload_file(): try: if not PLATFORM_TOKEN: return jsonify({"success": False, "msg": "未配置PLATFORM_TOKEN,请先配置密钥", "need_config": True}), 401 if 'file' not in request.files: return jsonify({"success": False, "msg": "没有上传文件"}), 400 file = request.files['file'] if file.filename == '': return jsonify({"success": False, "msg": "没有选择文件"}), 400 # 保存临时文件 temp_dir = os.path.join(BASE_DIR, 'temp') os.makedirs(temp_dir, exist_ok=True) temp_path = os.path.join(temp_dir, file.filename) file.save(temp_path) # 调用upload.py上传 from upload import upload_image, init_upload_table init_upload_table() result = upload_image(temp_path) # 删除临时文件 os.remove(temp_path) return jsonify(result) except Exception as e: return jsonify({"success": False, "msg": str(e)}), 500 ``` ### Technical Analysis The multipart filename is controlled by the requester and is concatenated directly with `temp_dir`. No `secure_filename`, canonical-path check, or random server-generated filename is used. A filename containing traversal components such as `../` may escape the temporary directory. Depending on operating-system path semantics, an absolute filename may also override the intended base path. `file.save()` then overwrites the selected destination. After sending the selected file to the external upload service, `os.remove(temp_path)` deletes it. Consequently, the same flaw supports both arbitrary overwrite and arbitrary deletion of files writable by the Flask process. The route is unauthenticated, which makes exploitation possible by any network peer when `PLATFORM_TO ...[truncated 1261 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Never use a client-supplied filename as a filesystem path. 2. Create temporary files with `tempfile.NamedTemporaryFile` or a cryptographically random UUID. 3. If the original filename must be retained as metadata, sanitize it with `werkzeug.utils.secure_filename` and do not use it for path selection. 4. Resolve the resulting path and verify that it is a descendant of the dedicated temporary directory. 5. Open files using exclusive creation semantics to avoid overwriting existing content. 6. Delete only the server-generated temporary file, preferably in a `finally` block. 7. Enforce request-size and image-size limits. 8. Validate image content rather than trusting the filename or client MIME type. 9. Authenticate and authorize the upload endpoint. 10. Run the service with minimal write permissions. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
server.py:724
Finding
Arbitrary Filesystem Read and Write Through the Crop API<![CDATA[ ## Vulnerability Details **File Location**: `server.py:724-741`; `cut.py:17-18, 43-66` **Vulnerability Type**: Unrestricted user-controlled filesystem paths **Risk Level**: High ### Complete Code Snippets ```python @app.route('/api/cut', methods=['POST']) def api_cut_image(): try: data = request.get_json() path = data.get('path') num = data.get('num') out = data.get('out', None) if not path or not num: return jsonify({"success": False, "msg": "参数缺失,path(图片路径)和num(宫格数)为必填项"}) # 构造cut.py命令 cmd = [sys.executable, os.path.join(BASE_DIR, 'cut.py'), '-path', path, '-num', str(num)] if out: cmd.extend(['-out', out]) # 执行裁剪命令 result = subprocess.run(cmd, capture_output=True, text=True, encoding='utf-8') ``` ```python # 检查文件是否存在 if not os.path.exists(args.path): print(f"错误:图片文件 {args.path} 不存在") return # 打开图片 try: img = Image.open(args.path) except Exception as e: print(f"打开图片失败:{str(e)}") return ``` ```python if args.out: os.makedirs(args.out, exist_ok=True) save_dir = args.out name_format = "{}{}" else: save_dir = os.path.dirname(args.path) name_format = f"{file_base}_{{}}{{}}" for r in range(rows): for c in range(cols): left = c * cell_width top = r * cell_height right = left + cell_width bottom = top + cell_height cropped_img = img.crop((left, top, right, bottom)) filename = name_format.format(index, file_ext) save_path = os.path.join(save_dir, filename) cropped_img.save(save_path) print(f"成功生成:{save_path}") index += 1 ``` ### Technical Analysis The API accepts raw input and output filesystem paths from the caller. These values are passed as arguments to `cut.py`, which opens the input and creates the output directory without checking whether either path is within an approved application directory. Using an argument ...[truncated 1646 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not accept raw filesystem paths from clients. 2. Accept an opaque upload or work ID and resolve it to a server-managed file. 3. Use separate, dedicated input and output roots. 4. Canonicalize every path and verify containment within the approved root before access. 5. Generate output directories and filenames on the server. 6. Prevent overwriting by using unique names and exclusive file creation. 7. Authenticate and authorize the endpoint. 8. Set Flask request-size limits and Pillow pixel limits. 9. Reject unsupported formats and validate decoded image dimensions. 10. Apply subprocess timeouts, concurrency limits, disk quotas, and cleanup procedures. 11. Run processing in a sandboxed worker with restricted filesystem access. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
templates/index.html:1486
Finding
Stored DOM Cross-Site Scripting Through Prompts and Error Messages<![CDATA[ ## Vulnerability Details **File Location**: `templates/index.html:1120, 1486-1495, 1729`; `templates/admin.html:180, 211-232` **Vulnerability Type**: Stored DOM-based cross-site scripting **Risk Level**: High ### Complete Code Snippets ```javascript function showToast(msg, type = 'success') { const toast = $(`<div class="toast ${type}">${msg}</div>`); $('body').append(toast); setTimeout(() => { toast.fadeOut(300, () => toast.remove()); }, 3000); } ``` ```javascript const item = $(` <div class="grid-item" data-id="${work.id}"> ${deleteBtn} <img src="${imgSrc}" alt="${work.prompt}"> <div class="grid-item-info"> <div class="grid-item-title">${work.prompt.substring(0, 20)}${work.prompt.length > 20 ? '...' : ''}</div> <div class="grid-item-meta"> <span>${work.date.substring(5, 16)}</span> ${statusHtml} </div> ${retryBtn} </div> </div> `); ``` ```javascript <span class="value error-text">${work.error || '未知错误'}</span> ``` ```javascript function showToast(msg, type = 'success') { const toast = $(`<div class="toast ${type}">${msg}</div>`); $('body').append(toast); setTimeout(() => toast.remove(), 3000); } ``` ```javascript const tr = $(` <tr> <td>${work.id}</td> <td>${work.model || '-'}</td> <td>${work.date || '-'}</td> <td><span class="status-badge status-${work.state}">${statusText}</span></td> <td><span class="prompt-text" title="${work.prompt || '-'}">${work.prompt ? work.prompt.substring(0, 30) + '...' : '-'}</span></td> <td>${work.num || 1} 宫格</td> <td>${work.ratio || '-'}</td> <td>${work.quality || '-'}</td> <td><span title="${work.task_id || '-'}">${work.task_id ? work.task_id.substring(0, 15) + '...' : '-'}</span></td> <td><span title="${work.path || '-'}">${work.path ? work.path.substring(0, 20) + '...' : '-' ...[truncated 2511 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not create HTML by interpolating untrusted values into template literals. 2. Build elements with DOM APIs and assign untrusted content through `textContent` or jQuery `.text()`. 3. Set attributes through safe APIs such as `.attr()` after validating their expected format. 4. Apply context-specific output encoding for HTML text and attribute contexts. 5. Sanitize content with a mature allowlist sanitizer only if user-supplied markup is explicitly required. 6. Change toast rendering to create the container separately and assign `msg` as text. 7. Add a restrictive Content Security Policy that disallows inline scripts and inline event handlers. 8. Validate server responses and expose only fields required by the interface. 9. Add automated XSS tests for prompts, errors, paths, task IDs, and API responses. 10. Combine frontend encoding with backend authentication; encoding alone does not protect privileged APIs. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
server.py:510
Finding
External API Bearer Credential Exposed in Application Logs<![CDATA[ ## Vulnerability Details **File Location**: `server.py:510-516` **Vulnerability Type**: Sensitive credential logging **Risk Level**: High ### Complete Code Snippet ```python headers = { "Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json" } print(f"生成请求URL: {CONFIG['server']['url']}") print(f"请求头: {json.dumps(headers, indent=2)}") print(f"请求payload: {json.dumps(payload, indent=2, ensure_ascii=False)}") response = requests.post(CONFIG['server']['url'], headers=headers, json=payload, timeout=120) ``` ### Technical Analysis The `Authorization` header contains the complete AceData bearer credential. The application serializes and prints that header before every generation request. Logging the token is not required for image generation or troubleshooting and exceeds the minimum privilege and data exposure necessary for the declared functionality. Console output may be captured by service managers, terminal history, container logging systems, monitoring agents, or shared support logs. The payload log may also expose user prompts and uploaded reference-image data or URLs. ### Attack Path 1. A normal user or attacker triggers `/api/generate`. 2. The server constructs an `Authorization: Bearer ...` header. 3. The complete header is written to standard output. 4. A user, process, administrator, support recipient, or compromised logging system obtains the logs. 5. The bearer token is extracted and replayed directly against the AceData API. ### Impact Assessment Anyone with access to the application logs can impersonate the configured external-service account for as long as the token remains valid. Potential consequences include: - Unauthorized API requests - Consumption of paid quota or account funds - Access to task information permitted by the token - Account abuse attributed to the legitimate user - Secondary disclosure if logs also contain prompts, task responses, or image URLs This finding concerns accidental credenti ...[truncated 213 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove all logging of complete request headers. 2. Introduce centralized secret redaction for `Authorization`, API keys, cookies, tokens, and signed URLs. 3. Log only non-sensitive metadata such as endpoint hostname, request ID, status code, and duration. 4. Avoid logging complete request payloads when they contain prompts or reference-image content. 5. Protect logs with restrictive permissions, limited retention, and access auditing. 6. Rotate `API_KEY` if the affected version has processed generation requests. 7. Search historical logs and backups for exposed bearer tokens and securely delete or restrict them. 8. Add tests that fail when known secret values appear in captured logs. ]]>
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
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (57)

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

Critical
Category
Data Flow
Content
}
                print(f"请求参数: {json.dumps(payload, indent=2)}")
                
                response = requests.post(CONFIG['server']['task_url'], headers=headers, json=payload, timeout=120)
                print(f"返回状态码: {response.status_code}")
                print(f"返回原始内容: {repr(response.text)}")
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

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

Critical
Category
Data Flow
Content
print(f"生成请求URL: {CONFIG['server']['url']}")
        print(f"请求头: {json.dumps(headers, indent=2)}")
        print(f"请求payload: {json.dumps(payload, indent=2, ensure_ascii=False)}")
        response = requests.post(CONFIG['server']['url'], headers=headers, json=payload, timeout=120)
        print(f"返回状态码: {response.status_code}")
        print(f"返回内容: {repr(response.text)}")
        response.raise_for_status()
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

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

Critical
Category
Data Flow
Content
payload = {"id": task_id,"action": "retrieve"}
    
    try:
        response = requests.post(CONFIG['server']['task_url'], headers=headers, json=payload, timeout=60)
        response.raise_for_status()
        data = response.json()
        print(f"接口返回成功: {json.dumps(data, indent=2, ensure_ascii=False)}")
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Tainted flow: 'cut_cmd' from requests.post (line 149, network input) → subprocess.run (code execution)

Critical
Category
Data Flow
Content
'-num', str(num),
                '-out', save_dir
            ]
            result = subprocess.run(cut_cmd, capture_output=True, text=True, encoding='utf-8')
            if result.returncode == 0:
                print(f"图片切割成功: {result.stdout}")
            else:
Confidence
90% confidence
Finding
External input (network, user) flows to a code execution sink. This enables remote code execution or command injection.

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

Critical
Category
Data Flow
Content
files = {
            "file": open(file_path, "rb")
        }
        response = requests.post(UPLOAD_URL, headers=headers, files=files, timeout=60)
        response.raise_for_status()
        result = response.json()
        url = result.get('url')
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
98% confidence
Finding
The skill is presented as an image generation/cutting utility, but the underlying capabilities include reading arbitrary local files, opening local folders, invoking local scripts on user-supplied paths, writing credentials, and remotely shutting down the service. In this context, the mismatch makes the hidden capabilities more dangerous because the skill appears routine and creative, not administrative or system-level.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The skill is presented as an image generation/cutting utility, but the underlying capabilities include reading arbitrary local files, opening local folders, invoking local scripts on user-supplied paths, writing credentials, and remotely shutting down the service. In this context, the mismatch makes the hidden capabilities more dangerous because the skill appears routine and creative, not administrative or system-level.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The skill is presented as an image generation/cutting utility, but the underlying capabilities include reading arbitrary local files, opening local folders, invoking local scripts on user-supplied paths, writing credentials, and remotely shutting down the service. In this context, the mismatch makes the hidden capabilities more dangerous because the skill appears routine and creative, not administrative or system-level.

Credential Access

High
Category
Privilege Escalation
Content
├── upload.py              # 图片上传工具
├── set.json               # 配置文件(模型、分辨率、质量)
├── prompt.md              # 提示词模板
├── .env                   # 环境变量(API密钥)
├── .env.example           # 环境变量示例
├── SKILL.md               # 本文档
├── data/
Confidence
72% confidence
Finding
The skill structure explicitly includes a real `.env` file containing API credentials within the project layout, which increases the risk that secrets are stored alongside application code and may be accidentally exposed, copied, or read by other local components. In a skill that also has file-access and admin behavior, credential storage inside the workspace is more sensitive.

Credential Access

High
Category
Privilege Escalation
Content
- `apikey` 字段已废弃,请使用 `.env` 文件配置
- `save_path` 可自定义图片保存路径

### .env 环境变量

```bash
# 请访问 https://share.acedata.cloud/r/1uN88BrUTQ 获取以下配置
Confidence
78% confidence
Finding
The documentation instructs users to place API keys and platform tokens into a `.env` file, which constitutes credential handling and local secret storage. If combined with weak file permissions, backup leakage, or undocumented file-reading routes, those secrets may be exposed or misused to access third-party services.

Credential Access

High
Category
Privilege Escalation
Content
os.makedirs(SAVE_BASE_PATH, exist_ok=True)

# 检查API_KEY配置,创建.env文件如果不存在
env_path = os.path.join(BASE_DIR, '.env')
if not os.path.exists(env_path):
    with open(env_path, 'w', encoding='utf-8') as f:
        f.write("# 请访问 https://share.acedata.cloud/r/1uN88BrUTQ 获取以下配置\n")
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
return jsonify({"success": False, "msg": "API_KEY为必填项,请填写"}), 400
        
        # 写入.env文件
        env_path = os.path.join(BASE_DIR, '.env')
        with open(env_path, 'w', encoding='utf-8') as f:
            f.write(f"API_KEY={api_key}\n")
            f.write(f"PLATFORM_TOKEN={platform_token}\n")
Confidence
91% confidence
Finding
This endpoint writes API_KEY and PLATFORM_TOKEN to disk and updates runtime configuration without any authentication or authorization checks. An attacker who can reach the service can replace credentials, redirect service behavior, or break functionality, turning configuration management into a remote tampering primitive.

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
The skill exposes administrative OS/process control endpoints unrelated to its stated image-generation purpose, including opening local folders and shutting down the server. With CORS enabled globally and no authentication checks on these routes, any reachable client can trigger disruptive or host-interacting actions remotely.

Missing User Warnings

High
Confidence
99% confidence
Finding
The shutdown endpoint immediately terminates the process via os._exit(0) with no authentication, authorization, or confirmation. Any reachable caller can cause a trivial denial of service, and in this image-processing skill that fully stops all generation, polling, and file-management functions.

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
The catch-all file-serving route joins attacker-supplied paths against the filesystem root and serves any existing file outside the app scope. The '..' check is insufficient because absolute or normalized paths like Windows drive paths or sensitive Unix paths can still expose arbitrary local files, making this a major information disclosure issue.

Context-Inappropriate Capability

High
Confidence
97% confidence
Finding
The UI directly exposes a service shutdown action that posts to /api/shutdown, which is inappropriate for a normal image-generation tool and can cause denial of service if accessible to non-admin users. In this skill context, shutdown is unrelated to core functionality, so accidental or unauthorized triggering is especially risky.

Tainted flow: 'files' from open (line 74, file read) → requests.post (network output)

High
Category
Data Flow
Content
files = {
            "file": open(file_path, "rb")
        }
        response = requests.post(UPLOAD_URL, headers=headers, files=files, timeout=60)
        response.raise_for_status()
        result = response.json()
        url = result.get('url')
Confidence
80% confidence
Finding
File contents flow to a network sink. This may indicate data exfiltration of sensitive files.

Lp3

Medium
Category
MCP Least Privilege
Confidence
81% confidence
Finding
The skill documents capabilities that imply filesystem access, environment variable handling, network communication, and shell/process execution, but it does not declare any explicit tool scope or permission boundaries. This creates a least-privilege failure: users and hosting platforms cannot easily assess or constrain what the skill is allowed to do, increasing the risk of overbroad local access and unintended side effects.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The skill explains how to configure API keys and use generation/editing features but does not clearly warn that prompts, uploaded images, and task metadata are transmitted to third-party services and also stored locally. This can lead to unintentional disclosure of sensitive content, especially because users may assume a localhost tool keeps data entirely local.

External Transmission

Medium
Category
Data Exfiltration
Content
```json
{
  "server": {
    "url": "https://api.acedata.cloud/nano-banana/images",
    "task_url": "https://api.acedata.cloud/nano-banana/tasks",
    "upload_url": "https://platform.acedata.cloud/api/v1/files/",
    "apikey": ""
Confidence
86% confidence
Finding
The skill transmits content to an external API endpoint for image generation. External transmission is expected for this type of service, but it is still security-relevant because prompts, task metadata, and possibly user content leave the local environment and go to a third party.

External Transmission

Medium
Category
Data Exfiltration
Content
{
  "server": {
    "url": "https://api.acedata.cloud/nano-banana/images",
    "task_url": "https://api.acedata.cloud/nano-banana/tasks",
    "upload_url": "https://platform.acedata.cloud/api/v1/files/",
    "apikey": ""
  },
Confidence
89% confidence
Finding
The documented upload endpoint sends files to a third-party platform service, which can expose user images and related metadata outside the local system. In an image-editing workflow this may be functional rather than malicious, but the absence of prominent warning and data-governance detail makes it a real privacy/security concern.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The documented admin endpoints include retry, close, delete, and shutdown actions but do not include warnings about deleting local data, altering task state, or stopping the running service. Exposing destructive operations without clear warnings increases the chance of accidental denial of service or data loss by users who do not realize the effect of these routes.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The natural-language instructions are written as mandatory requirements in Chinese and direct the model to generate output under those constraints without any indication that the user can choose another language or locale. This creates a language/locale policy issue because it imposes a specific language context by default rather than offering opt-in or documenting a justified regional limitation.

Tainted flow: 'payload' from requests.post (line 201, network input) → requests.post (network output)

Medium
Category
Data Flow
Content
}
                print(f"请求参数: {json.dumps(payload, indent=2)}")
                
                response = requests.post(CONFIG['server']['task_url'], headers=headers, json=payload, timeout=120)
                print(f"返回状态码: {response.status_code}")
                print(f"返回原始内容: {repr(response.text)}")
Confidence
65% confidence
Finding
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Tainted flow: 'image_url' from requests.post (line 220, network input) → requests.get (network output)

Medium
Category
Data Flow
Content
ext = 'png'
                        main_path = os.path.join(save_dir, f'main.{ext}')
                        
                        img_response = requests.get(image_url, stream=True, timeout=60)
                        img_response.raise_for_status()
                        with open(main_path, 'wb') as f:
                            for chunk in img_response.iter_content(chunk_size=8192):
Confidence
96% confidence
Finding
The server downloads image_url returned by an external service without validating scheme, host, IP range, or content type. If the upstream service is compromised or attacker-influenced, this enables SSRF to internal services or retrieval of arbitrary local-network resources, which is especially risky because this skill already acts as a networked backend.

Static analysis

No suspicious patterns detected.