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

Content
View full analysis

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
View 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

Content
View full analysis

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
View 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

Content
View full analysis

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
View 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 相关行为。相反,它的主要用途是运维/监控:生成日报、执行本地测试、写入监控文件,并提示人工收集外部平台数据。这与声明的主要目的存在实质性偏差,因此应判定为描述与实际行为不匹配。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding

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

Content

No source excerpt is available for this finding.

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.

Content

No source excerpt is available for this finding.

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.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/daily_monitor.py (reported line 29)May include surrounding context.

python
# 测试1: 本地模式
    try:
        result = subprocess.run(
            ["python3", f"{SKILL_DIR}/scripts/generate_voice.py", "测试"],
            capture_output=True,
            text=True,

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/generate_voice.py (reported line 60)May include surrounding context.

python
]
    
    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:

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
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.

Content

Scanner excerpt · scripts/init.sh (reported line 7)May include surrounding context.

sh
echo "🎙️  Voice Chat Bridge 初始化..."

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

# 创建配置文件

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/transcribe.py (reported line 26)May include surrounding context.

python
]
    
    try:
        subprocess.run(ffmpeg_cmd, check=True, capture_output=True)
    except subprocess.CalledProcessError as e:
        print(f"音频转换失败: {e}")
        return None

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/transcribe.py (reported line 36)May include surrounding context.

python
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)

Natural-Language Policy Violations

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.