Back to skill

Security audit

Voice TTS/ASR

Security checks for vulnerabilities and agentic risk

Overview

This voice skill mostly matches its advertised ASR/TTS and Telegram purpose, but it needs Review because some scripts mix user speech with agent instructions and use unsafe code/config handling.

Install only after reviewing the scripts and accepting that voice text/audio may be sent to Edge TTS and Telegram, Telegram bot tokens may be read from local config or environment variables, and inbound audio can be moved then deleted after transcription. Avoid untrusted installer arguments, protect ~/.openclaw/openclaw.json and bot tokens, and treat this package as needing fixes for JSON parsing, ASR output isolation, dependency pinning, and the missing helper scripts before broad use.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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 (4)

T01 · Skill Instruction Hijacking

Error
Location
bin/voice-asr.mjs:117
Finding
ASR Output Injects Mandatory Instructions into the Agent Session<![CDATA[ ## Vulnerability Details **File Location**: `bin/voice-asr.mjs`, lines 117-121 **Vulnerability Type**: Agent instruction injection through tool output **Risk Level**: Critical ### Vulnerable Code ```javascript const voiceMessage = `【语音消息】 执行要求:必须按照 voice-tts skill 的规则执行,回复需调用 send_voice_reply.mjs 返回语音+文字双通道格式 语音内容:${stdout.trim()}`; process.stdout.write(voiceMessage); ``` The embedded instruction tells the agent that it must follow the Skill's rules and invoke `send_voice_reply.mjs` to return both voice and text. ### Technical Analysis The ASR entry point does not return the transcription as isolated, untrusted data. Instead, it constructs an instruction-bearing message that imposes mandatory behavior on the consuming agent. The untrusted transcription in `stdout` is concatenated directly after this instruction. Consequently, tool output contains both privileged-looking operational instructions and attacker-controlled audio content without a structured trust boundary. If the surrounding agent interprets tool output as instructions, this can alter the current session's behavior and cause additional tool invocation. This is instruction hijacking rather than ordinary ASR formatting because the output explicitly directs the agent to execute another script and adopt a prescribed response format. ### Attack Path 1. An attacker submits an audio message for transcription. 2. The OpenClaw media integration invokes `bin/voice-asr.mjs`. 3. Whisper converts the attacker-controlled audio into text. 4. The script combines the transcription with a mandatory directive requiring the agent to invoke `send_voice_reply.mjs`. 5. The agent consumes the resulting output as part of its active context. 6. The agent may follow the embedded directive and initiate TTS or outbound messaging. 7. Additional instructions spoken in the audio may be interpreted in the same instruction-bearing context, further influencing downstream agent behavior. ### Impact Assessment Succe ...[truncated 690 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove all agent-facing commands from ASR output. 2. Return transcription as structured data with an explicit untrusted-data field, for example: ```javascript process.stdout.write(JSON.stringify({ type: 'transcription', text: stdout.trim() })); ``` 3. Ensure the consuming agent treats `text` exclusively as user content, never as system or developer instructions. 4. Do not instruct the agent to invoke `send_voice_reply.mjs` from tool output. Voice-response selection should be controlled by trusted application policy outside the transcription. 5. Apply explicit prompt-injection boundaries around transcribed audio and require user confirmation before performing sensitive outbound actions. 6. Add tests confirming that transcribed phrases resembling commands cannot alter tool-selection policy. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
install.sh:73
Finding
Arbitrary Python Code Injection Through the Installer Model Argument<![CDATA[ ## Vulnerability Details **File Location**: `install.sh`, lines 16-22 and 73-80 **Vulnerability Type**: Code injection through generated Python source **Risk Level**: High ### Vulnerable Code ```bash MODEL="turbo" PROXY="" while [[ $# -gt 0 ]]; do case "$1" in --model) MODEL="$2"; shift 2 ;; --proxy) PROXY="$2"; shift 2 ;; *) echo "未知参数: $1"; exit 1 ;; esac done ``` ```bash python3 - <<EOF import whisper print(f"下载模型: $MODEL ...") whisper.load_model("$MODEL") print("下载完成 ✓") EOF ``` ### Technical Analysis The user-controlled `--model` value is interpolated directly into executable Python source inside an unquoted shell heredoc. No allowlist validation or Python-string escaping is applied. Shell quoting around the original command-line argument does not make this safe because the value is subsequently inserted into Python syntax. An attacker can supply quote characters and Python statements that terminate the intended string literal and execute arbitrary code. For example, a specially constructed model value could close the argument to `whisper.load_model`, insert a call such as `os.system(...)`, and comment out the remaining generated source. The precise payload must account for both interpolation points, but both are generated from the same unrestricted value and are therefore injectable. ### Attack Path 1. An attacker convinces a user or automation process to run `install.sh` with an attacker-controlled `--model` argument. 2. The argument parser stores the value in `MODEL` without validating it against supported Whisper model names. 3. The shell expands `$MODEL` into the heredoc. 4. The expanded heredoc is passed to `python3` as executable source code. 5. Injected Python statements execute with the privileges of the user running the installer. 6. If the installer is run in a privileged administrative context, the injected payload inherits those privileges. ### Impact Assessment An attacker who controls the installer argume ...[truncated 601 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Enforce a strict allowlist before using the model value: ```bash case "$MODEL" in tiny|base|small|turbo|large-v3) ;; *) err "Unsupported Whisper model" ;; esac ``` 2. Never generate Python source by interpolating user input. Pass the value as a positional argument: ```bash python3 - "$MODEL" <<'PY' import sys import whisper model = sys.argv[1] allowed = {"tiny", "base", "small", "turbo", "large-v3"} if model not in allowed: raise SystemExit("Unsupported Whisper model") print(f"Downloading model: {model} ...") whisper.load_model(model) print("Download complete") PY ``` 3. Validate that options expecting values actually have a following argument before reading `$2`. 4. Avoid running the full installer as root. Elevate only the individual package-manager operation that requires administrative privileges. 5. Add negative tests using quotes, newlines, shell metacharacters, and Python syntax in `--model`. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
lib/config.mjs:31
Finding
OpenClaw Configuration Is Evaluated as JavaScript Instead of Parsed as JSON<![CDATA[ ## Vulnerability Details **File Location**: `lib/config.mjs`, lines 31-36; `scripts/send_voice_reply.mjs`, lines 56-65 **Vulnerability Type**: Unsafe configuration evaluation **Risk Level**: High ### Vulnerable Code From `lib/config.mjs`: ```javascript function tryLoadOpenClawSkillConfig() { try { if (!fs.existsSync(openclawConfigPath)) return {}; const raw = fs.readFileSync(openclawConfigPath, 'utf8'); const parsed = vm.runInNewContext(`(${raw})`, {}); return parsed?.skills?.entries?.['voice-tts']?.config || {}; } catch { return {}; } } ``` From `scripts/send_voice_reply.mjs`: ```javascript function getBotToken(agentId) { try { const configPath = path.join(os.homedir(), '.openclaw', 'openclaw.json'); if (!fs.existsSync(configPath)) return null; const raw = fs.readFileSync(configPath, 'utf8'); const cfg = vm.runInNewContext(`(${raw})`, {}); const accounts = cfg?.channels?.telegram?.accounts; if (!accounts) return null; return accounts[agentId]?.botToken || accounts['default']?.botToken || null; } catch { return null; } } ``` ### Technical Analysis The code reads a file named `openclaw.json` and evaluates its contents as a JavaScript expression using `vm.runInNewContext`. A JSON configuration file should be parsed as inert data with `JSON.parse`. JavaScript object expressions can contain executable constructs such as function invocations, getters, or resource-exhaustion expressions that valid JSON cannot contain. Wrapping the file in parentheses does not convert it into safe data. A Node.js VM context should not be treated as a robust security boundary for hostile content. Even where direct host access is constrained, evaluating untrusted expressions creates denial-of-service and sandbox-escape exposure, including risks arising from future Node.js VM vulnerabilities or unsafe objects passed into the context. The same unsafe pattern is used both during normal configuration loading ...[truncated 1606 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the `node:vm` dependency from configuration handling. 2. Replace both evaluations with strict JSON parsing: ```javascript const parsed = JSON.parse(raw); ``` 3. Validate parsed configuration against a strict schema. Reject unexpected properties, invalid data types, oversized values, and dangerous path values. 4. Treat configuration parse failures as explicit errors rather than silently returning an empty object, especially when credentials or security-sensitive behavior is involved. 5. Restrict `~/.openclaw/openclaw.json` permissions to the owning user. 6. Add tests proving that JavaScript expressions, comments, getters, and function calls are rejected. 7. Consider size-limiting the file before reading it to reduce memory-exhaustion exposure. ]]>

T08 · Insecure Dependencies

Warning
Location
install.sh:47
Finding
Installer Uses Unpinned and Ambiguous Python Dependencies<![CDATA[ ## Vulnerability Details **File Location**: `install.sh`, lines 47-53 **Vulnerability Type**: Unsafe dependency installation and supply-chain exposure **Risk Level**: Medium ### Vulnerable Code ```bash PIP_CMD="pip3 install edge-tts whisper click" if [[ -n "$PROXY" ]]; then PIP_CMD="pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple edge-tts whisper click" export https_proxy="$PROXY" http_proxy="$PROXY" fi $PIP_CMD 2>&1 | tail -3 ``` The same unpinned requirements are declared in `SKILL.md`: ```yaml metadata: {"openclaw": {"emoji": "🎙️", "requires": {"bins": ["node>=18", "python3", "ffmpeg"], "pip": ["edge-tts", "whisper", "click"]}}} ``` ### Technical Analysis The installer retrieves `edge-tts`, `whisper`, and `click` without version constraints, integrity hashes, or a lock file. Each installation can therefore resolve to different package versions and artifacts. Python package installation may execute package build or installation logic. If an upstream release, dependency, package-index account, or configured mirror is compromised, malicious code may run during installation or when the Skill imports the package. The generic package name `whisper` is also ambiguous relative to the documented OpenAI Whisper functionality. Without a verified distribution identity and version, the installer may retrieve an unintended or incompatible project. The proxy option additionally changes the package index to a mirror. While use of a mirror is disclosed, no hash verification ensures that artifacts from the selected source match reviewed dependencies. ### Attack Path 1. A user runs `install.sh`. 2. The script requests mutable package names from PyPI or the configured mirror. 3. The package resolver selects the latest versions available at installation time. 4. A compromised, substituted, or unintended package is downloaded. 5. Package build or installation code runs with the privileges of the installing user. 6. Malicious runtime code may lat ...[truncated 661 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Confirm and document the exact intended distribution for Whisper rather than relying on an ambiguous package name. 2. Pin every direct and transitive dependency to reviewed versions. 3. Generate a hash-locked requirements file and install it using: ```bash python3 -m pip install --require-hashes -r requirements.txt ``` 4. Use an isolated virtual environment rather than installing into the user's global Python environment. 5. Prefer `python3 -m pip` over a standalone `pip3` executable to guarantee interpreter consistency. 6. Review dependency provenance, release signatures where available, maintainers, and package-index ownership. 7. Apply the same integrity requirements when using a package mirror. 8. Integrate dependency vulnerability and provenance scanning into release checks. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (28)

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
The stated purpose is ASR/TTS, but the documentation also instructs system package installation, model downloads, local file mutation, and external Telegram delivery without clearly framing those as privileged side effects. This mismatch can mislead users and orchestration layers into granting or triggering broader behavior than expected, especially where agent skills are trusted based on their declared description.

Ae1

High
Category
analysis-evasion
Content
agent 回复文字后,如需以语音发送,调用 `send_voice_reply.mjs` 手动发送 Telegram 语音消息:
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
agent 回复文字后,如需以语音发送,调用 `send_voice_reply.mjs` 手动发送 Telegram 语音消息:
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
agent 回复文字后,如需以语音发送,调用 `send_voice_reply.mjs` 手动发送 Telegram 语音消息:
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ssd 1

High
Confidence
98% confidence
Finding
The script emits user-controlled transcription inside an imperative wrapper that instructs the downstream agent to obey the voice-tts workflow and call a specific tool. Because spoken input is attacker-controlled, this creates a semantic prompt-injection channel where untrusted content is delivered in-band with operational instructions, increasing the chance the agent will execute unintended actions or give the transcript elevated authority.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
TTS_OUT=$(node "$SKILL_DIR/bin/voice-tts.mjs" "安装测试" -f /tmp/tts-test.mp3 --agent main 2>&1)
if [[ -f /tmp/tts-test.mp3 && -s /tmp/tts-test.mp3 ]]; then
  ok "TTS 生成验证通过 ✓"
  rm -f /tmp/tts-test.mp3
else
  warn "TTS 生成验证未通过,请检查 edge-tts 安装"
fi
Confidence
95% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Lp3

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding
The skill documentation describes capabilities that require shell execution, environment access, package installation, file handling, and networked Telegram/TTS operations, but it declares no explicit tool scope or permissions boundary. In an agent ecosystem, this increases the chance that the skill is invoked with broader-than-expected privileges and that operators do not understand its effective access to local files, secrets, and external services.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
The description says the skill fully replaces the built-in TTS tool for processing Chinese content, and later sections are centered on Chinese voices and prompts. This appears to impose a specific language/locale behavior without documenting user opt-in or an alternative language selection path.

Missing User Warnings

Medium
Confidence
86% confidence
Finding
The skill documents sending user-provided text through external services to generate and deliver Telegram voice messages, but it does not prominently warn that message content may leave the local environment. This can expose sensitive response content to third-party infrastructure or unintended recipients if users assume the skill is purely local.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
```bash
pip install edge-tts whisper click
brew install ffmpeg   # macOS
sudo apt install -y ffmpeg  # Ubuntu
```

安装完成后运行冒烟测试:
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Natural-Language Policy Violations

Medium
Confidence
84% confidence
Finding
The sample configuration uses only `zh-CN` voices and a Chinese ASR initial prompt, which reinforces a fixed locale assumption. There is no accompanying note that these are defaults users may change for other languages, so the documentation reads as enforcing a single language setting.

Missing User Warnings

Medium
Confidence
86% confidence
Finding
The documentation explains multiple token lookup paths, including config files and environment variables, but does not treat bot tokens as sensitive credentials requiring careful handling. In practice, this can encourage insecure storage, accidental logging, or overbroad access to messaging accounts if operators copy tokens into unsafe places.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The skill automatically copies inbound audio into an agent workspace and deletes the original after successful transcription, but this destructive behavior is not highlighted as a significant operational and privacy risk. Automatic file movement and deletion can cause data loss, break forensic traceability, or alter evidence without explicit operator approval.

File System Enumeration

Medium
Category
Data Exfiltration
Content
python3 -c "import whisper; print('whisper ok')"

# 检查未处理语音文件
ls -la ~/.openclaw/media/inbound/

# 直接测试 ASR
node bin/voice-asr.mjs ~/.openclaw/media/inbound/your-file.ogg
Confidence
60% confidence
Finding
Code scans file system directories looking for sensitive files. This could be reconnaissance for credential theft.

Context-Inappropriate Capability

Medium
Confidence
84% confidence
Finding
The bulk-processing script scans and processes all unhandled inbound voice files, which goes beyond a narrow per-request voice conversion function and creates a broader surveillance or unintended data-processing capability. In multi-user or shared-agent environments, this can lead to over-collection and transcription of audio that was not explicitly selected for the current task.

Description-Behavior Mismatch

Medium
Confidence
89% confidence
Finding
The manifest describes this skill as providing speech input via Whisper ASR and speech output via Edge TTS, but this file also copies inbound audio into an agent workspace and deletes the original file after successful transcription. Persisting and relocating user media is not an obvious implementation detail of transcription itself, so the code's behavior exceeds the described scope.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
After successful transcription, the script copies the input audio into a workspace directory and deletes the original file when it is under the inbound path. Although comments describe the behavior, there is no user-facing disclosure, confirmation prompt, or visible warning emitted before this destructive file operation.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
The generated voice message is hard-coded in Chinese and instructs downstream behavior using Chinese text, which imposes a specific language/locale regardless of user preference. There is no indication here that the user can choose the language or that the locale restriction is documented as intentional.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
This manifest/config file sets the default voice to a zh-CN voice and provides a Chinese-only ASR initial prompt, which indicates the skill is configured to operate in a specific language by default. There is no accompanying indication in this file that users can choose another language or explicitly opt in, which matches the language/locale policy violation criteria.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
brew install ffmpeg 2>&1 | tail -3
  else
    info "检测到 Linux,尝试用 apt 安装 ffmpeg..."
    sudo apt install -y ffmpeg 2>&1 | tail -3
  fi
  ok "ffmpeg 安装完成 ✓"
fi
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The generated OpenClaw config forces the ASR argument `--language zh`, which constrains recognition to Chinese. This is a natural-language locale policy issue because the script does not present this as an opt-in choice or explain that the skill is intentionally limited to a Chinese-only deployment context.

Natural-Language Policy Violations

Medium
Confidence
91% confidence
Finding
The generated agent voice settings set all default voices to `zh-CN-*` variants, enforcing a Chinese locale by default. Because the script does not offer a language/voice selection step or clearly justify a Chinese-only constraint, this creates a policy-relevant locale restriction.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The code reads a global file from the user's home directory and evaluates its contents with vm.runInNewContext instead of parsing strict JSON. If an attacker can modify ~/.openclaw/openclaw.json, they can inject JavaScript that executes during config loading, turning a voice configuration feature into arbitrary code execution. The broader access to a cross-skill global config also increases the blast radius beyond this skill's stated purpose.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This code defines all user-facing error messages exclusively in Chinese, with no indication of locale selection, fallback options, or region-specific justification. That creates a natural-language policy issue because the skill appears to force a specific language without user opt-in.

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
The module comment states the fallback order is --token, then the current agent/default botToken from openclaw.json, then TELEGRAM_BOT_TOKEN. However, the implementation at L126-L128 gives precedence to the environment variable over openclaw.json by computing explicitToken as args.token || process.env.TELEGRAM_BOT_TOKEN and then using explicitToken || openclawToken. This is an active contradiction between documented intent and runtime behavior.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
bin/voice-asr.mjs:60

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
bin/voice-tts.mjs:43

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/send_voice_reply.mjs:44