Back to skill

Security audit

Voice For Openclaw Publish

Security checks for vulnerabilities and agentic risk

Overview

This TTS skill matches its stated purpose, but users should know their text/audio may go to MiniMax, Telegram, or Feishu and should protect the required secrets.

Install only if you are comfortable sending TTS text to MiniMax and, when using delivery mode, audio and captions to Telegram or Feishu. Keep MINIMAX_API_KEY and Telegram tokens out of shared folders or repositories, add your own .gitignore for .env, and use --generate-only when you want local audio without message delivery.

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
setup.txt:1
Finding

Credential files are not protected by a repository ignore rule

Content
View full analysis

Vulnerability Details

File Location: setup.txt:1-13, SKILL.md:104-121
Vulnerability Type: Credential exposure through insecure configuration
Risk Level: Medium

Vulnerable Code

setup.txt:1-13:

text
# MiniMax TTS Plus - Environment Variables
# Copy this file to .env and fill in your values.
# NEVER commit .env to version control.

# === Required: MiniMax API (https://api.minimaxi.com) ===
# Get your API Secret Key from: https://platform.minimax.io → Account → API Keys
MINIMAX_API_KEY=your-minimax-secret-key-here

# === Optional: Telegram sending ===
# Only needed if you want to send voice messages to Telegram.
# Get bot token from: https://t.me/BotFather
# Get your chat ID from: https://t.me/useridbot or check @userinfobot
TELEGRAM_BOT_TOKEN=your-telegram-bot-token-here

Relevant documentation in SKILL.md:104-121:

