Back to skill

Security audit

Voice Log

Security checks for vulnerabilities and agentic risk

Overview

This is a disclosed voice-journaling skill that records microphone audio, sends it to Soniox for transcription, and stores a rolling local transcript while running.

Install only if you are comfortable with a background process recording microphone audio, sending it to Soniox, and keeping a rolling local transcript for up to 60 minutes. Stop it when finished, avoid using it around people who have not consented, and consider pinning the Soniox dependency before sensitive use.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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)

T09 · Insecure Skill Coding Practices

Note
Location
scripts/voice_journal_ctl.js:66
Finding
Unverified Stale PID Can Terminate an Unrelated Process<![CDATA[ ## Vulnerability Details **File Location**: `scripts/voice_journal_ctl.js`, lines 66–70 and 143–149 **Vulnerability Type**: Improper process identity validation **Risk Level**: Low ### Vulnerable Code ```javascript function readPid() { if (!fs.existsSync(paths.pid)) return null; const raw = fs.readFileSync(paths.pid, "utf8").trim(); const pid = Number(raw); return Number.isInteger(pid) ? pid : null; } ``` ```javascript async function end() { const pid = readPid(); if (!pid || !isPidRunning(pid)) { console.log("Voice journal is not running."); return; } process.kill(pid, "SIGTERM"); ``` The process-liveness check used before termination is: ```javascript function isPidRunning(pid) { if (!Number.isInteger(pid) || pid <= 1) return false; try { process.kill(pid, 0); return true; } catch (_) { return false; } } ``` ### Technical Analysis The controller treats the numeric value in `.data/daemon.pid` as sufficient proof of the daemon's identity. The `isPidRunning()` function establishes only that a process currently owns the PID; it does not establish that the process is the voice journal daemon started by this Skill. If the daemon exits abnormally, such as through `SIGKILL`, a system crash, or another path that bypasses its shutdown cleanup, its PID file can remain in place. Operating systems eventually reuse process identifiers. Once the stale PID is assigned to another same-user process, the `end` command considers that unrelated process to be the active daemon and sends it `SIGTERM`. The `.data` directory is hardened to mode `0700` and files to `0600`, which limits cross-user tampering. However, those permissions do not prevent natural PID reuse or manipulation by another process operating under the same user account. ### Attack Path 1. Start the voice journal so that the daemon writes its PID to `.data/daemon.pid`. 2. Cause the daemon to exit without executing its normal shutdown cleanup, for examp ...[truncated 1051 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Use an authenticated daemon-control mechanism rather than relying solely on a reusable numeric PID: 1. **Preferred approach: authenticated local IPC** - Create a Unix-domain socket inside the permission-restricted `.data` directory. - Generate a cryptographically random instance token when starting the daemon. - Require the controller to present that token over the socket. - Let the daemon perform its own authenticated shutdown after receiving the request. 2. **Use exclusive process locking** - Hold an exclusive lock for the daemon's lifetime. - Treat a PID file without a corresponding live lock as stale. - Remove stale state before starting or stopping a daemon. 3. **Validate process identity before signaling** - Record additional startup identity information, such as the daemon's executable path, script path, process start time, and a random instance identifier. - Before sending a signal, verify the target's command line and start time using an operating-system-specific process interface. - Do not signal the process if any identity attribute differs. 4. **Improve stale-state cleanup** - On startup and before shutdown, detect PID files that do not correspond to a verified daemon instance and remove them safely. - Continue removing the PID file during graceful shutdown, while recognizing that cleanup alone cannot handle `SIGKILL` or system crashes. 5. **Fail closed** - If process identity cannot be established reliably, report stale or unverifiable daemon state and require manual cleanup rather than sending `SIGTERM`. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (19)

Context Leakage

High
Category
Data Exfiltration
Content
metadata: {"openclaw":{"requires":{"bins":["node","arecord|rec|ffmpeg"],"env":{"SONIOX_API_KEY":"required - Soniox API key"},"note":"Captures microphone audio locally and streams audio to Soniox realtime STT only while journal is running."}}}
---

# Voice log

Conversation journal that uses Soniox realtime STT in a background daemon that:
- Captures microphone audio continuously.
Confidence
96% confidence
Finding
This skill is explicitly designed to capture microphone audio continuously, convert it to text, and store conversation logs, which creates a real context-leakage path for sensitive spoken information. The risk is elevated because data is both transmitted to a cloud STT provider and retained locally, so confidential discussions, bystander speech, or unrelated secrets may be exposed.

Ae1

High
Category
analysis-evasion
Content
node scripts/voice_journal_ctl.js start
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/voice_journal_ctl.js start
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/voice_journal_ctl.js start
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/voice_journal_ctl.js start
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/voice_journal_ctl.js start
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/voice_journal_ctl.js start
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/voice_journal_ctl.js start
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/voice_journal_ctl.js start
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/voice_journal_ctl.js start
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill declares environment requirements and operational behavior but does not define an explicit tool/permission scope. In an agent setting, missing scope boundaries can let the runtime or orchestrator invoke the skill without clear consent or least-privilege controls, especially for microphone capture and external network use.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The description enables passive microphone capture and cloud transcription without a prominent privacy warning. Users may trigger the skill without understanding that ambient speech will be captured and sent to a third-party service, creating consent and data exposure risks.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The manifest explicitly advertises background speech-to-text, rolling logs, and conversation recap, but it does not disclose that audio may be continuously captured and sent to a third-party provider using a required Soniox API key. In a voice journaling skill, this omission is security-relevant because users may trigger passive logging without understanding the privacy implications, leading to unintended collection, retention, or transmission of sensitive conversations.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The `last()` command prints raw journal transcript content directly to stdout, which can expose highly sensitive personal speech data to any caller, logs, terminal history, or upstream agent without an explicit warning, confirmation, or access-control check. In this skill’s context, the data is especially privacy-sensitive because it captures passive/background conversation, so accidental disclosure is a realistic risk even if the behavior is intentional.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
This daemon captures microphone audio continuously and sends it to Soniox for transcription, but this file contains no user-facing notice, consent check, or runtime indicator before recording/transmission begins. In the context of a background voice journaling skill, silent capture and export of ambient speech can expose highly sensitive conversations and create significant privacy and compliance risk if started unexpectedly or without explicit informed consent.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The skill explicitly performs background speech-to-text logging and requires a third-party Soniox API key, yet the user-facing description does not clearly warn that live conversation audio may be captured and transmitted to an external service. This creates a meaningful privacy and consent risk because users may enable passive logging without understanding that sensitive speech could be recorded and shared off-device.

Missing User Warnings

Low
Confidence
92% confidence
Finding
The skill states that it keeps a text-only log for the latest 60 minutes, but this retention is not surfaced as an explicit privacy warning in the user-facing description. Hidden or understated retention increases the chance that sensitive conversation content is stored locally without informed user awareness.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"last-journal": "node scripts/voice_journal_ctl.js last"
  },
  "dependencies": {
    "@soniox/node": "^1.1.1"
  }
}
Confidence
80% confidence
Finding
The dependency uses a caret range, which allows automatic adoption of future 1.x releases of @soniox/node without review. For a skill that captures and transmits live conversation data, an unexpected upstream change or compromised release could alter data handling or introduce malicious behavior into a highly sensitive execution path.

Missing User Warnings

Low
Confidence
90% confidence
Finding
The code writes transcribed speech into local journal files, but this file provides no disclosure to the user that conversation content will be retained on disk. Even with best-effort file permission hardening, local persistence of sensitive transcripts increases exposure to later unauthorized access, accidental sharing, or forensic recovery, especially on shared or lightly managed systems.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/voice_journal_ctl.js:102

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/voice_journal_daemon.js:146