Back to skill

Security audit

Bidirectional Voice Chat System

Security checks for vulnerabilities and agentic risk

Overview

A user should review this voice skill before installing because it can expose generated audio over unauthenticated network endpoints and its documentation overstates several shipped capabilities.

Install only if you are comfortable auditing and tightening it first. Keep the server bound to localhost unless you add authentication, avoid public tunnels for private audio, verify any downloaded executables before installation, and treat generated MP3s as retained sensitive content until deleted.

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)

T08 · Insecure Dependencies

Error
Location
SKILL.md:61
Finding
Unverified Third-Party Executable Installation## Vulnerability Details **File Location**: `SKILL.md`, lines 61-65 **Vulnerability Type**: Unverified executable download and supply-chain exposure **Risk Level**: High **Vulnerable Code**: ```bash - **macOS recommended**: `hear` - local recognition, no network required ```bash curl -LO https://github.com/sveinbjornt/hear/releases/download/0.7/hear-0.7.zip unzip hear-0.7.zip && cp hear-0.7/hear ~/.local/bin/ ``` ``` ### Technical Analysis The installation instructions download an archive containing a native executable and copy that executable into the user's local executable directory without validating a cryptographic checksum or digital signature. HTTPS protects the download in transit, but it does not protect against compromise of the hosting account, repository, release artifact, or upstream build process. If the hosted archive is replaced, a user following the documented installation procedure will install the modified executable. The Skill later invokes this executable from `~/.local/bin/hear` when processing audio. Installing `hear` is relevant only to the optional macOS local-transcription mode. Downloading an unverified executable is not necessary to provide that functionality; artifact integrity verification can be added without reducing functionality. ### Attack Path 1. An attacker compromises the upstream repository, release account, or artifact-publishing process. 2. The attacker replaces `hear-0.7.zip` with an archive containing a modified `hear` executable. 3. A user follows the Skill's installation instructions. 4. The archive is downloaded and its executable is copied to `~/.local/bin/hear` without integrity verification. 5. The user invokes `scripts/transcribe.py`. 6. The Python script executes the compromised binary with the privileges of the current user. ### Impact Assessment A compromised executable could run arbitrary code with the installing user's privileges. This ...[truncated 443 chars]
Remediation
## Remediation Suggestions 1. Publish and document a trusted SHA-256 or stronger digest for the exact release archive. 2. Verify the digest before extracting or installing the executable: ```bash curl --fail --location --output hear-0.7.zip \ https://github.com/sveinbjornt/hear/releases/download/0.7/hear-0.7.zip echo "EXPECTED_SHA256 hear-0.7.zip" | shasum -a 256 --check - ``` 3. Prefer a signed release and verify its signature against a documented maintainer key. 4. Stop installation immediately if download or verification fails. 5. Extract into a newly created temporary directory rather than the current directory. 6. Document the publisher, fixed version, expected checksum, and required permissions. 7. Keep local transcription explicitly optional and provide a supported package-manager installation path where available. 8. Pin Python and npm dependencies to reviewed versions and hashes rather than using unconstrained installation commands.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/voice_server.py:18
Finding
Unauthenticated Exposure of Generated Voice Recordings## Vulnerability Details **File Location**: `scripts/voice_server.py`, lines 18-35 **Vulnerability Type**: Unauthenticated file disclosure and unsafe network binding **Risk Level**: High **Vulnerable Code**: ```python class QuietHTTPRequestHandler(http.server.SimpleHTTPRequestHandler): """Silent HTTP Handler""" def __init__(self, *args, **kwargs): super().__init__(*args, directory=VOICE_DIR, **kwargs) def log_message(self, format, *args): # Do not output access logs pass def main(): # Ensure directory exists os.makedirs(VOICE_DIR, exist_ok=True) handler = QuietHTTPRequestHandler with socketserver.TCPServer(("", PORT), handler) as httpd: print(f"🌐 Voice Chat Bridge Server started") print(f"📂 Serving: {VOICE_DIR}") print(f"🔗 Local: http://localhost:{PORT}/") ``` The documentation also recommends exposing this service through public tunnel providers: ```bash ngrok http 8765 cloudflared tunnel --config ~/.cloudflared/config.yml run ``` ### Technical Analysis Passing an empty host string to `TCPServer` causes the service to listen on all available network interfaces rather than only the loopback interface. The server uses `SimpleHTTPRequestHandler` to serve the entire voice-output directory and implements no authentication or authorization. When the root path is requested, `SimpleHTTPRequestHandler` normally generates a directory listing. Consequently, the short random MP3 filenames do not provide meaningful access control because a client can enumerate them by opening the directory index. Suppressing access logs further reduces the operator's ability to detect unauthorized access. The exposure becomes especially severe when the documented Ngrok, Cloudflare Tunnel, or LocalTunnel deployment options are used, because the otherwise local HTTP service may become reachable from the public Internet. ...[truncated 1297 chars]
Remediation
## Remediation Suggestions 1. Bind to loopback by default: ```python with socketserver.TCPServer(("127.0.0.1", PORT), handler) as httpd: ``` 2. Require an explicit configuration option before binding to a LAN or public interface. 3. Disable directory listing and return files only through controlled routes. 4. Require authentication for every file request. 5. Use cryptographically strong, expiring, per-file access tokens rather than treating filenames as authorization. 6. Apply an expiration policy and delete recordings promptly after use. 7. Enable privacy-conscious access logging so unauthorized requests can be investigated. 8. Place public deployments behind TLS and an authenticated reverse proxy or tunnel access policy. 9. Warn users prominently that publishing the endpoint can expose conversation audio. 10. Restrict output-directory permissions to the owning user and avoid storing unrelated files in the served directory.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/transcribe.py:15
Finding
Predictable Shared Temporary File Allows File-Clobbering and Concurrency Attacks## Vulnerability Details **File Location**: `scripts/transcribe.py`, lines 15-55 **Vulnerability Type**: Insecure temporary-file handling **Risk Level**: Medium **Vulnerable Code**: ```python # Convert to a 16 kHz mono WAV first wav_path = "/tmp/hear_temp.wav" # ffmpeg conversion ffmpeg_cmd = [ "ffmpeg", "-i", audio_path, "-ar", "16000", "-ac", "1", "-c:a", "pcm_s16le", wav_path, "-y" ] try: subprocess.run(ffmpeg_cmd, check=True, capture_output=True) except subprocess.CalledProcessError as e: print(f"Audio conversion failed: {e}") return None # Use hear for recognition hear_path = os.path.expanduser("~/.local/bin/hear") hear_cmd = [hear_path, "-i", wav_path, "-l", "zh-CN", "-p"] try: result = subprocess.run(hear_cmd, capture_output=True, text=True, timeout=30) # Clean up temporary file os.remove(wav_path) if result.returncode == 0: return result.stdout.strip() else: error = result.stderr.strip() if "No speech detected" in error: return "[No speech detected; check the audio file]" elif "denied" in error.lower() or "not authorized" in error.lower(): return "[Speech recognition permission is required in system settings]" else: return f"[Recognition failed: {error}]" except subprocess.TimeoutExpired: os.remove(wav_path) return "[Recognition timeout]" except Exception as e: if os.path.exists(wav_path): os.remove(wav_path) return f"[Error: {e}]" ``` ### Technical Analysis Every transcription operation uses the fixed path `/tmp/hear_temp.wav`. The system temporary directory is shared among local processes, and the filename is predictable. The FFmpeg command also uses `-y`, which authorizes overwriting the destination. A local attacker may pre-create the predictable path as a symbolic link to another file writable by the ...[truncated 1814 chars]
Remediation
## Remediation Suggestions 1. Use Python's `tempfile` module to create a unique private temporary directory for every invocation. 2. Store the WAV file inside that directory and remove the directory automatically: ```python import tempfile from pathlib import Path with tempfile.TemporaryDirectory(prefix="voice-transcribe-") as temp_dir: wav_path = str(Path(temp_dir) / "audio.wav") ffmpeg_cmd = [ "ffmpeg", "-i", audio_path, "-ar", "16000", "-ac", "1", "-c:a", "pcm_s16le", wav_path ] subprocess.run(ffmpeg_cmd, check=True, capture_output=True) result = subprocess.run( [hear_path, "-i", wav_path, "-l", "zh-CN", "-p"], capture_output=True, text=True, timeout=30 ) ``` 3. Ensure temporary directories and files are accessible only to the current user. 4. Avoid fixed filenames in shared temporary directories. 5. Avoid unconditional overwrite flags unless the destination was securely created by the current process. 6. Put cleanup in a context manager or `finally` block so exceptions cannot leave sensitive audio behind. 7. Add tests that execute multiple transcription operations concurrently.
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (18)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
声明描述的核心功能是语音对话:语音识别、TTS 合成、以及公网访问能力。但提供的代码片段并未实现这些用户面向的对话能力,也没有展示 Cloudflare Tunnel 相关行为。相反,它的主要用途是运维/监控:生成日报、执行本地测试、写入监控文件,并提示人工收集外部平台数据。这与声明的主要目的存在实质性偏差,因此应判定为描述与实际行为不匹配。

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding
声明描述的是一个完整的双向语音对话系统,包含语音识别、语音合成以及通过 Cloudflare Tunnel 提供公网访问。但提供的代码片段只负责将输入文本通过 Edge TTS 合成为音频文件,并输出一个基于配置域名的链接。代码中没有任何音频输入处理、语音识别、会话管理、Web 服务暴露或 Cloudflare Tunnel 建立/管理逻辑。因此,实际行为仅覆盖了声明中的一部分(语音合成),与整体声明存在明显不符。

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
The supplied code only implements audio transcription. It preprocesses an input audio file with ffmpeg and invokes a local macOS-oriented speech recognition tool ('hear') to produce text. There is no text-to-speech functionality, no Edge TTS integration, no Cloudflare Tunnel setup or public exposure behavior, and no orchestration for a full two-way voice conversation system. While the speech-to-text portion matches part of the description, the declared purpose materially overstates the implemented behavior in this chunk.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The supplied code only provides a quiet local HTTP file server for a voice output directory. It does not perform audio capture, speech recognition, text processing, text-to-speech synthesis, conversational orchestration, or Cloudflare Tunnel exposure. While serving generated audio files could be a supporting component of a voice system, the declared description presents a much broader end-user capability set than this code chunk actually implements. Therefore, the description does not accurately represent the behavior of this specific code chunk.

