Back to skill

Security audit

Xiaozhi Claw

Security checks for vulnerabilities and agentic risk

Overview

This voice-channel skill matches its stated purpose, but it exposes an unauthenticated WebSocket path into the agent and handles sensitive voice/text data with weak controls.

Review before installing. Use this only on a trusted, isolated network unless the plugin adds device authentication, pairing enforcement, WSS/TLS, payload and recording limits, and redacted logging. Assume microphone audio, transcripts, and generated responses may be sent to Volcengine Doubao and may appear in application logs in the current version.

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

T05 · Unauthorized Access and Privilege Escalation

Error
Location
src/websocket-server.ts:38
Finding

Unauthenticated Network Clients Can Submit Arbitrary Messages to the OpenClaw Agent

Content
View full analysis
{ const deviceId = req.url?.split("?")[0].slice(1) || "unknown"; console.log(`🎤 XiaoZhi device connected: ${deviceId}`); const audioStream = createAudioStream(AUDIO_CONFIG); const doubaoService = createDoubaoService(DOUBAO_CONFIG); clients.set(deviceId, { ws, audioStream, audioBuffer: [], isListening: false, doubaoService, }); ws.on("message", async (data: Buffer) => { try { const message: XiaoZhiMessage = JSON.parse(data.toString()); await handleXiaozhiMessage(deviceId, message, ctx); } catch (error) { ``` The resulting text is forwarded directly to the agent: ```ts const response = await ctx.agent.processMessage({ from: deviceId, text: userText, channel: "xiaozhi", }); ``` The channel also enables permissive quick-start behavior: ```ts meta: { ...meta, quickstartAllowFrom: true, }, ``` ### Technical Analysis `WebSocketServer` is created with only a port, so it listens on the default network interfaces. The connection handler does not validate a bearer token, client certificate, signed challenge, approved pairing record, source address, or WebSocket origin. The client controls its apparent identity through the request URL: ```ts const deviceId = req.url?.split("?")[0].slice(1) || "unknown"; ``` That value is accepted as the sender identity without verification. A JSON `listen/stop` message can contain an arbitrary `text` property, which is subsequently passed to `ctx.agent.processMessage`. Consequently, network reachability to the configured port is sufficient to invoke the agent. Although a pairing adapter ...[truncated 1552 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
src/websocket-server.ts:65
Finding

Unbounded Audio Buffering Permits Remote Memory and CPU Exhaustion

Content
View full analysis
0) { try { console.log(`🎙️ Processing STT for ${deviceId}...`); // Concatenate all audio frames const fullAudio = Buffer.concat(session.audioBuffer); // Convert Opus to WAV for Doubao STT const wavData = session.audioStream.pcmToWav( session.audioBuffer.flatMap(buf => session.audioStream.decodeOpus(buf)), AUDIO_CONFIG.sampleRate ); // Call Doubao STT API userText = await session.doubaoService.speechToText(wavData, AUDIO_CONFIG.sampleRate); ``` ### Technical Analysis After a client sends a `listen/start` message, every subsequent non-JSON message is retained in `session.audioBuffer`. No controls limit: - The total buffered byte count - The number or size of frames - The recording duration - The message rate - The numb ...[truncated 1687 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
README.md:65
Finding

Voice and Agent Traffic Uses Unencrypted WebSocket Transport

Content
View full analysis
{ const defaultId = accountId || "default"; return { id: defaultId, name: "XiaoZhi Device", enabled: true, deviceId: defaultId, wsUrl: `ws://localhost:8080`, }; }, ``` The server is instantiated without TLS configuration: ```ts wss = new WebSocketServer({ port }); ``` ### Technical Analysis The `ws://` protocol does not provide transport encryption, endpoint authentication, or message integrity. The protocol carries microphone audio, attacker- or user-provided text, and generated agent responses. Anyone able to observe or manipulate traffic on the network path may inspect or alter those WebSocket frames. The implementation does not create an HTTPS server with a certificate and does not document a TLS reverse-proxy requirement. It therefore encourages deployment of the voice channel over plaintext LAN connections. ### Attack Path 1. A device is configured according to the documentation to connect through `ws://`. 2. A network-adjacent attacker gains visibility into the route between the ESP32 device and the OpenClaw host, such as through a compromised access point, shared network, or switched-network interception. 3. The attacker captures WebSocket frames containing audio, submitted text, or TTS responses. 4. Where active interception is possible, the attacker modifies or injects frames because the transport provides no cryptographic integrity or server authentication. 5. Modified text may subsequen ...[truncated 563 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
src/websocket-server.ts:129
Finding

Complete User Transcripts and Agent Responses Are Exposed in Logs

Content
View full analysis
{ const { message, account } = ctx; // Send text message to XiaoZhi device console.log(`Sending to XiaoZhi ${account.deviceId}: ${message}`); // TODO: Implement actual WebSocket message sending return { success: true }; }, ``` ### Technical Analysis The plugin writes complete conversation content to standard application logs without redaction, classification, user consent, or a debug-only guard. Voice transcripts and agent responses can contain credentials, personal information, confidential business content, health information, or private contextual data. Application logs frequently have a broader audience and longer retention period than live channel traffic. They may be collected by process managers, container platforms, centralized logging services, backups, or support systems. ### Attack Path 1. A legitimate user speaks sensitive information or requests a response containing private data. 2. Doubao STT returns the transcript to the plugin. 3. The plugin writes the complete transcript to standard logs. 4. The agent response is also written to standard logs before TTS processing. 5. An operator, compromised log collector, support user, or other principal with log access retrieves the conversation ...[truncated 734 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (19)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · README.md (reported line 45)May include surrounding context.

Copy .env.example to .env and fill in your credentials:

bash
cp .env.example .env

Edit .env file:

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · index.ts (reported line 1)May include surrounding context.

ts
// Load environment variables from .env file
import 'dotenv/config';

import type { ChannelPlugin, OpenClawPluginApi } from "openclaw/plugin-sdk";

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · src/doubao-service.ts (reported line 6)May include surrounding context.

ts
// Load environment variables from .env file
import 'dotenv/config';

import type { ChannelPlugin, OpenClawPluginApi } from "openclaw/plugin-sdk";

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The README advertises real-time voice, WebSocket transport, and third-party STT/TTS integration, but it does not clearly warn that microphone audio and transcribed text may leave the local device and be sent to external services. Users may unknowingly expose sensitive conversations, and the example connection uses plain ws://, which further increases privacy and interception risk on untrusted networks.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
87% confidence
Finding

The skill requests or documents access to environment-provided credentials (DOUBAO_APP_ID and DOUBAO_ACCESS_TOKEN) but does not declare an explicit tool scope or permissions block describing that capability. This weakens least-privilege controls and makes it harder for reviewers and users to understand what sensitive resources the skill depends on.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill describes microphone audio streaming, speech transcription, and TTS through Volcengine Doubao, but it does not clearly warn users that raw voice data and derived transcripts are transmitted to an external third-party service. In a voice-assistant context, this can expose highly sensitive personal, household, or business information without sufficiently informed consent.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The default voice type is set to a Chinese voice, and the STT request fixes language: 'zh-CN', which enforces a specific language/locale behavior. This can violate language/locale policy when no opt-in, configurability, or justification is provided in the file.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The STT payload explicitly sets the recognition language to zh-CN, which constrains output to a single locale. The file does not provide an alternative language option or indicate that the user has chosen this locale.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The service sends user-provided audio to /api/v1/asr and user-provided text to /api/v1/tts via HTTPS, which is a privacy-relevant network operation. While the file comments describe STT/TTS integration, there is no user-facing disclosure, prompt, or warning indicating that content will be sent to a third-party service.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

When no text is provided, the server converts captured device audio and sends it to an external Doubao speech-to-text service. This creates a real privacy and data-handling risk because potentially sensitive voice content leaves the local system, and this file shows no consent, notice, or policy enforcement before transmission. In a voice-assistant integration, that behavior is expected functionally, but it still represents a genuine privacy vulnerability if users are not clearly informed and given control.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The manifest context describes support for 'Volcengine Doubao STT/TTS,' but this plugin file exposes only 'whisper'/'openai' for STT and 'openai'/'elevenlabs' for TTS. This is a semantic mismatch between the stated capability and the actual declared configurable behavior in the manifest/configuration.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The dependency uses a caret range, which permits automatic installation of newer minor/patch releases. This weakens build reproducibility and can expose the project to supply-chain risk if a newly published compatible version is compromised or introduces a security regression.

Content

Scanner excerpt · package.json (reported line 12)May include surrounding context.

json
"dev": "tsc --watch"
  },
  "dependencies": {
    "dotenv": "^16.3.1",
    "ws": "^8.14.2",
    "opusscript": "^0.1.1"
  },

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
98% confidence
Finding

The ws dependency is not pinned to an exact version, so installs may resolve to different releases over time. Because this package has multiple historical advisories and is part of a network-facing WebSocket bridge, version drift increases the chance of pulling a vulnerable release or complicates verification that a safe version is deployed.

Content

Scanner excerpt · package.json (reported line 13)May include surrounding context.

json
},
  "dependencies": {
    "dotenv": "^16.3.1",
    "ws": "^8.14.2",
    "opusscript": "^0.1.1"
  },
  "devDependencies": {

Unverifiable Dependency: ws has 7 known advisory(ies) (CVE-2016-10518 (Remote Memory Disclosure in ws); CVE-2024-37890 (ws affected by a DoS when handling a request with many HTTP headers); CVE-2026-45736 (ws: Uninitialized memory disclosure) +4 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
97% confidence
Finding

The manifest references ws without an exact pinned version, and the package has known published advisories. In a plugin that explicitly exposes WebSocket functionality for real-time device communication, inability to verify the resolved version means the deployed artifact may include a vulnerable network-facing component, increasing risk of denial of service or information disclosure.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
92% confidence
Finding

The opusscript dependency is specified with a caret range, allowing non-deterministic installs across environments. While not inherently exploitable by itself, this increases supply-chain exposure and can unexpectedly introduce insecure or unstable transitive code.

Content

Scanner excerpt · package.json (reported line 14)May include surrounding context.

json
"dependencies": {
    "dotenv": "^16.3.1",
    "ws": "^8.14.2",
    "opusscript": "^0.1.1"
  },
  "devDependencies": {
    "@types/node": "^20.10.0",

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

Scanner excerpt · package.json (reported line 17)May include surrounding context.

json
"opusscript": "^0.1.1"
  },
  "devDependencies": {
    "@types/node": "^20.10.0",
    "@types/ws": "^8.5.10",
    "typescript": "^5.3.0"
  }

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

Scanner excerpt · package.json (reported line 18)May include surrounding context.

json
},
  "devDependencies": {
    "@types/node": "^20.10.0",
    "@types/ws": "^8.5.10",
    "typescript": "^5.3.0"
  }
}

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

Scanner excerpt · package.json (reported line 19)May include surrounding context.

json
"devDependencies": {
    "@types/node": "^20.10.0",
    "@types/ws": "^8.5.10",
    "typescript": "^5.3.0"
  }
}

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

The code sends response text to an external Doubao text-to-speech service, which means generated or user-derived content may be disclosed to a third party. Although this is consistent with the skill's stated purpose, the lack of any visible warning or consent flow in this file means sensitive text could be transferred off-platform without the user's awareness. The impact is generally lower than raw audio/STT, but it is still a legitimate privacy concern.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.