Voice UI
WarnAudited by ClawScan on May 10, 2026.
Overview
The voice UI purpose is coherent, but the included local server exposes powerful agent and file access without adequate safeguards.
Do not run this on an untrusted network or with valuable credentials until the server is locked to localhost, authenticated, path-safe, and requires review before code edits or commits. If you test it, use a throwaway workspace and scoped API keys.
Findings (6)
Artifact-based informational review of SKILL.md, metadata, install specs, static scan signals, and capability signals. ClawScan does not execute the skill or run runtime probes.
A webpage or another machine that can reach the port could ask the user's agent to act, potentially using tools or editing files as the user.
An unauthenticated HTTP endpoint forwards caller-controlled messages to the OpenClaw CLI, with permissive CORS and no explicit localhost-only bind.
res.setHeader('Access-Control-Allow-Origin', '*'); ... if (req.method === 'POST' && req.url === '/api/chat') { ... const response = await callOpenClaw(message); } ... const proc = spawn(OPENCLAW, args, { env: { ...process.env, NO_COLOR: '1' }, timeout: 180000 }); ... server.listen(PORTBind only to 127.0.0.1, remove wildcard CORS, add authentication/CSRF protection, and require explicit confirmation before any tool action that edits files or uses accounts.
A caller that can reach the server may be able to request parent-directory paths and read local files outside the skill directory, including configuration files.
The static file handler joins the raw request URL to the skill directory and reads it without normalizing and enforcing that it remains inside the intended static root.
let filePath = req.url === '/' ? '/index.html' : req.url; filePath = path.join(__dirname, filePath); ... const content = fs.readFileSync(filePath);
Serve only an allowlisted static directory, decode and normalize paths safely, reject any path that escapes the directory, and do not expose this server to the network.
A crafted message can be treated as a trusted voice-ui request and steer the agent into code-editing behavior.
A user-controlled phrase is used to add authoritative instructions that redirect the agent toward editing a local UI file.
if (message.includes('voice-uiから')) { fullMessage = `${message}\n\n[コンテキスト: voice-uiアプリからのリクエストです。UIの変更は /Users/yuki/.openclaw/workspace/voice-ui/index.html を編集してください]`; }Do not authenticate intent through prompt text; use server-side command parsing, authenticated UI actions, and user confirmation before code changes.
Anyone able to reach the endpoint may be able to use the user's configured agent, workspace, model access, and local credentials.
Requests run as the configured OpenClaw 'voice' agent with the server process environment and any inherited credentials, without checking who made the request.
const args = ['agent', '--agent', 'voice', '--session-id', 'voice-ui', '-m', fullMessage, '--json']; ... spawn(OPENCLAW, args, { env: { ...process.env, NO_COLOR: '1' } })Use a least-privilege agent profile, require local authentication, avoid inheriting broad environment credentials, and restrict available tools for voice-ui requests.
A malicious or accidental HTML/script response could run inside the local UI and call the same local endpoints.
User transcripts and agent replies are inserted as HTML instead of text, so untrusted content can become executable browser markup.
d.innerHTML = `<div class="bubble">${txt.replace(/\n/g, '<br>')}</div>`;Render chat text with textContent or a strict sanitizer, and avoid allowing model output to become HTML.
Voice requests can result in persistent code changes rather than only temporary UI behavior.
The skill intentionally persists self-modifications through Git commits. This is disclosed and purpose-aligned, but it changes local code and history.
UIやコードを編集したら、必ず以下を実行: cd /Users/yuki/.openclaw/workspace/voice-ui && git add -A && git commit -m "変更内容の説明"
Use this only in a disposable or version-controlled workspace, review diffs before trusting changes, and keep backups.
