Back to skill

Security audit

VoooAI - AI Multimedia NL2Workflow Platform

Security checks for vulnerabilities and agentic risk

Overview

This skill is mostly a disclosed VoooAI media-generation relay, but it has unsafe network and file-handling paths that could expose the user's access key or local/internal data if misused or misconfigured.

Review before installing. Only use this skill with a VOOOAI_ACCESS_KEY you are willing to use for media generation, do not set VOOOAI_BASE_URL except to a trusted VoooAI HTTPS origin, upload only files you intentionally selected, and avoid using direct --urls downloads from untrusted sources. Generated workflows may consume credits, so confirm costs before execution.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/_common.py:10
Finding

Bearer Access Key Can Be Transmitted to an Attacker-Controlled Server

Content
View full analysis
dict: access_key = _ensure_access_key() headers = { "Authorization": f"Bearer {access_key}", } if content_type: headers["Content-Type"] = content_type return headers def api_get(path: str, timeout: int = 30) -> dict: validate_api_path(path) url = f"{BASE_URL.rstrip('/')}{path}" req = urllib.request.Request(url, method="GET", headers=_headers()) try: with urllib.request.urlopen(req, timeout=timeout) as resp: return json.loads(resp.read().decode("utf-8")) ``` The corresponding POST implementation uses the same pattern: ```python validate_api_path(path) url = f"{BASE_URL.rstrip('/')}{path}" data = json.dumps(body).encode("utf-8") req = urllib.request.Request( url, data=data, method="POST", headers=_headers(), ) try: with urllib.request.urlopen(req, timeout=timeout) as resp: return json.loads(resp.read().decode("utf-8")) ``` ### Technical Analysis `VOOOAI_BASE_URL` is accepted without validating its scheme, hostname, port, credentials, or relationship to the expected VoooAI origin. The API path allowlist only validates the path supplied to `api_get()` or `api_post()`; it does not validate the destination represented by `BASE_URL`. Every request adds `VOOOAI_ACCESS_KEY` as a bearer token. Consequently, a modified environment can direct authenticated requests to an arbitrary HTTP or HTTPS server. A non-HTTPS URL also exposes the token to network interception. Redirect behavior is not explicitly constrained, so ...[truncated 1377 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/upload_file.py:34
Finding

Media Upload Validation Can Be Bypassed to Upload Arbitrary Local Files

Content
View full analysis
max_size_mb * 1024 * 1024: error_exit(f"文件过大: {file_size / 1024 / 1024:.1f}MB(最大 {max_size_mb}MB)") # 检查 MIME 类型 mime_type, _ = mimetypes.guess_type(file_path) if mime_type and not any(mime_type.startswith(p) for p in ALLOWED_PREFIXES): error_exit(f"不支持的文件类型: {mime_type},仅支持图片、视频和音频") # 构建 multipart/form-data 请求体 boundary = f"----VoooAIUpload{uuid.uuid4().hex}" filename = os.path.basename(file_path) content_type = mime_type or "application/octet-stream" body_parts = [] # file 字段 body_parts.append(f"--{boundary}\r\n".encode()) body_parts.append( f'Content-Disposition: form-data; name="file"; filename="{filename}"\r\n'.encode() ) body_parts.append(f"Content-Type: {content_type}\r\n\r\n".encode()) with open(file_path, "rb") as f: body_parts.append(f.read()) body_parts.append(b"\r\n") # 结束边界 body_parts.append(f"--{boundary}--\r\n".encode()) data = b"".join(body_parts) # 校验路径(/api/upload) api_path = "/api/upload" validate_api_path(api_path) # 获取 AccessKey access_key = _ensure_access_key() url = f"{BASE_URL.rstrip('/')}{api_path}" req = urllib.request.Request( url, data=data, method="POST", headers={ "Authorization": f"Bearer {access_key}", "Content-Type": f"multipart/form-data; boundary={boundary}", }, ) ``` ### Technical Analysis The code relies on `mimetypes.guess_type()`, which infers a MIME type from the filename rather than examining the file content. Validation is performed only when `mime_type` is truthy: ```python if mime_type and not any(...): ``` If an extensionless file or an unrecognized extension causes `guess_type()` to return `None`, validation is skipped and the file is uploaded as `appl ...[truncated 1515 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/download_results.py:73
Finding