markdown
1. Copy `setup.txt` to `.env` and fill in your credentials:
```bash
cp skills/voice-for-openclaw/setup.txt skills/voice-for-openclaw/.env
# Then edit .env with your real values
  1. The script loads credentials from .env at runtime — no hardcoded tokens in scripts.

⚠️ Security note: Credentials are loaded from .env only — no tokens are hardcoded in shell scripts. The .env file is gitignored and never published.

text

### Technical Analysis

The setup instructions direct users to create a project-local `.env` file containing a MiniMax API secret and, optionally, a Telegram bot token and chat ID. However, the audited project contains no `.gitignore` file or equivalent repository control that excludes `.env`.

The documentation states that `.env` is gitignored and never published, but this assertion is not enforced by the distributed project. A warning inside the template does not prevent Git or other packaging tools from including the credential file.

This is an insecure secret-management practice rather than intentional cre
...[truncated 1436 chars]
Remediation
View remediation

Remediation Suggestions

  1. Add a project-root .gitignore with at least:

    gitignore
    .env
    .env.*
    !.env.example
    
  2. Keep setup.txt or rename it to .env.example, ensuring it contains placeholders only.

  3. Prefer injecting secrets through the process environment or a supported secret manager rather than keeping them in the project directory.

  4. Restrict local credential-file permissions, for example with chmod 600 .env.

  5. Add a startup check that warns when .env has permissions allowing access by other users.

  6. Add secret scanning to continuous integration and pre-commit workflows.

  7. Remove or qualify the statement that .env is “gitignored and never published” unless the repository actually enforces that behavior.

  8. If credentials have already been committed, revoke and rotate them; removing the file from the latest revision alone does not remove it from repository history.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/tts-xiaoye.sh:169
Finding

Telegram delivery failures are unconditionally reported as successful

Content
View full analysis

Vulnerability Details

File Location: scripts/tts-xiaoye.sh:169-190
Vulnerability Type: Improper error handling and false success reporting
Risk Level: Medium

Vulnerable Code

bash
# Default: Telegram voice message (MP3 direct send, no transcoding)
TARGET="${TARGET:-$DEFAULT_TARGET}"
if [[ -z "$TARGET" ]]; then
  echo "❌ Telegram target is empty" >&2
  exit 1
fi

# sendVoice: plain voice bubble; with caption = voice + text display
if [[ -n "$CAPTION" ]]; then
  RESPONSE=$(curl -s -X POST "https://api.telegram.org/bot${BOT_TOKEN}/sendVoice" \
    -F "chat_id=${TARGET}" \
    -F "voice=@${AUDIO_FILE}" \
    -F "caption=${CAPTION}")
else
  RESPONSE=$(curl -s -X POST "https://api.telegram.org/bot${BOT_TOKEN}/sendVoice" \
    -F "chat_id=${TARGET}" \
    -F "voice=@${AUDIO_FILE}")
fi

printf '{"ok":true,"mode":"send-voice","target":"%s","audio_file":"%s","voice":"%s","caption":"%s"}\n' \
  "$TARGET" "$AUDIO_FILE" "$VOICE" "$CAPTION"

Technical Analysis

The script validates the Telegram target but does not verify that BOT_TOKEN is populated before constructing the request URL. It captures Telegram's response in RESPONSE but never examines it.

The use of curl -s suppresses diagnostic output and does not treat ordinary HTTP error status codes as failures. Even when Telegram returns a JSON response with "ok": false, the script discards that response and unconditionally emits its own JSON containing "ok": true.

Consequently, invalid or revoked credentials, rejected media, invalid chat identifiers, Telegram API errors, and some network failures can be hidden from the calling Agent. The issue is especially relevant because the script's JSON output is intended for consumption by other automation.

The output is also manually constructed with printf without JSON escaping. User-controlled captions, voice identifiers, or target values containing quotes, backslashes, or con ...[truncated 1687 chars]

Remediation
View remediation

Remediation Suggestions

  1. Validate both required Telegram parameters before sending:

    bash
    if [[ -z "$BOT_TOKEN" ]]; then
      echo '{"ok":false,"error":"TELEGRAM_BOT_TOKEN is not configured"}' >&2
      exit 1
    fi
    
  2. Invoke curl with explicit transport and HTTP failure handling:

    bash
    RESPONSE=$(curl --fail-with-body --show-error --silent \
      --connect-timeout 10 --max-time 120 \
      -X POST "https://api.telegram.org/bot${BOT_TOKEN}/sendVoice" \
      -F "chat_id=${TARGET}" \
      -F "voice=@${AUDIO_FILE}") || {
        echo '{"ok":false,"error":"Telegram request failed"}' >&2
        exit 1
      }
    
  3. Parse the response with a real JSON parser and require Telegram's ok property to equal true.

  4. Return a nonzero exit status and an "ok": false result whenever Telegram rejects the request.

  5. Generate all status output with Python, jq, or another JSON serializer rather than interpolating unescaped strings with printf.

  6. Do not print the bot token or complete request URL in diagnostics, because the Telegram token is embedded in the URL path.

  7. Add tests covering missing tokens, invalid targets, HTTP failures, Telegram "ok": false responses, network timeouts, and captions containing quotes or control characters.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (19)

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding

The description emphasizes MiniMax TTS, but the skill also references direct Telegram delivery, extra credentials, and auxiliary modes such as generate-only and voice listing. This mismatch matters because reviewers and users may consent to audio generation without realizing the skill can also transmit content to third-party messaging services using additional secrets.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
89% confidence
Finding

The description emphasizes MiniMax TTS, but the skill also references direct Telegram delivery, extra credentials, and auxiliary modes such as generate-only and voice listing. This mismatch matters because reviewers and users may consent to audio generation without realizing the skill can also transmit content to third-party messaging services using additional secrets.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/tts-xiaoye.sh (reported line 25)May include surrounding context.

sh
WORKSPACE_DIR = os.path.expanduser("~/.openclaw/workspace")
SKILL_DIR = os.path.join(WORKSPACE_DIR, "skills", "voice-for-openclaw")
DEFAULT_OUTPUT_DIR = os.path.join(WORKSPACE_DIR, "generated", "tmp")
ENV_FILE = os.path.join(SKILL_DIR, ".env")

def load_env_file(path):
    """Load KEY=VALUE pairs from .env file (simple format only)."""

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/tts.py (reported line 19)May include surrounding context.

python
WORKSPACE_DIR = os.path.expanduser("~/.openclaw/workspace")
SKILL_DIR = os.path.join(WORKSPACE_DIR, "skills", "voice-for-openclaw")
DEFAULT_OUTPUT_DIR = os.path.join(WORKSPACE_DIR, "generated", "tmp")
ENV_FILE = os.path.join(SKILL_DIR, ".env")

def load_env_file(path):
    """Load KEY=VALUE pairs from .env file (simple format only)."""

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

md
# MiniMax TTS Plus - Environment Variables
# Copy this file to .env and fill in your values.
# NEVER commit .env to version control.

# === Required: MiniMax API (https://api.minimaxi.com) ===

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

md
# MiniMax TTS Plus - Environment Variables
# Copy this file to .env and fill in your values.
# NEVER commit .env to version control.

# === Required: MiniMax API (https://api.minimaxi.com) ===

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/tts-xiaoye.sh (reported line 24)May include surrounding context.

sh
# MiniMax TTS Plus - Environment Variables
# Copy this file to .env and fill in your values.
# NEVER commit .env to version control.

# === Required: MiniMax API (https://api.minimaxi.com) ===

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/tts.py (reported line 22)May include surrounding context.

python
# MiniMax TTS Plus - Environment Variables
# Copy this file to .env and fill in your values.
# NEVER commit .env to version control.

# === Required: MiniMax API (https://api.minimaxi.com) ===

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/tts.py (reported line 40)May include surrounding context.

python
# MiniMax TTS Plus - Environment Variables
# Copy this file to .env and fill in your values.
# NEVER commit .env to version control.

# === Required: MiniMax API (https://api.minimaxi.com) ===

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/tts.py (reported line 46)May include surrounding context.

python
# MiniMax TTS Plus - Environment Variables
# Copy this file to .env and fill in your values.
# NEVER commit .env to version control.

# === Required: MiniMax API (https://api.minimaxi.com) ===

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · setup.txt (reported line 2)May include surrounding context.

text
# MiniMax TTS Plus - Environment Variables
# Copy this file to .env and fill in your values.
# NEVER commit .env to version control.

# === Required: MiniMax API (https://api.minimaxi.com) ===

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · setup.txt (reported line 3)May include surrounding context.

text
# MiniMax TTS Plus - Environment Variables
# Copy this file to .env and fill in your values.
# NEVER commit .env to version control.

# === Required: MiniMax API (https://api.minimaxi.com) ===

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill advertises capabilities that include environment access, file reads, shell execution, and network use, but it does not declare an explicit tool/permission scope. In an agent ecosystem, this weakens least-privilege boundaries and can allow a TTS skill to exercise broader powers than users or reviewers expect.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
83% confidence
Finding

The activation/stop instruction tells users to say the Chinese phrases "文字模式" or "关闭语音" to stop voice generation, which imposes a language-specific control path. While the file contains bilingual documentation, it does not clearly state that equivalent stop commands are available in other languages or that language choice is optional.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
95% confidence
Finding

This script sends generated audio and optional caption text to Telegram via the public Bot API, which is an external transmission of potentially sensitive user content. In a TTS skill this behavior is expected, but it is still security-relevant because user-provided text and derived audio leave the local environment and are delivered to a third-party service and chat target.

Content

Scanner excerpt · scripts/tts-xiaoye.sh (reported line 179)May include surrounding context.

sh
# sendVoice: plain voice bubble; with caption = voice + text display
if [[ -n "$CAPTION" ]]; then
  RESPONSE=$(curl -s -X POST "https://api.telegram.org/bot${BOT_TOKEN}/sendVoice" \
    -F "chat_id=${TARGET}" \
    -F "voice=@${AUDIO_FILE}" \
    -F "caption=${CAPTION}")

External Transmission

Medium
Category
Data Exfiltration
Confidence
95% confidence
Finding

This is the same outbound Telegram transmission path in the no-caption branch, sending the generated voice file to Telegram. Even though this is functional behavior for the skill, it creates an exfiltration path for any text converted to speech and should be treated as a real data transfer risk.

Content

Scanner excerpt · scripts/tts-xiaoye.sh (reported line 184)May include surrounding context.

sh
-F "voice=@${AUDIO_FILE}" \
    -F "caption=${CAPTION}")
else
  RESPONSE=$(curl -s -X POST "https://api.telegram.org/bot${BOT_TOKEN}/sendVoice" \
    -F "chat_id=${TARGET}" \
    -F "voice=@${AUDIO_FILE}")
fi

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/tts.py (reported line 70)May include surrounding context.

python
data = {"voice_type": "all"}

    try:
        resp = requests.post(url, headers=headers, json=data, timeout=30)
        resp.raise_for_status()
        result = resp.json()

External Transmission

Medium
Category
Data Exfiltration
Confidence
85% confidence
Finding

This call transmits arbitrary input text to a third-party TTS service along with an API credential. In a skill context, user or agent text may contain secrets, internal prompts, or sensitive business data, so sending it off-box creates a real confidentiality risk even though it is part of intended functionality.

Content

Scanner excerpt · scripts/tts.py (reported line 129)May include surrounding context.

python
try:
        print(f"Generating speech...", file=sys.stderr)
        resp = requests.post(url, headers=headers, json=data, timeout=120)
        resp.raise_for_status()
        result = resp.json()

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The setup section states that credentials are loaded from .env only and emphasizes that .env is the source of secrets. However, the manifest metadata explicitly declares MINIMAX_API_KEY, TELEGRAM_BOT_TOKEN, and TELEGRAM_TARGET as environment variables, indicating the skill is designed to consume process environment values directly rather than exclusively from .env. This is a documentation-to-configuration contradiction about how secrets are sourced.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.