Back to skill

Security audit

WebChat Voice GUI

Security checks for vulnerabilities and agentic risk

Overview

This skill provides the advertised local voice-input feature, but it also installs a persistent startup hook that keeps rewriting the OpenClaw Control UI with browser JavaScript from a mutable workspace file.

Install only if you are comfortable with a skill patching your local OpenClaw Control UI and installing a startup hook that re-applies JavaScript after updates. Review who can modify ~/.openclaw/workspace/voice-input/voice-input.js, keep the workspace protected, and consider disabling or uninstalling the hook if you do not need update-survival behavior.

Vulnerability Patterns
  • System PersistenceInstalls backdoors, hooks, services, or scheduled tasks that survive the run
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T06 · System Persistence

Error
Location
scripts/deploy.sh:79
Finding
Persistent Gateway Startup Hook Promotes User-Writable JavaScript into the Control UI<![CDATA[ ## Vulnerability Details **File Location**: `scripts/deploy.sh:79-85`, `hooks/handler.ts:7-15`, `hooks/inject.sh:27-34` **Vulnerability Type**: Persistent startup code execution **Risk Level**: High ### Vulnerable Code #### `scripts/deploy.sh:79-85` ```bash # 3) Install gateway startup hook (survives openclaw update) HOOK_DIR="$HOME/.openclaw/hooks/voice-input-inject" mkdir -p "$HOOK_DIR" cp -f "$SKILL_DIR/hooks/handler.ts" "$HOOK_DIR/handler.ts" cp -f "$SKILL_DIR/hooks/inject.sh" "$HOOK_DIR/inject.sh" cp -f "$SKILL_DIR/hooks/HOOK.md" "$HOOK_DIR/HOOK.md" chmod +x "$HOOK_DIR/inject.sh" ``` #### `hooks/handler.ts:7-15` ```ts const handler = async (event: any) => { if (event.type !== "gateway" || event.action !== "startup") return; // SECURITY: execFileSync with array args — no shell interpolation. // Script path is derived from __dirname (relative to this file), not user input. const script = join(__dirname, "inject.sh"); try { execFileSync("bash", [script], { timeout: 10_000, ``` #### `hooks/inject.sh:27-34` ```bash cp -f "$SRC" "$ASSET_DIR/voice-input.js" if ! grep -q "$MARKER" "$INDEX" 2>/dev/null; then # SECURITY: sed uses only hardcoded strings — no variable interpolation. sed -i 's|</body>| <script src="./assets/voice-input.js"></script>\n </body>|' "$INDEX" echo "[voice-input-inject] Injected into $INDEX" else echo "[voice-input-inject] Already present in $INDEX" ``` ### Technical Analysis Deployment creates a persistent OpenClaw gateway startup hook under `~/.openclaw/hooks/voice-input-inject`. Whenever the gateway emits a startup event, `handler.ts` invokes `inject.sh` through Bash. The script then copies `~/.openclaw/workspace/voice-input/voice-input.js` into the trusted OpenClaw Control UI asset directory and ensures that `index.html` loads it. Although `execFileSync` avoids shell-argument injection, it does not address the trust-boundary problem. The startup hook treats a workspace file as truste ...[truncated 2157 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. **Remove automatic startup reinjection** - Do not execute a Bash reinjection script on every gateway startup. - Prefer an officially supported OpenClaw extension or plugin mechanism that preserves clear package ownership and lifecycle controls. 2. **Use an immutable or package-controlled source** - Do not copy executable browser code from a general workspace directory. - Keep the canonical asset in an installation directory that is not writable by unrelated workspace operations. 3. **Verify integrity before every deployment** - Pin an expected SHA-256 digest for `voice-input.js`. - Refuse to copy the file when its digest differs from the approved value. - For updateable distributions, verify a trusted digital signature rather than relying only on a locally writable checksum. 4. **Apply restrictive permissions** - Ensure the hook and source asset are owned by the expected user. - Reject symbolic links and files with unexpected ownership or permissions. - Open and validate the source safely before copying it to reduce path-substitution risks. 5. **Limit persistence** - Require explicit user confirmation before restoring UI modifications after an update. - Record reinjection activity and integrity-check failures in an auditable log. - Provide a supported mechanism to disable or remove the hook without executing additional unverified workspace content. 6. **Deploy atomically** - Copy a verified asset to a temporary file in the destination directory. - Revalidate it and atomically rename it into place. - Preserve a known-good backup of `index.html` and avoid broad text substitution when a structured extension mechanism is available. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (16)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The skill is presented primarily as a voice-input UI enhancement, but it also persistently injects JavaScript into the Control UI and installs a gateway startup hook that re-applies the patch after updates. Persistent code injection and startup execution materially increase risk because they create a durable mechanism to modify trusted UI code and can be repurposed for credential theft, UI tampering, or broader compromise if the injected asset or hook is changed.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
# 2) Remove voice-input.js from Control UI and undo index.html injection
echo "[2/3] Reverting Control UI..."
if [[ -f "$ASSET_DIR/voice-input.js" ]]; then
  rm -f "$ASSET_DIR/voice-input.js"
  echo "      removed: voice-input.js asset"
fi
Confidence
95% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
# 3) Remove workspace runtime files (voice-input.js, i18n.json)
echo "[3/3] Removing workspace runtime files..."
rm -f "$VOICE_DIR/voice-input.js" "$VOICE_DIR/i18n.json"
rmdir "$VOICE_DIR" 2>/dev/null && echo "      removed: $VOICE_DIR" || true

# Restart gateway
Confidence
95% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill declares shell and network-relevant behavior in its metadata and description, but does not define an explicit tool scope such as permissions or allowed-tools. This weakens reviewability and enforcement because a skill that modifies installed UI files, installs a persistent startup hook, and depends on local network services should clearly declare the operational capabilities it needs.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
- VOICE_LANG (optional, default: auto — prompts interactively if not set)
  persistence:
    - "Gateway startup hook: voice-input-inject (re-injects JS after updates)"
  privileges: user-level only, no root/sudo required
  dependencies:
    - faster-whisper transcription service on port 18790
---
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Natural-Language Policy Violations

Medium
Confidence
87% confidence
Finding
The file includes a dedicated Chinese locale block alongside English and German, but the content itself does not show any mechanism for user opt-in or locale selection policy. Under the language/locale policy rule, hard-coded locale behavior can be problematic unless the skill explicitly offers a choice or documents why the locale is constrained.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The code captures microphone audio and posts it to a transcription endpoint via fetch, but the UI shown here does not provide a clear privacy disclosure about where audio is sent, what service processes it, or what trust boundary applies. Although browser mic permission is required and the metadata claims 'local' transcription, the implementation may send audio to same-origin /transcribe or localhost, so users can be misled into sharing sensitive speech without informed consent.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
In continuous mode, transcribed text is automatically sent after a short 2-second review window unless the user focuses or clicks the textarea. This can cause unintended transmission of sensitive or erroneous speech-derived content into the chat workflow, especially because speech recognition errors, ambient audio, or stop-keyword misses may result in content being sent without explicit confirmation.

Context-Inappropriate Capability

Medium
Confidence
84% confidence
Finding
This code imports child_process and invokes bash to run inject.sh on startup. Spawning an external process is a privileged operational capability that is not obviously required for microphone capture, local STT, VU metering, or keyboard shortcuts as described in the manifest, aside from a vague note about a gateway hook.

Description-Behavior Mismatch

Medium
Confidence
89% confidence
Finding
The manifest focuses on microphone UI, recording, local transcription, and keyboard controls, with only a brief mention of a 'gateway hook for update safety.' In this file, the implemented behavior is launching an external bash script during gateway startup to modify the Control UI, which is a materially different operational capability than the user-facing voice features described.

Description-Behavior Mismatch

Medium
Confidence
84% confidence
Finding
The manifest primarily describes UI voice-input behavior and mentions an 'update safety' gateway hook, but this script performs direct file-system modification of the Control UI distribution by copying a script into assets and rewriting index.html. That install-time patching behavior is not clearly conveyed by the main description and is broader than merely providing microphone/transcription functionality.

External Transmission

Medium
Category
Data Exfiltration
Content
Checks:
```bash
systemctl --user status openclaw-transcribe.service
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:18790/transcribe -X POST -H 'Content-Type: application/octet-stream' --data-binary 'x'
```

If this is down/missing, voice input will not produce text.
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Context-Inappropriate Capability

Medium
Confidence
84% confidence
Finding
Checking and interacting with systemd user services, plus restarting the OpenClaw gateway, is a host-level operational capability not inherently required just to provide browser microphone input and local transcription UI. While adjacent to deployment, it expands the skill's effective control over local runtime services beyond the core voice-button purpose described in the manifest.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The script copies assets into the workspace and Control UI directories, patches JavaScript with `sed`, modifies `index.html`, and installs hook files, all without an explicit warning or confirmation to the user. Silent modification of application files and startup behavior is risky because users may not realize they are granting persistent code execution and altering the UI's trusted contents.

Description-Behavior Mismatch

Medium
Confidence
92% confidence
Finding
The deploy script installs a persistent gateway hook under the user's OpenClaw hooks directory, which causes code from this skill to survive normal UI updates and continue executing later. Persistence mechanisms are security-relevant because they expand the trust boundary from a one-time UI asset copy to ongoing code execution, and the script does not present explicit consent or integrity checks for the hook contents.

Missing User Warnings

Low
Confidence
82% confidence
Finding
The script restarts the OpenClaw gateway automatically and suppresses output, which can disrupt active sessions and applies newly installed hook behavior immediately without the user noticing. While low severity on its own, automatic service restarts reduce user awareness and compound the persistence risk introduced earlier in the script.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
hooks/handler.ts:14