Back to skill

Security audit

senseaudio-let-claw-talkv1

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to be a real voice assistant, but it needs Review because it starts long-running microphone workflows, stores secrets and conversation data locally, and includes an unsafe optional WeSpeaker service.

Review carefully before installing. Use it only if you are comfortable with a long-running microphone assistant that sends speech to SenseAudio and stores local logs/state. Avoid putting API keys on the command line, restrict the credential file permissions, review or disable transcript logging, and do not enable WeSpeaker until its local HTTP service has authentication/path validation and its dependency installation is pinned to reviewed versions or commits.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (4)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/local_wespeaker_service.py:38
Finding

Unauthenticated WeSpeaker Service Permits Path Traversal and State-Changing Requests

Content
View full analysis
Path: return self.profiles_dir / f"{profile_name}.npy" def meta_path(self, profile_name: str) -> Path: return self.profiles_dir / f"{profile_name}.json" def save_embeddings(self, profile_name: str, embeddings: np.ndarray) -> None: path = self.embedding_path(profile_name) np.save(path, embeddings.astype(np.float32)) meta = { "profile_name": profile_name, "sample_count": int(embeddings.shape[0]), "updated_at": __import__("time").strftime("%Y-%m-%dT%H:%M:%S%z"), } write_json(self.meta_path(profile_name), meta) def clear_profile(self, profile_name: str) -> None: for path in [self.embedding_path(profile_name), self.meta_path(profile_name)]: if path.exists(): path.unlink() ``` ```python class Handler(BaseHTTPRequestHandler): runtime: WeSpeakerRuntime = None shutdown_event: threading.Event = None def _read_json(self) -> dict: length = int(self.headers.get("Content-Length", "0") or "0") if length <= 0: return {} body = self.rfile.read(length).decode("utf-8") return json.loads(body or "{}") def do_POST(self): try: payload = self._read_json() if self.path == "/enroll": ...[truncated 4204 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/configure_senseaudio_credentials.py:20
Finding

Credential Helper Stores API Keys Without Enforcing Restrictive Permissions

Content
View full analysis
int: parser = argparse.ArgumentParser(description="Write SenseAudio API keys into the user-level AudioClaw credentials file.") parser.add_argument("--api-key", default="", help="Shared key used for both ASR and TTS.") parser.add_argument("--asr-api-key", default="", help="Optional ASR-only key.") parser.add_argument("--tts-api-key", default="", help="Optional TTS-only key.") parser.add_argument("--path", default=str(default_credentials_path())) args = parser.parse_args() target = Path(str(args.path)).expanduser().resolve() payload = load_payload(target) if args.api_key: payload["SENSEAUDIO_API_KEY"] = args.api_key.strip() if args.asr_api_key: payload["AUDIOCLAW_ASR_API_KEY"] = args.asr_api_key.strip() if args.tts_api_key: payload["AUDIOCLAW_TTS_API_KEY"] = args.tts_api_key.strip() if not payload: raise SystemExit("No credentials were provided.") target.parent.mkdir(parents=True, exist_ok=True) target.write_text(json.dumps(payload, ensure_ascii=False, indent=2) + "\n", encoding="utf-8") ``` ### Technical Analysis The helper writes long-lived API keys as plaintext JSON but does not explicitly create the file with owner-only permissions or correct permissions on an existing file. On Unix-like systems, the resulting mode depends on the process umask. A common umask of `022` can create the file as mode `0644`, making it readable by other local users. Parent-directory restrictions may reduce practical exposure in some installations, but the helper does not verify or enforce them. The documented invocation also encourages supplying a key through a command-line argument. Command-line secrets can be retained in shell h ...[truncated 1018 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/run_continuous_voice_assistant.py:678
Finding

Persistent Runtime Logs Retain Recognized Speech and Assistant Replies

Content
View full analysis
str: cleaned = re.sub(r"\s+", " ", str(text or "")).strip() if len(cleaned) <= limit: return cleaned return cleaned[: max(0, limit - 1)] + "…" def log_runtime_event(event: str, message: str, **fields) -> None: try: RUNTIME_EVENT_LOG_PATH.parent.mkdir(parents=True, exist_ok=True) line = f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] {event}: {message}" if fields: line += " | " + json.dumps(fields, ensure_ascii=False, default=str) with RUNTIME_EVENT_LOG_PATH.open("a", encoding="utf-8") as fh: fh.write(line.rstrip() + "\n") except Exception: pass ``` Assistant replies are logged: ```python def emit_reply( reply: str, args: argparse.Namespace, turn_id: int, armed_until: float, speaker_profile: dict, ) -> tuple[float, bool]: print_status(f"[claw] {reply}") log_runtime_event("reply", "assistant reply emitted", preview=preview_text(reply), turn_id=turn_id) ``` Recognized user speech is also logged: ```python print_status(f"[you] {transcript}") log_runtime_event("transcript", "recognized user speech", preview=preview_text(transcript), asr_model=active_asr_model) ``` ### Technical Analysis The assistant writes up to 180 characters from each recognized utterance and each generated reply to a persistent runtime log. Similar previews are also recorded for wake-blocked speech, local commands, exit commands, and agent requests. Voice-assistant conversations may contain passwords spoken aloud, personal information, medical information, business discussions, or private requests. The implementation creates an append-only record without: - Explic ...[truncated 1317 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Error
Location
references/wespeaker_user_setup.md:31
Finding

Optional WeSpeaker Setup Executes Unpinned Dependencies From a Mutable Git Source

Content
View full analysis
Remediation
View remediation
" ``` 2. Prefer a verified release artifact from a trusted package index rather than installing from a live branch. 3. Pin every direct and transitive dependency in a lock file appropriate to each supported platform and Python version. 4. Require package hashes with `pip --require-hashes`. 5. Publish the expected commit identifiers, package versions, and artifact hashes in the Skill documentation. 6. Build and scan wheels in a controlled environment before distributing them to users. 7. Run the optional service in a restricted environment with minimum filesystem and network access. 8. Establish an update process that re-audits dependency changes before changing pins. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (68)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description focuses on a full duplex local voice assistant pipeline: continuous microphone listening, speech recognition, agent querying, and spoken responses across macOS/Windows. The supplied code does none of that. Its sole function is to accept API key arguments and persist them to a credentials JSON file in the user's home directory. While credential setup could be a supporting implementation detail within a larger skill, this specific code chunk's purpose is materially different from the declared primary behavior and introduces a concrete capability—writing credential files—that is not described. Therefore this chunk does not accurately represent the declared skill behavior.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

声明描述的是一个较完整的连续语音助手 skill,而代码片段实际仅实现了其中一小部分:把本地音频文件上传到 SenseAudio ASR 接口进行转写。代码确实与描述中的“用户语音通过 SenseAudio ASR 转文字”这一子能力一致,但缺少声明中大部分核心行为,尤其是持续监听、录音、agent 集成、TTS 输出和跨平台录音方案。因此从“描述是否准确代表代码实际行为”来看,描述明显比代码宽泛得多,属于实质性不匹配。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

声明描述的是一个完整的本机语音助手技能,核心能力应包括麦克风监听、语音识别、与 agent 交互以及语音合成回复。但提供的代码块只是在本地处理音色元数据:读写 JSON 文件、生成自定义/克隆音色信息、列出全部音色并进行搜索。它既不访问麦克风,也不处理音频流、ASR、TTS 或跨平台录音逻辑。该代码更像是 TTS 音色配置支持模块,而不是所声明技能的核心行为。因此,这段代码与声明用途存在明显不匹配。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

声明的核心用途是连续语音助手的录音、识别、问答与播报流程,只把 WeSpeaker 描述为“可选后台服务”。但实际代码块并未处理录音、ASR、TTS、agent 通信或持续监听逻辑,而是专门围绕 WeSpeaker 本地服务进行管理,并提供声纹注册和验证等说话人识别功能。这些能力不仅比描述更具体,而且属于不同的主要功能面,因此描述未能准确代表该代码块的实际行为。

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
88% confidence
Finding

The skill directs use of a user-level credentials file containing the SenseAudio API key, which is a sensitive secret. Referencing and depending on local secret files is expected for this functionality, but without explicit permission scoping, secure file handling guidance, and warnings against leakage through logs or broad file access, it increases the risk of accidental exposure.

Content

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

md
- 或 `/Applications/商汤输入法AudioClaw.app/Contents/Resources/claws/picoclaw/audioclaw-darwin-amd64`
- 有可用的 `python3`
- 已通过用户级凭据文件提供 SenseAudio key:
  - `~/.audioclaw/workspace/state/senseaudio_credentials.json`
- 如果没有安装 `numpy + sounddevice + webrtcvad`,当前 skill 会优先回退到 macOS 原生 Swift 录音器
- 使用原生 Swift 录音器时,建议本机有可用的命令行开发工具:
  - `xcode-select --install`

Credential Access

High
Category
Privilege Escalation
Confidence
88% confidence
Finding

On Windows, the skill similarly relies on a local credentials JSON file storing an API key. Secret material in predictable user paths is susceptible to accidental disclosure by overbroad file permissions, backups, logs, or other tools running as the user.

Content

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

md
- `webrtcvad`
  - `setuptools`
- 用户级凭据文件需要存在:
  - `C:\Users\<用户名>\.audioclaw\workspace\state\senseaudio_credentials.json`

推荐安装命令:

Credential Access

High
Category
Privilege Escalation
Confidence
86% confidence
Finding

The skill documents shared credential locations, which indicates intentional access to secrets. In context this is functional, but it remains sensitive because any skill with broad file-read access could exfiltrate the API key if boundaries are not enforced.

Content

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

md
- 建议单独准备用户级虚拟环境
  - 不要塞进 skill 包
- 用户级共享凭据:
  - `~/.audioclaw/workspace/state/senseaudio_credentials.json`
  - 或 `C:\Users\<用户名>\.audioclaw\workspace\state\senseaudio_credentials.json`

WeSpeaker 完整环境建议:

Credential Access

High
Category
Privilege Escalation
Confidence
86% confidence
Finding

This duplicate shared-credentials reference reinforces that the skill expects access to plaintext API-key storage. The danger is not the mention itself but normalizing broad secret-file usage without stronger controls or user-facing warnings.

Content

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

md
- 不要塞进 skill 包
- 用户级共享凭据:
  - `~/.audioclaw/workspace/state/senseaudio_credentials.json`
  - 或 `C:\Users\<用户名>\.audioclaw\workspace\state\senseaudio_credentials.json`

WeSpeaker 完整环境建议:

Credential Access

High
Category
Privilege Escalation
Confidence
93% confidence
Finding

The skill suggests passing the API key directly on the command line to a configuration script. Command-line arguments are commonly exposed via shell history, process listings, crash dumps, and telemetry, making this a stronger secret-handling risk than merely reading a credential file.

Content

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

md
- 推荐优先使用 `py -3`
- 如果系统里只有 `C:\Users\<用户名>\AppData\Local\Microsoft\WindowsApps\python.exe` 这种应用商店别名,启动器会直接提示你安装 Python,或手动设置 `VOICECLAW_PYTHON_BIN`
- 不建议把真实 SenseAudio key 写进 skill 包本身。更稳的做法是写到用户级文件:
  - `C:\Users\<用户名>\.audioclaw\workspace\state\senseaudio_credentials.json`
  - 或用当前 skill 自带脚本写入:
    `py -3 "{baseDir}\scripts\configure_senseaudio_credentials.py" --api-key "你的sk-..."`

Credential Access

High
Category
Privilege Escalation
Confidence
89% confidence
Finding

The runtime notes confirm automatic reuse of an API key from a known credential file, which is legitimate but security-sensitive behavior. Without explicit permission declarations and storage protections, a compromised or overly broad skill execution context could read and misuse the credential.

Content

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

md
## Runtime notes

- 默认会复用 `~/.audioclaw/workspace/state/senseaudio_credentials.json` 里的 `SENSEAUDIO_API_KEY`
- 默认会把已记住的用户偏好保存在 `~/.audioclaw/workspace/state/voiceclaw_preferences.json`
- 默认会把当前运行状态摘要保存在 `~/.audioclaw/workspace/state/voiceclaw_runtime_state.json`
- `run_continuous_voice_assistant.py` 现在自带当前 skill 内部的 SenseAudio ASR、SenseAudio TTS 和常用音色目录,不再依赖其他语音 skill

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- `run_continuous_voice_assistant.py` 现在自带当前 skill 内部的 SenseAudio ASR、SenseAudio TTS 和常用音色目录,不再依赖其他语音 skill

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- `run_continuous_voice_assistant.py` 现在自带当前 skill 内部的 SenseAudio ASR、SenseAudio TTS 和常用音色目录,不再依赖其他语音 skill

YARA rule 'agent_skill_remote_bootstrap_execution': Remote script or code download followed by execution/bootstrap installation [agent_skills]

High
Category
YARA Match
Confidence
95% confidence
Finding

Installing directly from a GitHub repository with pip install git+https://... executes an unpinned, remotely fetched package build/install path at install time. This creates a software supply-chain risk: if the upstream repository, dependency chain, or referenced branch changes or is compromised, users may install and run attacker-controlled code in their local environment.

Content

Scanner excerpt · references/wespeaker_user_setup.md (reported line 33)May include surrounding context.

aker 依赖链里某些组件还在调用旧接口。优先建议按 WeSpeaker README 里偏旧、更稳的组合来装。

bash
~/.audioclaw/workspace/tools/wespeaker/.venv/bin/pip install torch==1.12.1 torchaudio==0.12.1
~/.audioclaw/workspace/tools/wespeaker/.venv/bin/pip install soundfile PyYAML requests onnxruntime s3prl openai-whisper peft
~/.audioclaw/workspace/tools/wespeaker/.venv/bin/pip install git+https://github.com/wenet-e2e/wespeaker.git

3. 验证环境

bash
~/.audioclaw/workspace/tools/wespeaker/.venv/bin/python - <<'PY'
import wespeaker
print("wespeaker ok")
PY

如果这里能输出 wespeaker ok,说明环境已经准备好。

4. 告诉 SenseAudio-Let-Claw-Talk-Universal 去哪里找环境

默认启动脚本会优先读取:

  • VOICECLAW_WESPEAKER_PYTHON

如果你按上面的推荐目录安装,一般不用再改。

如果你把环境装在别的位置,可以手动指定:

bash
export VOICECLAW_WESPEAKER_PYTHON=/你的路径/bin/

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

Scanner excerpt · references/runtime_tuning.md (reported line 93)May include surrounding context.

md
def default_credentials_path() -> Path:
    return (Path.home() / ".audioclaw" / "workspace" / "state" / "senseaudio_credentials.json").resolve()


def load_payload(path: Path) -> dict:

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

Scanner excerpt · scripts/configure_senseaudio_credentials.py (reported line 8)May include surrounding context.

python
def default_credentials_path() -> Path:
    return (Path.home() / ".audioclaw" / "workspace" / "state" / "senseaudio_credentials.json").resolve()


def load_payload(path: Path) -> dict:

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

Scanner excerpt · scripts/run_continuous_voice_assistant.py (reported line 109)May include surrounding context.

python
def default_credentials_path() -> Path:
    return (Path.home() / ".audioclaw" / "workspace" / "state" / "senseaudio_credentials.json").resolve()


def load_payload(path: Path) -> dict:

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · scripts/local_wespeaker_client.py (reported line 183)May include surrounding context.

python
raise RuntimeError(f"WeSpeaker service 脚本不存在:{service_script}")

    log_path = get_log_path(args)
    env = os.environ.copy()
    env["WESPEAKER_HOME"] = str((state_dir / "models").resolve())
    env["VIRTUAL_ENV"] = str(python_path.parent.parent)
    env["PATH"] = f"{python_path.parent}{os.pathsep}{env.get('PATH', '')}"

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Confidence
85% confidence
Finding

os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

Content

Scanner excerpt · scripts/start_senseaudio_let_claw_talk_universal.py (reported line 81)May include surrounding context.

python
if extra:
        command.extend(shlex.split(extra, posix=not IS_WINDOWS))

    os.execv(sys.executable, command)


if __name__ == "__main__":

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
97% confidence
Finding

The skill instructs the host to use shell commands, read environment variables, access credential files, write state/log files, and call remote services, but it does not declare any explicit tool scope or permissions. That creates a confused-deputy risk where users and the platform cannot clearly constrain what the skill may access before invocation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill is designed for continuous microphone monitoring and remote processing of captured speech by ASR/TTS and agent services, but the description does not present a clear upfront privacy warning or consent notice. Users may enable an always-listening mode without understanding that ambient speech can be captured and sent to third-party services.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The WeSpeaker enrollment flow collects and stores biometric voice samples and verification profiles, but the instructions do not provide a clear warning about biometric data sensitivity, storage location, retention, or deletion implications. Biometric voiceprints are high-sensitivity data that cannot be easily rotated if mishandled.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
65% 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 · SKILL.md (reported line 337)May include surrounding context.

md
原因:

- 持续监听属于长期麦克风进程
- 不适合用 `exec + nohup + &` 在工具调用后台硬挂
- 更稳的做法是让 skill 直接打开一个新的终端窗口承载会话
- 这个启动器会按平台自动选择:
  - macOS:Terminal + `osascript`

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill defines very broad natural-language phrases as direct launch commands and explicitly instructs the agent to start a detached long-running assistant process instead of confirming intent. That increases the chance of unintended invocation from ambiguous user phrasing, quoted text, or conversational discussion, which is especially risky because the launched process enables always-listening microphone behavior.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The default prompt hard-codes Chinese wake and sleep phrases and a 90-second wake-hold window without explicit user opt-in. In a continuous-listening assistant, forced defaults can cause unexpected microphone activation or failure to match the user's language and environment, reducing user control over when the agent is actively listening and responding.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
81% confidence
Finding

Multiple spoken commands and wake phrases are specified only in Chinese, such as preference commands, voice switching, and wake-word examples. Because the file does not indicate that Chinese is optional, configurable, or required for a justified region-specific reason, this appears to force a specific language without user opt-in.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.