Back to skill

Security audit

Minimax Tts Gyh

Security checks for vulnerabilities and agentic risk

Overview

This skill is a straightforward MiniMax text-to-speech helper with expected API-key use and no hidden persistence or destructive behavior.

Install only if you are comfortable sending the text you provide to MiniMax and exposing MINIMAX_API_KEY to this script. Prefer an isolated Python environment, consider pinning dependencies, and avoid running it on networks where a compromised vendor download URL could reach sensitive internal services.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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 (2)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/tts.py:98
Finding
Unvalidated Server-Provided Download URL Enables SSRF and Unbounded Downloads<![CDATA[ ## Vulnerability Details **File Location**: `scripts/tts.py`, lines 98-111 **Vulnerability Type**: Unvalidated remote URL, unrestricted redirects, and unbounded response buffering **Risk Level**: Medium ### Vulnerable Code ```python def download_file(file_id: str, output_path: str): """下载音频文件""" url = f"{API_HOST}/v1/files/retrieve" params = {"file_id": file_id} resp = requests.get(url, headers=HEADERS, params=params, timeout=30) resp.raise_for_status() download_url = resp.json()["file"]["download_url"] with open(output_path, "wb") as f: vr = requests.get(download_url, timeout=60) vr.raise_for_status() f.write(vr.content) print(f"✅ 文件已下载: {output_path}") ``` ### Technical Analysis The script trusts the `download_url` returned by the MiniMax API and passes it directly to `requests.get`. It does not validate: - The URL scheme - The destination hostname - The resolved IP address - Redirect destinations - Whether the target is a loopback, private, link-local, or reserved address - The response size or declared content type The `requests` library follows HTTP redirects by default. Consequently, even an initially trusted URL can redirect the client to a sensitive internal destination. Exploitation requires control over, or compromise of, the API response or an upstream service capable of influencing the returned download URL. The response is also read through `vr.content`, which buffers the complete body in memory before writing it. No maximum response size is enforced, creating memory and disk exhaustion risk. The API authorization header is not forwarded to the download URL, which limits direct exposure of `MINIMAX_API_KEY`. ### Attack Path 1. An attacker compromises or gains influence over the API response associated with a TTS file retrieval request. 2. The response supplies a malicious `download_url`, or a URL that redirects to an attacker-selected destination. 3. The skill automatically ...[truncated 1169 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Accept only HTTPS download URLs. 2. Maintain an explicit allowlist of approved MiniMax and trusted CDN hostnames. 3. Resolve the hostname before connecting and reject loopback, private, link-local, multicast, unspecified, and reserved IP ranges. 4. Disable automatic redirects with `allow_redirects=False`, or validate every redirect target using the same scheme, hostname, and IP checks. 5. Stream downloads with `stream=True` instead of buffering the entire response through `vr.content`. 6. Enforce a strict maximum download size using both `Content-Length` and a running byte counter while streaming. 7. Validate the response content type against expected audio types. 8. Download to a temporary file in the destination directory and atomically replace the final output only after all validation succeeds. 9. Apply separate connection and read timeouts and remove partial files when an error occurs. Example hardened pattern: ```python with requests.get( validated_url, stream=True, timeout=(10, 60), allow_redirects=False, ) as response: response.raise_for_status() total = 0 with open(temp_path, "wb") as output: for chunk in response.iter_content(chunk_size=64 * 1024): if not chunk: continue total += len(chunk) if total > MAX_AUDIO_BYTES: raise ValueError("Audio download exceeds the permitted size") output.write(chunk) ``` ]]>

T08 · Insecure Dependencies

Note
Location
SKILL.md:24
Finding
Unpinned Third-Party Dependency Installation<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, line 24 **Vulnerability Type**: Unconstrained third-party dependency **Risk Level**: Low ### Vulnerable Code ```text - `pip3 install requests` ``` ### Technical Analysis The installation instruction retrieves `requests` without specifying a reviewed version or cryptographic hashes. The package name is not visibly misspelled, and the command does not specify an untrusted custom package index. Nevertheless, installation resolves a mutable package version at setup time. This prevents reproducible installation and means future users may receive a release different from the one originally audited. If a future release or package distribution channel is compromised, malicious installation or runtime code could execute under the installing user's privileges. ### Attack Path 1. A user follows the documented setup instruction. 2. `pip` queries its configured package index and resolves the latest dependency version allowed at that time. 3. A compromised package release, compromised index, or unsafe local package-index configuration supplies malicious content. 4. The package is installed into the selected Python environment. 5. Malicious package code can execute during installation or when `requests` is imported by `scripts/tts.py`. This path depends on an upstream supply-chain compromise or an already unsafe package-manager configuration; the audited project does not itself provide a malicious package source. ### Impact Assessment Malicious dependency code would execute with the privileges of the user performing installation or running the script. Depending on those privileges, it could access environment variables such as `MINIMAX_API_KEY`, alter files available to the user, make network requests, or compromise the Python environment. The issue does not independently establish privilege escalation. Its scope is bounded by the permissions of the installation and runtime account. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions 1. Add a reviewed dependency manifest instead of instructing users to install an unconstrained package. 2. Pin `requests` and its transitive dependencies to tested versions. 3. Generate and verify cryptographic hashes for every resolved distribution. 4. Use a lock file or hash-locked requirements file to make installations reproducible. 5. Install only from the intended HTTPS package index and avoid unreviewed additional indexes. 6. Use an isolated virtual environment with least-privilege permissions. 7. Establish a process for dependency vulnerability scanning and controlled version updates. Example installation approach: ```bash python3 -m pip install --require-hashes -r requirements.txt ``` The corresponding `requirements.txt` should contain exact versions and reviewed SHA-256 hashes for `requests` and all transitive dependencies. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (9)

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

Critical
Category
Data Flow
Content
print(f"   模型: {model} | 声音: {voice_id} | 语速: {speed}x")
    print(f"   文本: {text[:50]}{'...' if len(text) > 50 else ''}")

    resp = requests.post(url, headers=HEADERS, json=payload, timeout=60)
    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.

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

Critical
Category
Data Flow
Content
for i in range(max_wait // 10):
        time.sleep(10)
        resp = requests.get(url, headers=HEADERS, params=params, 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.

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

Critical
Category
Data Flow
Content
for i in range(max_wait // 10):
        time.sleep(10)
        resp = requests.get(url, headers=HEADERS, params=params, 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.

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

Critical
Category
Data Flow
Content
"""列出可用声音"""
    url = f"{API_HOST}/v1/voices"
    params = {"model": model}
    resp = requests.get(url, headers=HEADERS, params=params, timeout=10)
    print(resp.text)
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill documentation advertises use of an environment variable (`MINIMAX_API_KEY`) and external API access, but it does not declare any explicit tool scope such as permissions or allowed-tools. That creates an authorization and review gap: a runner may allow environment and network access without the skill clearly disclosing those capabilities, increasing the chance of unintended secret exposure or unvetted outbound requests.

External Transmission

Medium
Category
Data Exfiltration
Content
print(f"   模型: {model} | 声音: {voice_id} | 语速: {speed}x")
    print(f"   文本: {text[:50]}{'...' if len(text) > 50 else ''}")

    resp = requests.post(url, headers=HEADERS, json=payload, timeout=60)
    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.

Tainted flow: 'download_url' from requests.get (line 108, network input) → requests.get (network output)

Medium
Category
Data Flow
Content
download_url = resp.json()["file"]["download_url"]

    with open(output_path, "wb") as f:
        vr = requests.get(download_url, timeout=60)
        vr.raise_for_status()
        f.write(vr.content)
    print(f"✅ 文件已下载: {output_path}")
Confidence
94% confidence
Finding
The code fetches a download URL from a prior API response and then performs a second request to that URL without validating its scheme, host, or whether it stays within the trusted MiniMax domain. If the upstream response is malicious, compromised, or intercepted in some environment, this creates an SSRF-style primitive and could make the agent contact arbitrary internal or external endpoints.

Natural-Language Policy Violations

Low
Confidence
89% confidence
Finding
The manifest description is written entirely in Chinese, which can impose a language expectation on users without indicating that the skill supports multiple languages or is intentionally limited to a Chinese-speaking audience. Under the policy, locale or language restrictions should be optional or clearly justified.

Natural-Language Policy Violations

Low
Confidence
94% confidence
Finding
This code file contains user-facing natural-language strings such as the module description, CLI help text, status output, and error messages entirely in Chinese. The file does not offer an alternative language or explain that the tool is intentionally limited to a Chinese-speaking audience, which can violate a language/locale policy requiring user choice or explicit justification.

Static analysis

No suspicious patterns detected.