Back to skill

Security audit

Kai Realtime Voice

Security checks for vulnerabilities and agentic risk

Overview

The skill is a MiniMax text-to-speech helper, but it is advertised as real-time WebSocket streaming while the inspected script actually makes non-streaming REST calls and saves a fixed local MP3 file.

Review before installing. Use this only with non-sensitive text you are comfortable sending to MiniMax under your API key, and avoid running it in shared or privileged environments. The publisher should either implement true WebSocket streaming or relabel it as a REST text-to-audio file generator, add clear data-transfer disclosure, JSON-safe request construction, and safer output-file handling.

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

Warning
Location
scripts/kai_realtime.sh:32
Finding

Unescaped User Input Allows JSON Request Manipulation

Content
View full analysis

Vulnerability Details

File Location: scripts/kai_realtime.sh, lines 32–41
Vulnerability Type: Unsafe JSON construction with untrusted input
Risk Level: Medium

Vulnerable Code

bash
TEXT="$2"
VOICE_ID="${KAI_ENGLISH_VOICE_ID:-moss_audio_2b525bea-10da-11f1-bd2a-3a1ec25b94c4}"

if [ -z "$TEXT" ]; then
    echo "Usage: $0 --stream \"text\""
    exit 1
fi

echo "Streaming text: $TEXT"

# For real streaming, would use WebSocket here
# For now, fallback to REST API
RESP=$(curl -s -X POST "https://api.minimax.io/v1/t2a_v2" \
    -H "Authorization: Bearer ${API_KEY}" \
    -H "Content-Type: application/json" \
    -d "{\"model\":\"speech-02-turbo\",\"text\":\"$TEXT\",\"stream\":false,\"output_format\":\"hex\",\"voice_setting\":{\"voice_id\":\"$VOICE_ID\",\"speed\":1},\"audio_setting\":{\"sample_rate\":32000}}")

Technical Analysis

The script constructs a JSON request by directly interpolating TEXT and VOICE_ID into a double-quoted string. Neither value is encoded using a JSON-aware serializer.

Shell quoting prevents these values from being interpreted as shell commands, so this is not shell command injection. However, quotation marks, backslashes, control characters, or JSON delimiters in either value can terminate the intended JSON string, add properties, create duplicate properties, or make the request invalid.

The concrete result depends on how the MiniMax endpoint handles unknown or duplicate JSON properties. At minimum, legitimate text containing quotation marks or other special characters can cause malformed requests. If the service accepts injected or duplicate properties, crafted input may alter request behavior.

Attack Path

  1. An attacker or untrusted caller controls the second argument passed to --stream.
  2. The attacker includes JSON syntax, such as embedded quotation marks and additional properties, in that argument.
  3. The script inserts the value directly i ...[truncated 925 chars]
Remediation
View remediation

Remediation Suggestions

Construct the payload with a JSON-aware serializer rather than shell string interpolation. For example, use jq:

bash
PAYLOAD=$(jq -n \
    --arg text "$TEXT" \
    --arg voice_id "$VOICE_ID" \
    '{
        model: "speech-02-turbo",
        text: $text,
        stream: false,
        output_format: "hex",
        voice_setting: {
            voice_id: $voice_id,
            speed: 1
        },
        audio_setting: {
            sample_rate: 32000
        }
    }')

RESP=$(curl --fail-with-body --silent --show-error \
    -X POST "https://api.minimax.io/v1/t2a_v2" \
    -H "Authorization: Bearer ${API_KEY}" \
    -H "Content-Type: application/json" \
    --data-binary "$PAYLOAD")

Additionally:

  • Validate VOICE_ID against the character set and length accepted by MiniMax.
  • Apply a reasonable maximum length to TEXT.
  • Handle HTTP failures explicitly with --fail-with-body.
  • Avoid printing sensitive user-supplied text unless operational logging requires it.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/kai_realtime.sh:45
Finding

Predictable Output File Permits Symbolic-Link File Clobbering

Content
View full analysis

Vulnerability Details

File Location: scripts/kai_realtime.sh, lines 45–47
Vulnerability Type: Unsafe predictable file creation and symbolic-link following
Risk Level: Medium

