Back to skill

Security audit

MiniMax Speech 2.8

Security checks for vulnerabilities and agentic risk

Overview

The skill matches its MiniMax text-to-speech purpose, but it needs review because it can send the user’s MiniMax API key and text to arbitrary endpoints and fetch arbitrary returned URLs.

Install only if you are comfortable with the skill using a MiniMax API key and sending requested text to MiniMax. Avoid custom --endpoint values unless you fully trust the destination, avoid --output-format url in sensitive environments, and use a least-privileged or disposable MiniMax key where possible.

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
scripts/minimax_tts.py:104
Finding
MiniMax API Credential Disclosure Through Unrestricted Endpoint Overrides<![CDATA[ ## Vulnerability Details **File Location**: `scripts/minimax_tts.py:104-107, 130, 150-156, 219-220, 231-232` **Vulnerability Type**: Bearer-token disclosure to a user-controlled network destination **Risk Level**: High ### Vulnerable Code ```python def run_tts(args: argparse.Namespace) -> None: api_key = ensure_api_key() headers = { "Authorization": f"Bearer {api_key}", "Content-Type": "application/json", } ``` ```python response = requests.post( args.endpoint, headers=headers, json=payload, timeout=args.timeout, ) ``` ```python def run_voices(args: argparse.Namespace) -> None: api_key = ensure_api_key() headers = { "Authorization": f"Bearer {api_key}", "Content-Type": "application/json", } payload = {"voice_type": args.voice_type} try: response = requests.post( args.endpoint, headers=headers, json=payload, timeout=args.timeout, ) ``` ```python tts_parser.add_argument( "--endpoint", default="https://api.minimax.io/v1/t2a_v2", help="Override MiniMax T2A endpoint", ) ``` ```python voices_parser.add_argument( "--endpoint", default="https://api.minimax.io/v1/get_voice", help="Override the catalog endpoint", ) ``` ### Technical Analysis Both CLI subcommands accept an unrestricted `--endpoint` argument. The script then attaches the value of `MINIMAX_API_KEY` as an HTTP bearer token to a request sent to that destination. Sending the credential to the default official MiniMax endpoints is necessary for the declared functionality. Allowing any caller-controlled host to receive the same credential is not necessary and violates least-privilege network handling. The code does not enforce HTTPS, validate the hostname, constrain the URL path, or require confirmation before sending the credential to a non-default destination. Consequently, an untrusted command, copied usage instruction, or ac ...[truncated 1369 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace unrestricted endpoint overrides with an allowlist of exact HTTPS origins, such as the documented MiniMax regional API hosts. 2. Validate all of the following before constructing or sending an authenticated request: - Scheme must be `https`. - Hostname must exactly match an approved MiniMax domain. - Port must be the expected HTTPS port. - URL must not contain embedded credentials. - Path must match the endpoint expected by the selected subcommand. 3. Do not attach `MINIMAX_API_KEY` when the destination is outside the allowlist. 4. If custom endpoints are an essential advanced feature, require an explicit unsafe-mode option and a separate credential intended for that endpoint. Display the normalized destination before transmission. 5. Ensure redirects are disabled or revalidated so an approved endpoint cannot redirect an authenticated request to an unapproved host. 6. Add automated tests confirming that HTTP URLs, lookalike domains, subdomain tricks, IP literals, and unknown paths are rejected. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/minimax_tts.py:29
Finding
Server-Controlled Audio URL Enables Server-Side Request Forgery<![CDATA[ ## Vulnerability Details **File Location**: `scripts/minimax_tts.py:29-38, 138-141` **Vulnerability Type**: Unvalidated remote URL retrieval and unbounded response buffering **Risk Level**: Medium ### Vulnerable Code ```python def decode_audio(audio_payload: str, output_format: str) -> bytes: if output_format == "hex": return bytes.fromhex(audio_payload) if output_format == "base64": return base64.b64decode(audio_payload) if output_format == "url": resp = requests.get(audio_payload, timeout=60) resp.raise_for_status() return resp.content fail(f"Unsupported output format: {output_format}") ``` ```python audio_payload = data.get("data", {}).get("audio") if not audio_payload: fail(f"No audio payload returned: {json.dumps(data)}") audio_bytes = decode_audio(audio_payload, args.output_format) out_file = Path(args.output or f"minimax_tts_output.{args.audio_format}") ``` ### Technical Analysis When `--output-format url` is selected, the script treats the API response's `data.audio` field as a trusted URL and performs a GET request without validating its scheme, hostname, resolved address, redirect chain, content type, or response size. A compromised API service or a custom endpoint can return a URL targeting localhost, private network ranges, link-local services, or cloud metadata endpoints. Because `requests.get()` follows redirects by default, an initially acceptable URL could also redirect to an internal destination. The use of `resp.content` buffers the complete response in memory. There is no maximum download size, so a malicious or unexpectedly large response can cause excessive memory consumption and subsequently consume disk space when written to the output file. The flagged decode-and-execute pattern is not present: hex and base64 data are decoded into bytes and written as audio, but the script does not execute those bytes. The security issue is the unrestricted network retrieval, no ...[truncated 1825 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Restrict audio download URLs to HTTPS and an allowlist of documented MiniMax-controlled CDN hosts. 2. Normalize the URL and reject: - Non-HTTPS schemes. - Embedded credentials. - IP-literal hosts. - Loopback, private, link-local, multicast, reserved, and cloud metadata address ranges. 3. Resolve the hostname and validate every resulting address immediately before connection to reduce DNS-rebinding risk. 4. Disable redirects with `allow_redirects=False`, or validate each redirect destination with the same host and address controls. 5. Use streaming downloads rather than `resp.content`, and enforce a strict maximum byte count: ```python with requests.get(url, stream=True, timeout=60, allow_redirects=False) as resp: resp.raise_for_status() total = 0 chunks = [] for chunk in resp.iter_content(chunk_size=65536): total += len(chunk) if total > MAX_AUDIO_BYTES: fail("Audio response exceeds the permitted size") chunks.append(chunk) return b"".join(chunks) ``` 6. Verify that the response `Content-Type` is an expected audio media type and reject HTML, JSON, and arbitrary binary responses. 7. Prefer returning hex or base64 audio through the already authenticated API response if URL-based retrieval is not required. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (13)

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

Critical
Category
Data Flow
Content
if timbre_weights:
        payload["timbre_weights"] = timbre_weights
    try:
        response = requests.post(args.endpoint, headers=headers, json=payload, timeout=args.timeout)
        response.raise_for_status()
    except requests.RequestException as exc:
        fail(f"TTS request failed: {exc}")
Confidence
98% confidence
Finding
The script sends an Authorization bearer token sourced from MINIMAX_API_KEY to a user-controlled --endpoint. Because the endpoint is overrideable without validation, an operator can unintentionally exfiltrate the API key and request contents to any remote host, turning a MiniMax-specific helper into a generic credentialed HTTP client.

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

Critical
Category
Data Flow
Content
}
    payload = {"voice_type": args.voice_type}
    try:
        response = requests.post(args.endpoint, headers=headers, json=payload, timeout=args.timeout)
        response.raise_for_status()
    except requests.RequestException as exc:
        fail(f"Voice catalog request failed: {exc}")
Confidence
98% confidence
Finding
The voice catalog path has the same issue: it transmits the bearer token from the environment to any URL supplied via --endpoint. This can leak the API key to attacker-controlled infrastructure and enables unauthorized reuse of the credential.

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill instructs the agent to use environment variables, write output files, and make outbound network requests, but it does not declare any explicit tool scope or permissions boundary. This creates a governance and least-privilege gap: an orchestrator or reviewer cannot easily constrain or approve sensitive capabilities before the skill is used.

External Transmission

Medium
Category
Data Exfiltration
Content
1. **Install dependencies.** Run `pip install requests` in the environment that will execute the script. The CLI talks to MiniMax's REST API, so you only need the `requests` library on top of Python 3.11+.
2. **Set your MiniMax credential.** Export `MINIMAX_API_KEY` with the API key the user promised to supply. The script will refuse to run without it.
3. **Use the bundled CLI.** `scripts/minimax_tts.py` exposes two subcommands:
   - `tts`: calls `POST https://api.minimax.io/v1/t2a_v2` (Speech 2.8 T2A HTTP) with the desired voice_id, voice settings, audio configuration, and optional voice effects. Example:
     ```bash
     python scripts/minimax_tts.py tts \
       --text "Tonight in Shenzhen the skies are clear." \
Confidence
83% confidence
Finding
The skill sends user-provided text and an API credential to an external third-party service, which is a real data egress and secret-use boundary. While expected for a TTS integration, it is still security-relevant because sensitive prompts or regulated content could be transmitted off-system without clear consent and endpoint restrictions.

External Transmission

Medium
Category
Data Exfiltration
Content
--output minimax-weather.mp3
     ```
     The script decodes the hex/base64 payload, saves the file, and prints metadata. Override the endpoint with `--endpoint` if you must hit `https://api-uw.minimax.io/v1/t2a_v2` or another region.
   - `voices`: calls `POST https://api.minimax.io/v1/get_voice` to enumerate `system`, `voice_cloning`, `voice_generation`, or `all` categories. Example:
     ```bash
     python scripts/minimax_tts.py voices --voice-type all --print-response
     ```
Confidence
90% confidence
Finding
The `--endpoint` override permits changing the remote destination from the default MiniMax API to another region or potentially any arbitrary URL, increasing the risk of SSRF-like misuse, unintended data exfiltration, or credential exposure to untrusted hosts. This makes the external transmission more dangerous than a fixed, documented API integration.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
When output_format is url, the script blindly fetches whatever URL the API response contains. If the upstream service is compromised, misconfigured, or if a custom endpoint is used, this creates an SSRF-style primitive that can reach unintended internal or external resources beyond the declared MiniMax API interaction.

External Transmission

Medium
Category
Data Exfiltration
Content
if timbre_weights:
        payload["timbre_weights"] = timbre_weights
    try:
        response = requests.post(args.endpoint, headers=headers, json=payload, timeout=args.timeout)
        response.raise_for_status()
    except requests.RequestException as exc:
        fail(f"TTS request failed: {exc}")
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
if timbre_weights:
        payload["timbre_weights"] = timbre_weights
    try:
        response = requests.post(args.endpoint, headers=headers, json=payload, timeout=args.timeout)
        response.raise_for_status()
    except requests.RequestException as exc:
        fail(f"TTS request failed: {exc}")
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
choices=["hex", "url", "base64"],
                             help="How the API returns audio data")
    tts_parser.add_argument("--output", help="Override output file path")
    tts_parser.add_argument("--endpoint", default="https://api.minimax.io/v1/t2a_v2",
                             help="Override MiniMax T2A endpoint")
    tts_parser.add_argument("--timeout", type=int, default=120,
                             help="HTTP timeout in seconds")
Confidence
60% 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
choices=["hex", "url", "base64"],
                             help="How the API returns audio data")
    tts_parser.add_argument("--output", help="Override output file path")
    tts_parser.add_argument("--endpoint", default="https://api.minimax.io/v1/t2a_v2",
                             help="Override MiniMax T2A endpoint")
    tts_parser.add_argument("--timeout", type=int, default=120,
                             help="HTTP timeout in seconds")
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Context-Inappropriate Capability

Medium
Confidence
97% confidence
Finding
The TTS CLI exposes --endpoint as a free-form URL override while still attaching the API bearer token and user-provided text. This expands the tool from a scoped MiniMax helper into a generic outbound HTTP client capable of credential and data exfiltration.

Context-Inappropriate Capability

Medium
Confidence
97% confidence
Finding
The voice catalog command also permits arbitrary endpoint override, allowing authenticated requests to be sent to non-MiniMax destinations. In this skill context, that is more dangerous because the command appears purpose-limited, so users may not expect it can be repurposed for exfiltration.

Missing User Warnings

Low
Confidence
90% confidence
Finding
The skill tells users to save audio and JSON outputs to disk but does not mention overwrite risks, safe output directories, or validation of output paths. In automation contexts, this can lead to accidental overwriting of local files or writing sensitive API responses to unintended locations.

Static analysis

No suspicious patterns detected.