Lp3

Medium
Category
MCP Least Privilege
Confidence
80% confidence
Finding
The skill documentation instructs use of shell commands, file writes, and local script execution, but it does not declare any explicit tool scope or permissions. In an agent environment, this increases the risk of overbroad execution because the runtime may permit filesystem and shell operations without clear least-privilege boundaries or user awareness.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The skill explicitly promotes exposing generated voice files through public URLs, tunnels, and sharing workflows, but provides no privacy or retention warning. Voice content often contains personal or sensitive data, so publishing it via Ngrok, Cloudflare Tunnel, LocalTunnel, or even LAN web hosting can unintentionally disclose private conversations to unauthorized parties.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
The manifest describes a bidirectional voice conversation system focused on speech recognition, TTS, and Cloudflare Tunnel exposure. This script instead collects installation/bug/feedback data, generates daily monitoring reports, and tracks GitHub/ClawHub follow-up tasks, which are operational analytics workflows rather than core voice-chat functionality.

Context-Inappropriate Capability

Medium
Confidence
83% confidence
Finding
The code launches a separate Python process to run another script as part of daily monitoring. While testing may be useful for maintenance, spawning subprocesses is not a capability implied by the manifest’s description of speech recognition, TTS, and tunnel access, making it an extra operational capability beyond the declared purpose.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
# 测试1: 本地模式
    try:
        result = subprocess.run(
            ["python3", f"{SKILL_DIR}/scripts/generate_voice.py", "测试"],
            capture_output=True,
            text=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The natural-language description and default voice configuration indicate the skill operates in Chinese using a zh-CN voice, and the usage text also assumes Chinese output. This appears to force a specific language/locale without user opt-in or an explicit documented justification for the constraint.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
]
    
    try:
        result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
        if result.returncode == 0 and os.path.exists(output_path):
            return filename, output_path
        else:
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
This code deletes files in the voice output directory when more than 50 MP3s are present, but the deletion is only noted in an internal comment and there is no user-facing print, prompt, or other disclosure before removal. For a code file, destructive file deletion should have some visible warning unless clearly disclosed elsewhere.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The script’s comments and all user-facing echo messages are written in Chinese, which imposes a specific language on users without any opt-in or explanation. This matches the policy category for language or locale violations because the skill does not offer an alternative language or justify that it is region-specific.