Vulnerable Code

bash
if [ -n "$HEX" ]; then
    mkdir -p "$WORKSPACE"
    echo "$HEX" | xxd -r -p > "${WORKSPACE}/realtime_test.mp3"
    echo "Saved: ${WORKSPACE}/realtime_test.mp3"

Technical Analysis

The generated audio is always written to the predictable path ${WORKSPACE}/realtime_test.mp3. Shell redirection opens that path with truncation and follows an existing symbolic link. The script does not verify that the workspace is trusted, that the destination is a regular file, or that the path did not change between validation and use.

WORKSPACE can also be selected through KAI_MINIMAX_WORKSPACE. Risk is highest when the script runs with elevated privileges, through an automation account, or with a workspace directory writable by another principal. An attacker who can prepare the destination can replace it with a symbolic link to another file writable by the script's execution identity.

Attack Path

  1. The attacker obtains write access to the configured workspace directory, or influences KAI_MINIMAX_WORKSPACE in the execution environment.
  2. The attacker creates realtime_test.mp3 as a symbolic link to a target file.
  3. The attacker or another user causes the script to execute a successful --stream request.
  4. The redirection operator follows the symbolic link and truncates the target.
  5. Decoded API response bytes are written into the target file with the privileges of the process running the skill.

Exploitation requires the attacker to control or write to the selected workspace before the write occurs. It does not independently grant access to files that the script's execution identity cannot write.

Impact Assessment

A successful attack can corrupt or replace any file writable by the acc ...[truncated 390 chars]

Remediation
View remediation

Remediation Suggestions

Use a private workspace and create output files securely:

  • Ensure the workspace is owned by the executing user and is not writable by other users.
  • Set a restrictive umask, such as umask 077.
  • Create a unique output with mktemp rather than using a predictable filename.
  • Reject symbolic links and non-regular destinations.
  • Write to a securely created temporary file and atomically rename it when complete.
  • Avoid executing this script with elevated privileges.

Example hardening:

bash
umask 077
mkdir -p -- "$WORKSPACE"
chmod 700 -- "$WORKSPACE"

TMP_FILE=$(mktemp "${WORKSPACE}/realtime.XXXXXX.mp3")
printf '%s' "$HEX" | xxd -r -p > "$TMP_FILE"
printf 'Saved: %s\n' "$TMP_FILE"

If a fixed final filename is required, verify workspace ownership and permissions, securely create a temporary file in the same directory, and use an atomic replacement strategy that does not follow an attacker-created symbolic link.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (11)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill claims real-time WebSocket streaming and low-latency conversational behavior, but the associated behavior reportedly uses one-shot REST calls, non-streaming output, and local file saving instead. This mismatch is security-relevant because users may authorize the skill under false assumptions about its data flows, timing, and interaction model, which undermines informed consent and review of external transmission and local artifact creation.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill advertises shell-based usage but declares no tool scope such as permissions or allowed-tools. In agent environments, this can cause the skill to run with broader-than-expected execution capability, reducing policy enforcement and making command execution less transparent to users and reviewers.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script advertises "Testing MiniMax WebSocket connection" and labels the feature as "Stream text to audio," but the operational code uses the REST /v1/t2a_v2 endpoint rather than a WebSocket connection. This is an active contradiction between the documented intent and implemented behavior, not merely an omitted detail.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
88% confidence
Finding

The script transmits data and an API bearer token to an external third-party service. In this skill context, external transmission is expected for TTS, but it still carries privacy and supply-chain risk because user text and credentials leave the local environment, and the behavior is presented as a connectivity test without clearly emphasizing outbound data transfer.

Content

Scanner excerpt · scripts/kai_realtime.sh (reported line 18)May include surrounding context.

sh
--test)
        echo "Testing MiniMax WebSocket connection..."
        # Test basic connectivity to API
        RESP=$(curl -s -o /dev/null -w "%{http_code}" "https://api.minimax.io/v1/t2a_v2" \
            -H "Authorization: Bearer ${API_KEY}" \
            -H "Content-Type: application/json" \
            -d '{"model":"speech-02-turbo","text":"test","stream":false,"output_format":"mp3"}')

