Back to skill

Security audit

KittenTTS WhatsApp

Security checks for vulnerabilities and agentic risk

Overview

The skill has a coherent audio purpose, but its install instructions and scripts create avoidable system-wide and code-execution risks.

Review this skill carefully before installing. Use a virtual environment, pin and verify dependencies, avoid --break-system-packages where possible, do not run the runtime scripts as root, avoid storing tokens in ~/.bashrc unless you accept that persistence, and fix the heredoc/input handling and temporary-file usage before processing untrusted text or audio.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/tts_walkie.sh:27
Finding
Arbitrary Command Execution Through Unquoted Heredoc Expansion<![CDATA[ ## Vulnerability Details **File Location**: `scripts/tts_walkie.sh`, lines 27-39 **Vulnerability Type**: Shell command injection and generated Python source injection **Risk Level**: High ### Vulnerable Code ```bash python3 << PYEOF from kittentts import KittenTTS import numpy as np, soundfile as sf, subprocess, sys, os text = """$TEXT""" voice = "$VOICE" speed = float("$VOICE_SPEED") tts = KittenTTS("KittenML/kitten-tts-mini-0.8") audio = tts.generate(text, voice=voice, speed=speed) # speed now actually used wav_path = "$WAV_PATH" ogg_path = "$OGG_PATH" ``` ### Technical Analysis The heredoc delimiter `PYEOF` is not quoted. Bash therefore performs parameter expansion, command substitution, and related shell processing on the heredoc body before passing it to Python. The attacker-controlled or externally influenced values `TEXT`, `VOICE`, and `VOICE_SPEED` are embedded directly in this body. A value containing shell command substitution, such as `$(command)`, causes the command to run in Bash before Python starts. Quotation marks surrounding the expanded values do not prevent this processing because they are heredoc content rather than shell syntax protecting the expansion. Directly embedding these values into Python source also creates a second injection surface. Crafted quotes, backslashes, or newline sequences can terminate the intended Python string and introduce arbitrary Python statements. The skill metadata identifies the skill as privileged because of its installation requirements. Although these scripts do not elevate privileges themselves, command injection obtains all privileges of whichever account invokes the script. Running it as root would therefore turn this into root-level arbitrary command execution. ### Attack Path 1. An attacker supplies or influences the text, voice argument, or `VOICE_SPEED` environment variable passed to `tts_walkie.sh`. 2. The malicious value contains command substitution, for example a value struct ...[truncated 962 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Quote the heredoc delimiter so Bash does not expand its contents. - Pass user-controlled values as command-line arguments or environment variables rather than generating Python source from them. - Restrict `VOICE` to the documented allowlist. - Parse `VOICE_SPEED` as a numeric value and enforce safe minimum and maximum bounds. - Avoid invoking the runtime script with root privileges. A safer pattern is: ```bash python3 - "$TEXT" "$VOICE" "$VOICE_SPEED" "$WAV_PATH" "$OGG_PATH" <<'PYEOF' from kittentts import KittenTTS import soundfile as sf import subprocess import sys text, voice, speed_raw, wav_path, ogg_path = sys.argv[1:] allowed_voices = { "Bella", "Jasper", "Luna", "Bruno", "Rosie", "Hugo", "Kiki", "Leo" } if voice not in allowed_voices: raise SystemExit("Invalid voice") try: speed = float(speed_raw) except ValueError: raise SystemExit("Invalid voice speed") if not 0.5 <= speed <= 2.0: raise SystemExit("Voice speed is outside the permitted range") tts = KittenTTS("KittenML/kitten-tts-mini-0.8") audio = tts.generate(text, voice=voice, speed=speed) sf.write(wav_path, audio, 24000) subprocess.run( [ "ffmpeg", "-y", "-i", wav_path, "-ar", "16000", "-ac", "1", "-c:a", "libopus", "-b:a", "128k", ogg_path ], check=True ) PYEOF ``` ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/tts_walkie.sh:11
Finding
Predictable Temporary Paths Permit Symlink and File-Clobbering Attacks<![CDATA[ ## Vulnerability Details **File Location**: `scripts/tts_walkie.sh`, lines 11-14 and 20-22 **Vulnerability Type**: Unsafe temporary-file handling **Risk Level**: High ### Vulnerable Code ```bash TMP_DIR="/tmp/kittentts-walkie" WAV_PATH="$TMP_DIR/tts_raw.wav" OGG_PATH="$TMP_DIR/walkie_reply.ogg" if [ -z "$TEXT" ]; then echo "Usage: tts_walkie.sh \"Your text\" [voice]" exit 1 fi # Create private temp dir (mode 700) mkdir -p "$TMP_DIR" chmod 700 "$TMP_DIR" ``` A second predictable temporary path is used in `scripts/transcribe.sh`, line 31: ```python wav_path = "/tmp/whisper_input.wav" ``` ### Technical Analysis The scripts use fixed, globally predictable names under the shared `/tmp` directory. The TTS script calls `mkdir -p` and only applies mode `700` afterward. Directory creation and permission hardening are not atomic, and the script does not verify that the existing object is a genuine directory owned by the invoking account rather than an attacker-created path. The files `tts_raw.wav`, `walkie_reply.ogg`, and `/tmp/whisper_input.wav` are subsequently opened for overwrite. An attacker with access to the same host can pre-create predictable paths or symbolic links before the victim executes the scripts. If the destination-writing library or tool follows the prepared link, output can be redirected to another file writable by the victim. Fixed names also create cross-run interference: concurrent invocations can overwrite or consume each other's audio. The transcription path is not placed in a private directory at all, increasing exposure to other local users. Applying `chmod 700` after `mkdir -p` does not eliminate the issue. If an unsafe object already exists, the script may alter it or continue using it without validating ownership and type. ### Attack Path 1. A local attacker predicts the fixed paths used by the scripts. 2. Before the victim invokes a script, the attacker pre-creates `/tmp/kittentts-walkie`, one of its output nam ...[truncated 1090 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Set `umask 077` before creating any temporary data. - Create a unique directory atomically with `mktemp -d`. - Register an exit trap that removes the unique directory on success, error, or interruption. - Keep both WAV and OGG files inside that directory. - Do not use a shared fixed transcription filename. - Refuse to operate on unexpected existing objects and avoid privileged execution. - If a stable final output name is required, copy it securely only after processing and document that concurrent calls require distinct destinations. Example: ```bash umask 077 TMP_DIR="$(mktemp -d "${TMPDIR:-/tmp}/kittentts-walkie.XXXXXXXX")" || exit 1 trap 'rm -rf -- "$TMP_DIR"' EXIT HUP INT TERM WAV_PATH="$TMP_DIR/tts_raw.wav" OGG_PATH="$TMP_DIR/walkie_reply.ogg" ``` The transcription script should receive a unique WAV path created inside its own `mktemp -d` directory instead of using `/tmp/whisper_input.wav`. ]]>

T08 · Insecure Dependencies

Warning
Location
SKILL.md:55
Finding
Unpinned Packages Are Installed Into the System Python Environment<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 55-62 and 78-83 **Vulnerability Type**: Unsafe and mutable third-party dependency installation **Risk Level**: Medium ### Vulnerable Code ```bash # 1. System package (requires root/privileged) apt-get install -y ffmpeg # 2. Python package pip3 install kittentts --break-system-packages # 3. Optional: set Hugging Face token to avoid rate limits # echo 'export HF_TOKEN="hf_your_token_here"' >> ~/.bashrc ``` The optional transcription instructions similarly state: ```bash # Install whisper (one-time, ~140MB-1.4GB depending on model) pip3 install whisper --break-system-packages bash scripts/transcribe.sh /path/to/audio.ogg [model] ``` ### Technical Analysis The installation commands retrieve Python packages without pinned versions or verified hashes. Consequently, the code installed for the same documented command can change after the skill has been reviewed. Package installation can execute build-system and installation logic, so a compromised registry account, malicious release, or unsafe transitive dependency could execute code during installation. The `--break-system-packages` option bypasses protections intended to prevent `pip` from modifying a distribution-managed Python environment. This can replace or conflict with packages required by operating-system tools and other applications. The package name `whisper` is also ambiguous relative to the commonly intended OpenAI Whisper distribution. The documentation does not establish the publisher, exact release, artifact hash, or verified source. Installing a similarly named or unintended distribution creates package-confusion risk. The audit found no evidence that the currently intended dependencies are malicious. The finding concerns the unsafe, mutable installation mechanism and insufficient dependency identity verification. ### Attack Path 1. An administrator follows the documented setup instructions, potentially using a privile ...[truncated 987 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Install Python dependencies in a dedicated virtual environment rather than the system interpreter. - Remove `--break-system-packages` from the documented workflow. - Verify the exact intended package names and publishers, especially for Whisper. - Pin direct and transitive dependency versions in a lock file. - Require hashes for downloaded artifacts, for example through a hash-locked requirements file and `pip install --require-hashes`. - Use a trusted, explicitly configured package index and review dependency provenance. - Install dependencies as an unprivileged account. - Pin the system package to an approved repository/version according to the deployment platform's package-management policy. - Document and verify the separately downloaded Hugging Face model revision where supported, rather than relying on a mutable model identifier. A hardened installation model would use a project-specific virtual environment and reviewed lock file: ```bash python3 -m venv .venv . .venv/bin/activate python -m pip install --upgrade pip python -m pip install --require-hashes -r requirements.lock ``` ]]>
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (4)

YARA rule 'backdoor_persistence': Backdoor persistence with malicious payloads (shell commands, SSH key injection, hidden root users) [malware]

High
Category
YARA Match
Content
| 80M | 80MB | `KittenML/kitten-tts-mini-0.8` |

Default: `kitten-tts-mini-0.8` (best quality). Change in `scripts/tts_walkie.sh`.

## Setup

Run these manually before the skill is used:

```bash
# 1. System package (requires root/privileged)
apt-get install -y ffmpeg

# 2. Python package
pip3 install kittentts --break-system-packages

# 3. Optional: set Hugging Face token to avoid rate limits
# echo 'export HF_TOKEN="hf_your_token_here"' >> ~/.bashrc
```

**Restart OpenClaw** after installing dependencies so the new packages are in PATH.

## Usage

### TTS only (no transcription)

```bash
bash scripts/tts_walkie.sh "Your message here" Bella
# Output: /tmp/walkie_reply.ogg (16kHz OGG Opus, WhatsApp-ready)
```

### Transcription only (optional — requires whisper)

```bash
# Install whisper (one-time, ~140MB-1.4GB depending on model)
pip3 install whisper --break-system-packages

bash scripts/transcribe.sh /path/to/audio.ogg [model]
# Model: tiny | base | small | medium | large (defaul
Confidence
75% confidence
Finding
YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
## ⚠️ Privileged Install Warning

The dependency install commands use `--break-system-packages` and `apt-get install -y`. These require root privileges and modify system packages. Review before running if you are on a managed system.

## Troubleshooting
Confidence
60% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
The whisper invocation hard-codes `--language en`, which imposes an English-only locale choice regardless of the input audio or user preference. This is a natural-language policy concern because it restricts language handling without offering opt-in, configurability, or a documented region-specific justification.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
# Create private temp dir (mode 700)
mkdir -p "$TMP_DIR"
chmod 700 "$TMP_DIR"

echo "[TTS] Generating: $TEXT"
echo "[TTS] Voice: $VOICE, Speed: $VOICE_SPEED"
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Static analysis

No suspicious patterns detected.