Session Persistence

Medium
Category
Rogue Agent
Content
echo "🎙️  Voice Chat Bridge 初始化..."

# 创建目录
mkdir -p ~/.openclaw/workspace/voice_output
touch ~/.openclaw/workspace/voice_output/.gitkeep

# 创建配置文件
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
]
    
    try:
        subprocess.run(ffmpeg_cmd, check=True, capture_output=True)
    except subprocess.CalledProcessError as e:
        print(f"音频转换失败: {e}")
        return None
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
The command hard-codes the recognition locale to `zh-CN`, which imposes a specific language setting on all users. This is a natural-language policy concern because the file does not offer any user opt-in, configuration mechanism, or explanation that the tool is intentionally limited to Chinese-only use.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
hear_cmd = [hear_path, "-i", wav_path, "-l", "zh-CN", "-p"]
    
    try:
        result = subprocess.run(hear_cmd, capture_output=True, text=True, timeout=30)
        
        # 清理临时文件
        os.remove(wav_path)
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Natural-Language Policy Violations

Low
Confidence
83% confidence
Finding
This code includes user-facing and instructional natural language in Chinese (for example the module docstring and handler docstring/comments) without any indication that the skill is region-specific or that language is configurable. The policy requires avoiding forced language/locale behavior unless there is explicit opt-in or a justified locale constraint.

Static analysis

No suspicious patterns detected.