External Transmission

Medium
Category
Data Exfiltration
Confidence
88% confidence
Finding

The script transmits data and an API bearer token to an external third-party service. In this skill context, external transmission is expected for TTS, but it still carries privacy and supply-chain risk because user text and credentials leave the local environment, and the behavior is presented as a connectivity test without clearly emphasizing outbound data transfer.

Content

Scanner excerpt · scripts/kai_realtime.sh (reported line 18)May include surrounding context.

sh
--test)
        echo "Testing MiniMax WebSocket connection..."
        # Test basic connectivity to API
        RESP=$(curl -s -o /dev/null -w "%{http_code}" "https://api.minimax.io/v1/t2a_v2" \
            -H "Authorization: Bearer ${API_KEY}" \
            -H "Content-Type: application/json" \
            -d '{"model":"speech-02-turbo","text":"test","stream":false,"output_format":"mp3"}')

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The variable name and default behavior explicitly bias the skill toward English output, and the script does not provide a user opt-in or selection mechanism for other languages or locales. This is a natural-language policy concern because it forces a specific language setting by default rather than letting the user choose.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The manifest description specifically claims low-latency real-time voice streaming via the MiniMax WebSocket API. However, the code explicitly states it does not use WebSocket and instead falls back to a non-streaming REST call with "stream":false, then writes the returned audio to disk as a file.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
92% confidence
Finding

The main code path sends arbitrary user-provided text to a remote API together with an authorization token, creating a clear external data exfiltration channel. This is contextually expected for a voice-generation skill, but it remains security-relevant because sensitive input may be transmitted off-host and the script performs no filtering, warning, or policy enforcement around what text is sent.

Content

Scanner excerpt · scripts/kai_realtime.sh (reported line 42)May include surrounding context.

sh
# For real streaming, would use WebSocket here
        # For now, fallback to REST API
        RESP=$(curl -s -X POST "https://api.minimax.io/v1/t2a_v2" \
            -H "Authorization: Bearer ${API_KEY}" \
            -H "Content-Type: application/json" \
            -d "{\"model\":\"speech-02-turbo\",\"text\":\"$TEXT\",\"stream\":false,\"output_format\":\"hex\",\"voice_setting\":{\"voice_id\":\"$VOICE_ID\",\"speed\":1},\"audio_setting\":{\"sample_rate\":32000}}")

External Transmission

Medium
Category
Data Exfiltration
Confidence
92% confidence
Finding

The main code path sends arbitrary user-provided text to a remote API together with an authorization token, creating a clear external data exfiltration channel. This is contextually expected for a voice-generation skill, but it remains security-relevant because sensitive input may be transmitted off-host and the script performs no filtering, warning, or policy enforcement around what text is sent.

Content

Scanner excerpt · scripts/kai_realtime.sh (reported line 42)May include surrounding context.

sh
# For real streaming, would use WebSocket here
        # For now, fallback to REST API
        RESP=$(curl -s -X POST "https://api.minimax.io/v1/t2a_v2" \
            -H "Authorization: Bearer ${API_KEY}" \
            -H "Content-Type: application/json" \
            -d "{\"model\":\"speech-02-turbo\",\"text\":\"$TEXT\",\"stream\":false,\"output_format\":\"hex\",\"voice_setting\":{\"voice_id\":\"$VOICE_ID\",\"speed\":1},\"audio_setting\":{\"sample_rate\":32000}}")

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

The skill states that an API key is auto-injected and implies external network use, but it does not warn users that prompts or audio-related content may be transmitted to a third-party service under stored credentials. This weakens transparency around credential use and data egress, increasing the chance of accidental disclosure of sensitive content to an external provider.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

In the --stream branch, the script creates a workspace directory and writes realtime_test.mp3 to disk, but the only disclosure comes after the write occurs. For a code file, file writes that affect user storage should have some visible prior disclosure unless clearly communicated as part of the operation.

Content

No source excerpt is available for this finding.