T05 · Unauthorized Access and Privilege Escalation
- Location
index.ts:162- Finding
Unrestricted Discord Voice Users Can Invoke a Tool-Enabled Agent
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill largely does what it claims, but by default anyone in a joined Discord voice channel can drive a full OpenClaw agent and share persisted context, so it needs review before use.
Install only in trusted Discord servers or channels, configure allowedUsers explicitly, and run voice-originated requests with a restricted agent/tool profile. Tell participants that speech may be recorded, logged, transcribed, sent to providers, and used as agent input. Prefer local or TLS-protected STT/TTS paths, avoid remote Wyoming TCP unless secured by a trusted tunnel, and audit/update the npm lockfile before production use.
index.ts:162Unrestricted Discord Voice Users Can Invoke a Tool-Enabled Agent
index.ts:232Guild-Wide Agent Sessions Allow Cross-User Context Leakage and Instruction Persistence
src/voice-connection.ts:834Voice Transcripts and Agent Responses Are Written to Plaintext Logs
src/stt.ts:370Wyoming STT Sends Raw Voice Audio over Unauthenticated Plaintext TCP
package-lock.json:5380Dependency Graph Contains a Git-over-SSH Package and Install-Script Components
The lockfile includes protobufjs 7.5.4, which the scanner reports as having multiple critical advisories including denial of service and code-injection issues in generated/protobuf handling paths. Even though this is only a lockfile and exploitability depends on runtime code paths, bundling a version with many known advisories is a real supply-chain risk, especially in an agent skill that may process untrusted network data and model-related payloads.
@hono/node-server 1.19.9 is reported with path traversal and middleware bypass issues in static file serving. In this specific skill context it appears as an optional/peer dependency pulled via another package rather than a direct runtime dependency of the Discord voice skill, so exposure is less certain, but the vulnerable package is still present in the dependency graph.
sharp 0.34.5 is flagged for inherited image-processing vulnerabilities in bundled libraries such as libvips/libheif. This matters because the broader dependency tree includes multiple media-processing components, and malformed media inputs can be attacker-controlled in chat or voice ecosystems, potentially leading to crashes or worse depending on the underlying native issue.
@mariozechner/pi-coding-agent 0.52.12 is listed with several advisories, but in this package-lock it is introduced through the peer dependency chain of openclaw rather than being a direct feature of the Discord voice skill. That makes the finding real at the dependency level, though likely low impact to this skill unless those agent-export, temp-extension, or auth file paths are actually exercised in the deployment environment.
Package name closely resembles a popular package, suggesting possible typosquatting. Attackers publish malicious packages with similar names to trick developers into installing them.
Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.
},
) {
super();
this.apiKey = config.deepgram?.apiKey || process.env["DEEPGRAM_API_KEY"] || "";
this.model = validateDeepgramModel(config.deepgram?.model || "nova-2");
this.sampleRate = options?.sampleRate ?? 48000;
this.interimResults = options?.interimResults ?? true;
Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.
},
) {
super();
this.apiKey = config.deepgram?.apiKey || process.env["DEEPGRAM_API_KEY"] || "";
this.model = validateDeepgramModel(config.deepgram?.model || "nova-2");
this.sampleRate = options?.sampleRate ?? 48000;
this.interimResults = options?.interimResults ?? true;
Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.
},
) {
super();
this.apiKey = config.deepgram?.apiKey || process.env["DEEPGRAM_API_KEY"] || "";
this.model = validateDeepgramModel(config.deepgram?.model || "nova-2");
this.sampleRate = options?.sampleRate ?? 48000;
this.interimResults = options?.interimResults ?? true;
Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.
private model: string;
constructor(config: DiscordVoiceConfig) {
this.apiKey = config.openai?.apiKey || process.env["OPENAI_API_KEY"] || "";
this.model = config.openai?.whisperModel || "whisper-1";
if (!this.apiKey) {
Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.
private model: string;
constructor(config: DiscordVoiceConfig) {
this.apiKey = config.openai?.apiKey || process.env["OPENAI_API_KEY"] || "";
this.model = config.openai?.whisperModel || "whisper-1";
if (!this.apiKey) {
Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.
private model: string;
constructor(config: DiscordVoiceConfig) {
this.apiKey = config.openai?.apiKey || process.env["OPENAI_API_KEY"] || "";
this.model = config.openai?.whisperModel || "whisper-1";
if (!this.apiKey) {
Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.
private model: string;
constructor(config: DiscordVoiceConfig) {
this.apiKey = config.openai?.apiKey || process.env["OPENAI_API_KEY"] || "";
this.model = config.openai?.whisperModel || "whisper-1";
if (!this.apiKey) {
Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.
private modelId: string;
constructor(config: DiscordVoiceConfig) {
this.apiKey = config.elevenlabs?.apiKey || process.env["ELEVENLABS_API_KEY"] || "";
this.voiceId = validateElevenLabsVoiceId(config.elevenlabs?.voiceId || "21m00Tcm4TlvDq8ikWAM");
this.modelId = config.elevenlabs?.modelId || "eleven_turbo_v2_5";
Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.
private modelId: string;
constructor(config: DiscordVoiceConfig) {
this.apiKey = config.elevenlabs?.apiKey || process.env["ELEVENLABS_API_KEY"] || "";
this.voiceId = validateElevenLabsVoiceId(config.elevenlabs?.voiceId || "21m00Tcm4TlvDq8ikWAM");
this.modelId = config.elevenlabs?.modelId || "eleven_turbo_v2_5";
The README prominently describes capturing voice, transcribing it, and sending it to third-party STT/TTS providers, but it does not provide an explicit privacy notice, consent requirement, or data-handling warning. In a Discord voice setting, this can lead operators to deploy monitoring and external transmission of user speech without adequately informing participants, increasing privacy and compliance risk.
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
# Ubuntu/Debian
sudo apt-get install ffmpeg build-essential python3
# Fedora/RHEL
sudo dnf install ffmpeg gcc-c++ make python3
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
# Ubuntu/Debian
sudo apt-get install ffmpeg build-essential python3
# Fedora/RHEL
sudo dnf install ffmpeg gcc-c++ make python3
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
sudo apt-get install ffmpeg build-essential python3
# Fedora/RHEL
sudo dnf install ffmpeg gcc-c++ make python3
# macOS
brew install ffmpeg
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
sudo apt-get install ffmpeg build-essential python3
# Fedora/RHEL
sudo dnf install ffmpeg gcc-c++ make python3
# macOS
brew install ffmpeg
Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.
## Configuration
| Option | Type | Default | Description |
| ---------------------- | ----------------- | ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `enabled` | boolean | `true` | Enable/disable the plugin |
| `sttProvider` | string | `"whisper"` | `"whisper"`, `"local-whisper"`, `"wyoming-whisper"`, `"gpt4o-mini"`, `"gpt4o-transcribe"`, `"gpt4o-transcribe-diarize"` (OpenAI), or `"deepgram"` |
Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.
| Option | Type | Default | Description |
| ---------------------- | ----------------- | ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `enabled` | boolean | `true` | Enable/disable the plugin |
| `sttProvider` | string | `"whisper"` | `"whisper"`, `"local-whisper"`, `"wyoming-whisper"`, `"gpt4o-mini"`, `"gpt4o-transcribe"`, `"gpt4o-transcribe-diarize"` (OpenAI), or `"deepgram"` |
| `sttFallbackProvider` | string | `undefined` | Single fallback (legacy). Prefer `sttFallbackProviders`. |
| `sttFallbackProviders` | string[] | `undefined` | Fallback STT when primary fails (quota, rate limit, Wyoming unreachable). E.g. `["local-whisper", "wyoming-whisper"]`. |
Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.
| Option | Type | Default | Description |
| ---------------------- | ----------------- | ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `enabled` | boolean | `true` | Enable/disable the plugin |
| `sttProvider` | string | `"whisper"` | `"whisper"`, `"local-whisper"`, `"wyoming-whisper"`, `"gpt4o-mini"`, `"gpt4o-transcribe"`, `"gpt4o-transcribe-diarize"` (OpenAI), or `"deepgram"` |
| `sttFallbackProvider` | string | `undefined` | Single fallback (legacy). Prefer `sttFallbackProviders`. |
| `sttFallbackProviders` | string[] | `undefined` | Fallback STT when primary fails (quota, rate limit, Wyoming unreachable). E.g. `["local-whisper", "wyoming-whisper"]`. |
Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.
| ---------------------- | ----------------- | ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `enabled` | boolean | `true` | Enable/disable the plugin |
| `sttProvider` | string | `"whisper"` | `"whisper"`, `"local-whisper"`, `"wyoming-whisper"`, `"gpt4o-mini"`, `"gpt4o-transcribe"`, `"gpt4o-transcribe-diarize"` (OpenAI), or `"deepgram"` |
| `sttFallbackProvider` | string | `undefined` | Single fallback (legacy). Prefer `sttFallbackProviders`. |
| `sttFallbackProviders` | string[] | `undefined` | Fallback STT when primary fails (quota, rate limit, Wyoming unreachable). E.g. `["local-whisper", "wyoming-whisper"]`. |
| `streamingSTT` | boolean | `true` | Use streaming STT (Deepgram only, ~1s faster) |
| `ttsProvider` | string | `"openai"` | `"openai"`, `"elevenlabs"`, `"deepgram"`, `"polly"`, `"edge"`, or `"kokoro"` |
Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.
| ---------------------- | ----------------- | ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `enabled` | boolean | `true` | Enable/disable the plugin |
| `sttProvider` | string | `"whisper"` | `"whisper"`, `"local-whisper"`, `"wyoming-whisper"`, `"gpt4o-mini"`, `"gpt4o-transcribe"`, `"gpt4o-transcribe-diarize"` (OpenAI), or `"deepgram"` |
| `sttFallbackProvider` | string | `undefined` | Single fallback (legacy). Prefer `sttFallbackProviders`. |
| `sttFallbackProviders` | string[] | `undefined` | Fallback STT when primary fails (quota, rate limit, Wyoming unreachable). E.g. `["local-whisper", "wyoming-whisper"]`. |
| `streamingSTT` | boolean | `true` | Use streaming STT (Deepgram only, ~1s faster) |
| `ttsProvider` | string | `"openai"` | `"openai"`, `"elevenlabs"`, `"deepgram"`, `"polly"`, `"edge"`, or `"kokoro"` |
Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.
| `sttProvider` | string | `"whisper"` | `"whisper"`, `"local-whisper"`, `"wyoming-whisper"`, `"gpt4o-mini"`, `"gpt4o-transcribe"`, `"gpt4o-transcribe-diarize"` (OpenAI), or `"deepgram"` |
| `sttFallbackProvider` | string | `undefined` | Single fallback (legacy). Prefer `sttFallbackProviders`. |
| `sttFallbackProviders` | string[] | `undefined` | Fallback STT when primary fails (quota, rate limit, Wyoming unreachable). E.g. `["local-whisper", "wyoming-whisper"]`. |
| `streamingSTT` | boolean | `true` | Use streaming STT (Deepgram only, ~1s faster) |
| `ttsProvider` | string | `"openai"` | `"openai"`, `"elevenlabs"`, `"deepgram"`, `"polly"`, `"edge"`, or `"kokoro"` |
| `ttsVoice` | string | `"nova"` | Deprecated – use provider-specific: `openai.voice`, `elevenlabs.voiceId`, `kokoro.voice` |
| `vadSensitivity` | string | `"medium"` | `"low"`, `"medium"`, or `"high"` |
Detected: suspicious.env_credential_access, suspicious.exposed_secret_literal, suspicious.insecure_tls_verification