Unrestricted Result URLs Enable Local File Retrieval and Internal Network Access

Content
View full analysis
tuple: """ 下载单个文件 Args: url: 文件 URL filepath: 保存路径 Returns: (filepath, error) - error 为 None 表示成功 """ req = urllib.request.Request(url, headers={"User-Agent": "VoooAI-Skill/1.0"}) try: with urllib.request.urlopen(req, timeout=120) as resp: with open(filepath, "wb") as f: while True: chunk = resp.read(8192) if not chunk: break f.write(chunk) return filepath, None except Exception as e: return filepath, str(e) ``` Direct URLs are accepted without validation: ```python download_items = [] if args.urls: # 直接指定的 URL for url in args.urls: download_items.append({ "url": url, "type": "unknown", "node_id": "", }) ``` URLs extracted from backend execution results also reach the same download function without scheme or destination validation. ### Technical Analysis `urllib.request.urlopen()` supports more than ordinary public HTTPS downloads. The input is not constrained to HTTPS, and there are no checks for: - `file://` URLs. - Loopback addresses. - Private network ranges. - Link-local addresses. - Cloud metadata endpoints. - DNS rebinding. - Cross-origin redirects. - Untrusted backend-provided output URLs. As a result, a direct `--urls` argument can copy readable local files into the output directory. HTTP URLs can cause requests to internal services that are reachable from the host but not from the attacker. Backend-provided result URLs create the same exposure if the service response is compromised or contains ...[truncated 1611 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/download_results.py:84
Finding

Unbounded Concurrent Downloads Can Exhaust Local Disk Space

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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 (20)

