T05 · Unauthorized Access and Privilege Escalation
- Location
server.cjs:21- Finding
Arbitrary Local File Disclosure Through Path Traversal
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
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.
server.cjs:21Arbitrary Local File Disclosure Through Path Traversal
server.cjs:11Unauthenticated Cross-Origin Access to a Privileged OpenClaw Agent
index.html:257DOM-Based Cross-Site Scripting in Chat Message Rendering
server.cjs:9OpenAI Bearer Credential Is Designed to Be Exposed to Browser JavaScript
CONTEXT.md:19Untrusted Requests Can Trigger Overprivileged Self-Modification and Broad Git Staging
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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
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.
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
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.
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({
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.
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({
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.
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.
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' })
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.
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' })
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.
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.
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.
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.
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.
Detected: suspicious.dangerous_exec