Back to skill

Security audit

Voice UI

Security checks for vulnerabilities and agentic risk

Overview

This skill is a disclosed self-modifying voice assistant, but it exposes powerful local agent, file, Git, credential, and browser surfaces without adequate scoping or user control.

Install only in an isolated test workspace with no sensitive files or credentials, and avoid exposing port 8765 beyond localhost. Before normal use, remove browser API-key exposure, authenticate and constrain /api/chat, bind the server to loopback, fix static file path validation, replace innerHTML rendering, disable automatic git add -A commits, and require explicit review before any code or Git changes.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • 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
  • 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 (5)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
server.cjs:21
Finding
Arbitrary Local File Disclosure Through Path Traversal<![CDATA[ ## Vulnerability Details **File Location**: `server.cjs:21-31` **Vulnerability Type**: Path traversal and arbitrary file read **Risk Level**: High ### Vulnerable Code ```js // Serve static files if (req.method === 'GET') { let filePath = req.url === '/' ? '/index.html' : req.url; filePath = path.join(__dirname, filePath); const ext = path.extname(filePath); const types = { '.html': 'text/html', '.js': 'text/javascript', '.css': 'text/css' }; try { const content = fs.readFileSync(filePath); res.writeHead(200, { 'Content-Type': types[ext] || 'text/plain' }); res.end(content); } catch { res.writeHead(404); res.end('Not found'); } return; } ``` ### Technical Analysis The server passes the untrusted request URL directly to `path.join()` and subsequently to `fs.readFileSync()`. It does not decode and validate the path, restrict access to an explicit public directory, or verify that the normalized path remains beneath the project root. Traversal components can consequently cause the normalized path to escape `__dirname`. The server will return any resulting file that is readable by its operating-system account. Because the server uses Node.js's default listen behavior and does not authenticate requests, this flaw may be available to other hosts whenever port 8765 is network-reachable. ### Attack Path 1. The victim starts the application. 2. An attacker connects to port 8765. 3. The attacker submits a crafted GET request containing sufficient parent-directory components, such as a path targeting `../../../../etc/passwd`. 4. `path.join()` normalizes the traversal sequence into a path outside the project directory. 5. `fs.readFileSync()` reads the target using the server process's filesystem privileges. 6. The file contents are returned in the HTTP response. ### Impact Assessment An attacker can read files accessible to the server account. The exposed scope may include: - OpenClaw configuration and credentials. ...[truncated 275 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Serve only files from a dedicated public directory. - Decode the URL safely and reject malformed encoding, NUL bytes, backslashes, and traversal segments. - Resolve the requested path and verify containment before reading it: ```js const publicRoot = path.resolve(__dirname, 'public'); const requestPath = decodeURIComponent(new URL(req.url, 'http://localhost').pathname); const target = path.resolve(publicRoot, `.${requestPath}`); if (target !== publicRoot && !target.startsWith(publicRoot + path.sep)) { res.writeHead(403); res.end('Forbidden'); return; } ``` - Apply an explicit allowlist if only `index.html` is required. - Use a maintained static-file middleware rather than implementing path handling manually. - Run the process as a low-privilege account with no access to unrelated credentials. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
server.cjs:11
Finding
Unauthenticated Cross-Origin Access to a Privileged OpenClaw Agent<![CDATA[ ## Vulnerability Details **File Location**: `server.cjs:11-14, 49-64, 88-98, 135-138` **Vulnerability Type**: Missing authentication, permissive CORS, and excessive agent privilege exposure **Risk Level**: Critical ### Vulnerable Code ```js const server = http.createServer(async (req, res) => { res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); ``` ```js // Chat API - calls openclaw agent CLI if (req.method === 'POST' && req.url === '/api/chat') { let body = ''; req.on('data', chunk => body += chunk); req.on('end', async () => { try { const { message } = JSON.parse(body); console.log(`👤 User: ${message}`); const response = await callOpenClaw(message); console.log(`🤖 Crow: ${response.substring(0, 100)}...`); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ response })); } catch (err) { console.error('Error:', err.message); res.writeHead(500, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: err.message })); } }); return; } ``` ```js const proc = spawn(OPENCLAW, args, { env: { ...process.env, NO_COLOR: '1' }, timeout: 180000 }); ``` ```js server.listen(PORT, () => { console.log(`🎤 Voice UI: http://localhost:${PORT}`); console.log(`🔗 Using OpenClaw agent: voice`); }); ``` ### Technical Analysis The `/api/chat` endpoint has no authentication or authorization. `Access-Control-Allow-Origin: *` permits scripts from any website to issue readable cross-origin requests, while `server.listen(PORT)` does not explicitly restrict the service to the loopback interface. Messages supplied by the remote client are forwarded to the configured `voice` agent. The spawned OpenClaw process inherits the server's complete environment and uses a persistent session identifier. The documen ...[truncated 1564 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Bind explicitly to the loopback interface: ```js server.listen(PORT, '127.0.0.1', () => { console.log(`Voice UI: http://127.0.0.1:${PORT}`); }); ``` - Require an unguessable authentication token for every API request. - Replace wildcard CORS with an exact trusted origin, or disable CORS if the UI and API share an origin. - Validate `Origin` and `Host` headers as defense in depth. - Add strict request-body size, rate, timeout, and concurrency limits. - Use a separate, minimally privileged OpenClaw agent with: - A dedicated workspace. - A filesystem allowlist. - No shell access unless indispensable. - No access to unrelated secrets. - Restricted Git capabilities. - Avoid a globally shared persistent session for untrusted callers. - Require explicit user approval before executing agent tool calls that modify state. - Run the server and agent in a sandbox or low-privilege operating-system account. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
index.html:257
Finding
DOM-Based Cross-Site Scripting in Chat Message Rendering<![CDATA[ ## Vulnerability Details **File Location**: `index.html:257-264` **Vulnerability Type**: DOM XSS through unsafe HTML interpolation **Risk Level**: High ### Vulnerable Code ```js function addMsg(role, txt) { const empty = chat.querySelector('.empty'); if (empty) empty.remove(); const d = document.createElement('div'); d.className = 'msg ' + (role === 'user' ? 'user' : 'bot'); d.innerHTML = `<div class="bubble">${txt.replace(/\n/g, '<br>')}</div>`; chat.appendChild(d); chat.scrollTop = chat.scrollHeight; } ``` ### Technical Analysis The `txt` value is inserted into `innerHTML` without escaping or sanitization. This value can originate from an OpenAI transcription, an OpenClaw response, or an OpenAI fallback response. All of these must be treated as untrusted. Replacing newline characters does not make HTML safe. If the value contains active HTML, event-handler attributes, SVG payloads, or similar browser-executable markup, the browser parses it as part of the application document. The absence of a restrictive Content Security Policy increases the available exploitation techniques. ### Attack Path 1. An attacker causes a transcript or model response to contain crafted HTML. 2. The response is passed to `addMsg()`. 3. `addMsg()` interpolates the value into `d.innerHTML`. 4. The browser parses and activates the injected markup. 5. The payload executes with the application's origin. 6. The payload can call same-origin API routes, alter the interface, read browser-accessible data, and exploit the local agent endpoint. One plausible source is an attacker-controlled prompt sent through the unauthenticated `/api/chat` endpoint that influences a model response later displayed by the UI. ### Impact Assessment Successful exploitation can provide execution in the application's browser origin, allowing an attacker to: - Send privileged same-origin requests to `/api/chat`. - Read any API responses available to the page. - Capture future trans ...[truncated 383 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Never render model or transcript data through `innerHTML`. Build the element and assign untrusted content through `textContent`: ```js function addMsg(role, txt) { const empty = chat.querySelector('.empty'); if (empty) empty.remove(); const wrapper = document.createElement('div'); wrapper.className = `msg ${role === 'user' ? 'user' : 'bot'}`; const bubble = document.createElement('div'); bubble.className = 'bubble'; bubble.textContent = String(txt); wrapper.appendChild(bubble); chat.appendChild(wrapper); chat.scrollTop = chat.scrollHeight; } ``` Preserve line breaks using CSS: ```css .bubble { white-space: pre-wrap; } ``` Also deploy a restrictive Content Security Policy, for example: ```http Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'none'; frame-ancestors 'none' ``` Move inline scripts and event handlers into a separate same-origin JavaScript file so that `unsafe-inline` is unnecessary. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
server.cjs:9
Finding
OpenAI Bearer Credential Is Designed to Be Exposed to Browser JavaScript<![CDATA[ ## Vulnerability Details **File Location**: `server.cjs:9, 41-45`; `index.html:242-243, 313-316, 339-342, 373-376` **Vulnerability Type**: Unsafe client-side secret exposure **Risk Level**: Medium ### Vulnerable Code ```js const OPENAI_KEY = process.env.OPENAI_API_KEY || ''; ``` ```js // API key endpoint if (req.method === 'GET' && req.url === '/api/key') { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ key: OPENAI_KEY })); return; } ``` ```js let KEY = null; fetch('/api/key').then(r => r.json()).then(d => KEY = d.key).catch(() => {}); ``` ```js const r1 = await fetch('https://api.openai.com/v1/audio/transcriptions', { method: 'POST', headers: { 'Authorization': `Bearer ${KEY}` }, body: form }); ``` ```js const r2 = await fetch('https://api.openai.com/v1/chat/completions', { method: 'POST', headers: { 'Authorization': `Bearer ${KEY}`, 'Content-Type': 'application/json' }, ``` ```js const r = await fetch('https://api.openai.com/v1/audio/speech', { method: 'POST', headers: { 'Authorization': `Bearer ${KEY}`, 'Content-Type': 'application/json' }, ``` ### Technical Analysis The application is designed to return the reusable OpenAI API key to browser JavaScript and use it directly in OpenAI requests. Browser-delivered bearer credentials cannot be kept secret from page scripts, extensions, developer tools, or an XSS payload. In the audited version, the `/api/key` branch is accidentally unreachable because the earlier generic GET handler returns before execution reaches it. Consequently, the current implementation generally fails to disclose the key but also breaks the advertised browser-side transcription and TTS workflow. The security defect will become directly exploitable if that routing error is corrected without changing the architecture. The key source is especially sensitive because `start.sh` may extract it from the user's broader OpenClaw configuration rather than from a narrowly s ...[truncated 1002 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Delete `/api/key`; never return reusable provider credentials to a browser. - Keep the OpenAI key exclusively in the backend process. - Implement narrow backend proxy endpoints for transcription and TTS. - Enforce authentication, rate limits, request-size limits, model allowlists, and spending controls on those endpoints. - Restrict accepted audio types and duration before sending content to OpenAI. - Use a dedicated, least-privileged API key for this application. - Rotate the existing key if it has ever been served to a browser. - Keep secrets out of global client-side variables and responses. ]]>

T01 · Skill Instruction Hijacking

Error
Location
CONTEXT.md:19
Finding
Untrusted Requests Can Trigger Overprivileged Self-Modification and Broad Git Staging<![CDATA[ ## Vulnerability Details **File Location**: `server.cjs:78-82`; `CONTEXT.md:19-25` **Vulnerability Type**: Unsafe agent-driven code modification and excessive Git scope **Risk Level**: High ### Vulnerable Code ```js function callOpenClaw(message) { return new Promise((resolve, reject) => { // Add context hint for UI changes let fullMessage = message; if (message.includes('voice-uiから')) { fullMessage = `${message}\n\n[コンテキスト: voice-uiアプリからのリクエストです。UIの変更は /Users/yuki/.openclaw/workspace/voice-ui/index.html を編集してください]`; } ``` ```markdown ## ⚠️ 変更後は必ずGitコミット! UIやコードを編集したら、必ず以下を実行: ```bash cd /Users/yuki/.openclaw/workspace/voice-ui && git add -A && git commit -m "変更内容の説明" ``` ``` ### Technical Analysis The self-modification feature intentionally gives natural-language requests a path to code-editing tools. The server trusts a user-controlled marker—`voice-uiから`—to add instructions directing the agent to edit a local file. No approval gate, diff validation, content safety check, or filesystem enforcement is implemented by this project. The associated context further directs the agent to execute `git add -A`, which stages every modification and untracked file in the repository rather than only the intended UI file. This design is particularly dangerous because `/api/chat` is unauthenticated. Although self-improvement is declared functionality, unrestricted tool access and repository-wide staging exceed the minimum privilege needed to update a single UI file. ### Attack Path 1. An attacker sends a request to the unauthenticated `/api/chat` endpoint. 2. The message contains the trusted marker `voice-uiから` and instructions framed as a UI change. 3. The server appends local file-editing context and forwards the combined message to OpenClaw. 4. Through prompt manipulation, the attacker attempts to make the tool-capable agent modify unintended code or add malicious content. 5. The project instructions require the agent to execute ...[truncated 877 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Do not allow arbitrary remote requests to invoke code-editing tools. - Require explicit, local user confirmation before applying any generated change. - Run modifications in a disposable copy or isolated branch. - Enforce the allowed target path outside the model prompt; do not rely on natural-language instructions. - Parse and validate the generated diff before application. - Reject changes that add external scripts, unsafe HTML sinks, credential access, new network destinations, or backend execution. - Stage only the intended file: ```bash git add -- index.html ``` - Display the complete diff and commit message to the user before committing. - Disable shell, filesystem, and Git tools not strictly required by the feature. - Use a dedicated low-privilege agent and workspace with no access to unrelated files or secrets. - Add automated security tests and a rollback mechanism for every generated change. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
Findings (29)

Context-Inappropriate Capability

High
Confidence
97% confidence
Finding
The page retrieves an API key into browser JavaScript and then uses it directly for OpenAI API calls. Any credential exposed to client-side code can be extracted by users, browser extensions, XSS, or devtools, enabling unauthorized API use and billing abuse.

Missing User Warnings

High
Confidence
95% confidence
Finding
The application records microphone input and transmits audio and conversation content to external services without clear, user-facing disclosure or consent messaging in the UI. Because voice data may contain sensitive personal information, silent exfiltration to third parties creates significant privacy and compliance risk.

Known Vulnerable Dependency: ws==8.19.0 — 2 advisory(ies): CVE-2026-45736 (ws: Uninitialized memory disclosure); CVE-2026-48779 (ws: Memory exhaustion DoS from tiny fragments and data chunks)

High
Category
Supply Chain
Confidence
98% confidence
Finding
The lockfile pins the project to ws 8.19.0, and the provided advisories indicate this version is affected by both uninitialized memory disclosure and memory-exhaustion denial of service issues. Because this skill is a voice assistant UI and likely exposes persistent WebSocket connections to clients, a vulnerable ws version is directly relevant and increases the chance that a remote attacker could leak process memory or crash/degrade the service through crafted traffic.

Known Vulnerable Dependency: ws==8.19.0 — 2 advisory(ies): CVE-2026-45736 (ws: Uninitialized memory disclosure); CVE-2026-48779 (ws: Memory exhaustion DoS from tiny fragments and data chunks)

High
Category
Supply Chain
Confidence
98% confidence
Finding
The package uses ws 8.19.0, which is identified as affected by memory disclosure and memory exhaustion denial-of-service vulnerabilities. Because this skill is a voice assistant UI and likely exposes a WebSocket server or client for real-time interaction, an attacker may be able to trigger information leakage or resource exhaustion remotely, making the context more dangerous than a non-networked utility.

Context-Inappropriate Capability

High
Confidence
98% confidence
Finding
The manifest describes a voice assistant UI that talks to an AI and updates code in real time, but this endpoint returns the raw OPENAI_API_KEY to callers. Exposing server-side credentials to arbitrary clients is a separate sensitive capability and not an obvious requirement for providing a voice UI.

Missing User Warnings

High
Confidence
98% confidence
Finding
This code serves the value of OPENAI_API_KEY directly from /api/key, which exposes a credential to any client that can access the server. Although the code labels it as an API key endpoint, there is no confirmation prompt, warning comment, or user-facing disclosure indicating that a sensitive environment variable will be transmitted over HTTP.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The context file directs the agent to perform a Git commit after making UI changes, which expands the agent's behavior from editing a local UI to mutating repository history. In a self-evolving skill, this is especially risky because user-triggered UI requests could cause persistent source control actions without an explicit, separate user confirmation step.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
Automatically staging and committing all changes with `git add -A && git commit` can capture unintended file modifications and permanently alter project history. Because this skill is designed to update code in response to natural-language requests, the instruction increases the chance of silent, user-unexpected persistence of AI-generated or accidental changes.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The README explicitly advertises self-modifying behavior (automatic code editing) and automatic Git commits, but it does not warn users that spoken or prompted instructions can cause persistent, potentially destructive changes to local code and repository state. In the context of an agentic tool that can modify files and commit them, lack of safety disclosure increases the chance that users will enable powerful behavior without understanding the risks of prompt injection, accidental destructive edits, or committing sensitive data.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The architecture section shows access to the filesystem, Git, and external APIs, but the documentation does not clearly warn that the skill can read/write local files, alter repository history/state, and transmit data to third-party services. This omission is dangerous because users may expose sensitive code, tokens, or local data to an agentic workflow without informed consent, especially given the self-evolving design and voice-driven interaction.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The documentation advertises spoken self-modification commands that automatically edit UI code and create Git commits, but it does not clearly warn users about the autonomous code-changing behavior before use. In a self-evolving skill, this is dangerous because a casual spoken request can trigger persistent source modifications and commit them, increasing the chance of unintended changes, prompt-injection-style abuse through voice input, or accidental propagation of harmful code.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The skill states that it uses OpenAI services for Whisper/TTS and may automatically retrieve API credentials from OpenClaw configuration, but it does not clearly disclose that user audio and credential-backed requests may be sent to external services. This creates privacy and consent risks, especially for voice data, and may surprise users who do not realize local interaction results in third-party transmission.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
The manifest description emphasizes asking the assistant to improve itself and watching code update in real time. In this file, the JavaScript handles microphone capture, transcription, chat completion, and text-to-speech, but there is no code-editing, self-modification, live reload, or code update behavior at all.

External Transmission

Medium
Category
Data Exfiltration
Content
try {
        if (!KEY) throw new Error('No API key');
        const r1 = await fetch('https://api.openai.com/v1/audio/transcriptions', {
          method: 'POST',
          headers: { 'Authorization': `Bearer ${KEY}` },
          body: form
Confidence
84% confidence
Finding
This code sends recorded audio to an external transcription API. External transmission is expected for cloud speech recognition, but in this skill it becomes security-relevant because sensitive microphone data is exported off-device and paired with a client-exposed API key design.

External Transmission

Medium
Category
Data Exfiltration
Content
try {
        if (!KEY) throw new Error('No API key');
        const r1 = await fetch('https://api.openai.com/v1/audio/transcriptions', {
          method: 'POST',
          headers: { 'Authorization': `Bearer ${KEY}` },
          body: form
Confidence
84% confidence
Finding
This code sends recorded audio to an external transcription API. External transmission is expected for cloud speech recognition, but in this skill it becomes security-relevant because sensitive microphone data is exported off-device and paired with a client-exposed API key design.

External Transmission

Medium
Category
Data Exfiltration
Content
if (!reply || reply.includes('Failed to call')) throw new Error('fallback');
        } catch {
          // Fallback to GPT
          const r2 = await fetch('https://api.openai.com/v1/chat/completions', {
            method: 'POST',
            headers: { 'Authorization': `Bearer ${KEY}`, 'Content-Type': 'application/json' },
            body: JSON.stringify({
Confidence
82% confidence
Finding
This request sends user chat content to an external LLM API. While such transmission is functional for the feature, it still creates privacy and data-governance risk because user speech-derived content is disclosed to a third party without strong disclosure or client/server isolation.

External Transmission

Medium
Category
Data Exfiltration
Content
if (!reply || reply.includes('Failed to call')) throw new Error('fallback');
        } catch {
          // Fallback to GPT
          const r2 = await fetch('https://api.openai.com/v1/chat/completions', {
            method: 'POST',
            headers: { 'Authorization': `Bearer ${KEY}`, 'Content-Type': 'application/json' },
            body: JSON.stringify({
Confidence
82% confidence
Finding
This request sends user chat content to an external LLM API. While such transmission is functional for the feature, it still creates privacy and data-governance risk because user speech-derived content is disclosed to a third party without strong disclosure or client/server isolation.

Natural-Language Policy Violations

Medium
Confidence
92% confidence
Finding
The system prompt explicitly says '日本語で話す', which forces a specific language behavior. There is no visible opt-in, language selector, or documented region-specific justification, so this is a natural-language locale policy concern.

External Transmission

Medium
Category
Data Exfiltration
Content
try {
        if (!KEY) return;
        const clean = txt.replace(/[\*\#\`\[\]]/g, '').substring(0, 300);
        const r = await fetch('https://api.openai.com/v1/audio/speech', {
          method: 'POST',
          headers: { 'Authorization': `Bearer ${KEY}`, 'Content-Type': 'application/json' },
          body: JSON.stringify({ model: 'tts-1', input: clean, voice: 'nova' })
Confidence
78% confidence
Finding
This sends assistant text to an external text-to-speech API, which may include sensitive derived content from the conversation. Although less severe than raw microphone upload, it still transmits conversational material to a third party and inherits the same disclosure and data-handling concerns.

External Transmission

Medium
Category
Data Exfiltration
Content
try {
        if (!KEY) return;
        const clean = txt.replace(/[\*\#\`\[\]]/g, '').substring(0, 300);
        const r = await fetch('https://api.openai.com/v1/audio/speech', {
          method: 'POST',
          headers: { 'Authorization': `Bearer ${KEY}`, 'Content-Type': 'application/json' },
          body: JSON.stringify({ model: 'tts-1', input: clean, voice: 'nova' })
Confidence
78% confidence
Finding
This sends assistant text to an external text-to-speech API, which may include sensitive derived content from the conversation. Although less severe than raw microphone upload, it still transmits conversational material to a third party and inherits the same disclosure and data-handling concerns.

Context-Inappropriate Capability

Medium
Confidence
86% confidence
Finding
The manifest frames the skill as a self-evolving voice assistant UI, but the code pulls an API credential from process.env. Accessing sensitive environment secrets is not an inherent or clearly justified requirement of a UI layer, especially when the same file also exposes that secret over HTTP.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The route order causes the broad GET static-file branch to intercept requests intended for /api/key, making documented API behavior inconsistent and unreachable. This is primarily a logic flaw, but it can create unsafe assumptions during development and lead to accidental later exposure of sensitive functionality when handlers are reordered without proper review.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
Arbitrary user input is forwarded directly into an external agent CLI that appears capable of acting on a local workspace and, per the skill description, updating code in real time. In this context, untrusted remote users may be able to induce the agent to modify files, leak local data, or perform other high-impact actions through prompt injection or tool misuse, especially with permissive CORS exposing the endpoint to any origin.

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
The code applies special behavior only when the input contains the Japanese phrase "voice-uiから", which imposes a language-specific activation condition without offering a language choice or documenting the constraint. This can create unequal behavior for users in other languages and fits the locale/language policy concern for natural-language handling.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The startup script automatically harvests an OpenAI API key from the user's broader OpenClaw configuration files and exports it into this skill's environment, even though the local voice UI should not implicitly depend on unrelated stored credentials. This creates unnecessary credential exposure and weakens isolation between skills: a compromised or modified skill can inherit and misuse API keys the user did not explicitly provide for this component.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
server.cjs:94