Tainted flow: 'req' from os.environ.get (line 110, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
97% confidence
Finding

The request destination is built from the environment-controlled BASE_URL and then used in urllib.request.urlopen while automatically attaching the Bearer access key in the Authorization header. If an attacker can influence VOOOAI_BASE_URL, they can redirect requests to an attacker-controlled host and capture the credential or proxy creative-operation requests, which is effectively SSRF plus secret exfiltration.

Content

Scanner excerpt · scripts/_common.py (reported line 84)May include surrounding context.

python
url = f"{BASE_URL.rstrip('/')}{path}"
    req = urllib.request.Request(url, method="GET", headers=_headers())
    try:
        with urllib.request.urlopen(req, timeout=timeout) as resp:
            return json.loads(resp.read().decode("utf-8"))
    except urllib.error.HTTPError as e:
        err_body = e.read().decode("utf-8") if e.fp else ""

Tainted flow: 'req' from os.environ.get (line 110, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
97% confidence
Finding

The POST path has the same issue: the code composes a URL from environment-controlled BASE_URL and sends authenticated requests with the Bearer token. A manipulated base URL can cause sensitive workflow inputs, uploaded-content metadata, and the access key itself to be sent to an unintended server.

Content

Scanner excerpt · scripts/_common.py (reported line 117)May include surrounding context.

python
headers=_headers(),
    )
    try:
        with urllib.request.urlopen(req, timeout=timeout) as resp:
            return json.loads(resp.read().decode("utf-8"))
    except urllib.error.HTTPError as e:
        err_body = e.read().decode("utf-8") if e.fp else ""

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill claims to be a passive relay, yet it supports direct execution of arbitrary workflow JSON/file/stdin and local parameter mutation via --set-param. That materially expands its authority from forwarding user prompts to executing attacker-controlled or unsafe workflow definitions, increasing the risk of misuse, unauthorized processing, or bypass of intended backend planning safeguards.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The skill claims to be a passive relay, yet it supports direct execution of arbitrary workflow JSON/file/stdin and local parameter mutation via --set-param. That materially expands its authority from forwarding user prompts to executing attacker-controlled or unsafe workflow definitions, increasing the risk of misuse, unauthorized processing, or bypass of intended backend planning safeguards.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill declares access to environment variables, file handling, and network-backed operations but does not explicitly constrain its tool scope with a permissions or allowed-tools declaration. That creates unnecessary ambiguity about what the skill may access at runtime and weakens least-privilege enforcement, especially for a skill that handles uploads and uses an access key.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The invocation guidance says to use the skill for any visual or audio content creation, generation, editing, or modification, which is broad enough to trigger the skill for many unrelated or higher-risk requests. Over-broad routing increases the chance that sensitive user content, copyrighted material, or unsafe media-manipulation requests are sent to the backend without sufficient narrowing or guardrails.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
75% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

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

md
| Direct API calls bypassing scripts | Security risk — use provided scripts only |
| Manual workflow JSON construction | Quality risk — use generate_workflow.py only |
| Deepfakes / non-consensual facial or voice mimicry | Content safety — violates ethical guidelines |
| Impersonating real individuals without consent | Content safety — privacy and legal concerns |
| Political disinformation / election interference | Content safety — harmful content prohibition |

## 5. Available Scripts

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The trigger pattern examples cover a very wide range of media-generation and editing requests without clearly defining hard boundaries for when human review, extra consent, or denial is required. In a media skill that supports uploads and transformations, such broad examples can cause over-invocation and accidental processing of sensitive or disallowed content.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
85% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

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

When generate_workflow.py returns points_warning or estimated_points:

  1. MUST show estimated cost to user before execution
  2. MUST wait for user confirmation
  3. NEVER auto-execute when points_warning exists

Example interaction:

text

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The script goes beyond the skill's stated role of relaying creative requests by querying and outputting account metadata such as points balance, membership level, trust level, rate limits, and possibly cost guidance. Even if obtained from a legitimate endpoint, exposing this information increases unnecessary data access and disclosure, which can leak operational/account details to users or downstream logs.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
83% confidence
Finding

The file’s natural-language descriptions are entirely in Chinese, including the top-level docstring that defines the script’s purpose. Under the policy, forcing a specific language without user opt-in can be a locale/language policy violation, and this file does not mention any user choice or justified regional constraint.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The module docstring is written entirely in Chinese, and the command-line description/help strings throughout the script are also Chinese-only. This imposes a specific language on users without any opt-in or indication that the tool is intentionally locale-specific.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The script downloads arbitrary remote URLs returned by the backend or supplied via --urls and writes them directly to local disk without validating the source domain, content type, size, or warning the operator about trust boundaries. In this skill, the backend is explicitly trusted to generate and return media artifacts, so a compromised backend, malicious workflow output, or attacker-controlled URL could cause unsafe local file writes, storage exhaustion, or delivery of deceptive content under innocuous filenames.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The module docstring, CLI description, help text, examples, and runtime messages are written entirely in Chinese. This imposes a specific language on all users without any opt-in, alternate locale, or justification that the skill is region-specific, which matches the language/locale policy violation criteria.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The file's user-facing natural language is consistently Chinese, including the module docstring, CLI description, help text, error messages, and status output. This imposes a specific language on users without any opt-in or documented locale constraint, which matches the language/locale policy violation criteria.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The module docstring, CLI description, help text, examples, warnings, and status messages are all presented in Chinese. This effectively forces a specific language for users of the skill, and the file does not offer an opt-in choice for interface language or explain that the tool is intentionally region-specific.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This file is a code file, so only SQP-2 and SQP-3 apply. Multiple user-facing strings beginning at the module docstring are fixed in Chinese, and the CLI help/output does not offer any language selection or explain that the tool is intended only for a Chinese-speaking or region-specific audience. That creates a natural-language locale policy concern under SQP-3.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

This code file contains natural-language content exclusively in Chinese in the module docstring and user-facing error output, with no indication that users can choose another language or that the skill is region-specific. That can violate a language/locale policy requiring user choice or explicit justification for a locale constraint.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The documentation understates behavior by describing capability discovery while the code also retrieves and reports credit balance and account status details. This mismatch can cause operators, reviewers, or calling agents to authorize or invoke the script without realizing it accesses and exposes additional sensitive metadata.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
75% confidence
Finding

The documentation states that VOOOAI_ACCESS_KEY is only for creative operations, not billing/admin. However, the script contains logic for account points state and references a subscription/recharge URL when points are insufficient, which contradicts that narrow framing by exposing an account/subscription-related concern.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.