Back to skill

Security audit

Local STT (Nvidia Parakeet + Whisper Support)

Security checks for vulnerabilities and agentic risk

Overview

This local transcription skill mostly does what it says, but its optional Matrix feature handles transcripts and credentials in ways users should review carefully.

Install only if you are comfortable with an optional Matrix mode that can send generated transcripts to a configured homeserver. Avoid using --room-id for sensitive audio unless MATRIX_HOMESERVER is HTTPS, use a narrowly scoped Matrix token, and be aware that the script may read generic home .env files and write Matrix metadata to /tmp/stt_matrix.log.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (4)

T08 · Insecure Dependencies

Error
Location
scripts/local-stt.py:1
Finding

Automatic Execution of Unpinned Third-Party Dependencies

Content
View full analysis
=3.12" # dependencies = [ # "onnx-asr", # "onnxruntime", # "huggingface_hub", # "click", # "requests", # ] ``` ### Technical Analysis The script uses `uv run --script` to resolve and execute third-party packages without exact version constraints or cryptographic hashes. Dependency resolution can therefore select newer package releases that were not present during the security review. This creates a supply-chain risk because package installation and import-time initialization occur within the Skill's execution context. If a listed package, its transitive dependencies, or the relevant package registry is compromised, malicious code could execute when the Skill is invoked. ### Attack Path 1. An attacker compromises a listed dependency, one of its transitive dependencies, or its package registry entry. 2. The attacker publishes a malicious release that still satisfies the unrestricted dependency declaration. 3. A user invokes `local-stt.py`. 4. `uv` resolves or installs the malicious release. 5. Malicious initialization or imported package code executes with the permissions of the Skill process. 6. The malicious package can inspect audio files, transcripts, environment variables, and other resources accessible to that process. ### Impact Assessment Successful exploitation permits arbitrary Python code execution with the privileges of the user running the Skill. The accessible scope may include input audio, generated transcripts, local files readable by the user, process environment variables, and Matrix credentials if the Matrix functionality is used. This does not itself grant elevated operating-system privileges, but it exposes the full authority already available to the Skill ...[truncated 15 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/local-stt.py:43
Finding

Excessive Import of Secrets from Home-Directory Environment Files

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/local-stt.py:65
Finding

Matrix Credentials and Transcripts Can Be Sent over Plaintext HTTP

Content
View full analysis
🎙️ {text}' } with open("/tmp/stt_matrix.log", "a") as log: log.write(f"Attempting send to {room_id} at {txn_id}\n") log.write(f"URL: {url}\n") resp = requests.put(url, headers=headers, json=payload, timeout=10) ``` ### Technical Analysis `MATRIX_HOMESERVER` is used directly to construct the destination URL without validating its scheme. If the value begins with `http://`, the bearer access token and transcript are transmitted without transport encryption. The authorization token is placed in the request header, while the transcript is included in the JSON body. Plaintext HTTP allows network observers or an active man-in-the-middle attacker to read both values and potentially modify the request. The network transmission itself is an explicitly documented, opt-in feature activated by `--room-id`; it is not covert exfiltration. However, allowing insecure transport i ...[truncated 977 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/local-stt.py:84
Finding

Predictable Shared Temporary Log File Permits Metadata Disclosure and Symlink Attacks

Content
View full analysis
Remediation
View remediation
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
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (13)

Tainted flow: 'url' from os.environ.get (line 90, credential/environment) → requests.put (network output)

Critical
Category
Data Flow
Confidence
95% confidence
Finding

The script reads Matrix homeserver and access token values from local environment/.env files and uses them to send transcribed speech to a remote server. In a skill described as local STT, this creates an unexpected exfiltration path for potentially sensitive audio-derived content and relies on attacker-influenced configuration for the destination URL.

Content

Scanner excerpt · scripts/local-stt.py (reported line 103)May include surrounding context.

python
log.write(f"Attempting send to {room_id} at {txn_id}\n")
            log.write(f"URL: {url}\n")

        resp = requests.put(url, headers=headers, json=payload, timeout=10)

        with open("/tmp/stt_matrix.log", "a") as log:
            log.write(f"Response: {resp.status_code}\n")

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

This is a strong description-behavior mismatch: the skill is presented as local speech-to-text, but static analysis indicates it also reads local credential files, uses Matrix tokens, writes debug logs, and sends transcription data over the network. Hidden credential access and silent exfiltration of transcript content materially change the trust model and can expose sensitive spoken data or secrets.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The stated purpose emphasizes local speech-to-text, but the implementation can also transmit transcriptions to a Matrix room over the network. This mismatch is security-relevant because users may supply sensitive audio under the assumption that processing remains local, making the hidden outbound capability more dangerous.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
88% confidence
Finding

Accessing ~/.openclaw/.env to load Matrix credentials gives the skill access to secrets unrelated to basic local transcription. Secret access is more sensitive here because it enables authenticated external posting and is performed automatically rather than through narrowly scoped configuration.

Content

Scanner excerpt · scripts/local-stt.py (reported line 49)May include surrounding context.

python
def load_env_file():
    """Load .env file from home directory if it exists."""
    env_paths = [Path.home() / ".openclaw" / ".env", Path.home() / ".env"]
    for env_path in env_paths:
        if env_path.exists():

Credential Access

High
Category
Privilege Escalation
Confidence
88% confidence
Finding

Accessing ~/.env broadens the credential surface even further by pulling from a generic user-level secrets file. This can unintentionally consume unrelated tokens and silently empower the skill to perform authenticated network operations beyond its advertised local role.

Content

Scanner excerpt · scripts/local-stt.py (reported line 50)May include surrounding context.

python
def load_env_file():
    """Load .env file from home directory if it exists."""
    env_paths = [Path.home() / ".openclaw" / ".env", Path.home() / ".env"]
    for env_path in env_paths:
        if env_path.exists():
            with open(env_path) as f:

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

Outbound HTTP requests to a Matrix homeserver are not justified by the core function of local transcription and create a clear external data-transfer capability. Because the transmitted payload contains the transcription text, this can expose private spoken content to remote infrastructure unexpectedly.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
86% confidence
Finding

The skill advertises a simple local STT capability, but the detected capabilities include network, shell, environment access, and file writing without any declared tool scope or permissions boundary. That lack of transparency increases the risk that the skill can access credentials, write files, or transmit data in ways users and reviewers would not expect.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The documentation mentions a Matrix room option but does not clearly warn that audio-derived transcript content may be forwarded externally. Because transcripts can contain highly sensitive spoken information, failing to disclose onward transmission creates privacy and data-handling risk, especially in a skill marketed as local STT.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

The Parakeet default is set to an English-only model, while the file also defines multilingual alternatives. Because this default applies unless the user explicitly overrides it, the skill effectively privileges one language without an opt-in choice or clear justification.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill reads credentials from ~/.openclaw/.env and ~/.env to enable message posting, which exceeds what is necessary for local transcription. Broad credential loading increases the chance of unanticipated secret use and makes the skill capable of authenticating to external services without explicit per-run user intent.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

When sending to Matrix, the code appends room and request metadata to /tmp/stt_matrix.log, creating persistent local output that may expose user activity. Although the network send is documented, there is no visible warning, prompt, or stdout/stderr disclosure that this separate log file will be created.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
94% confidence
Finding

This request sends transcription data to an external Matrix server, which is a direct external transmission of potentially sensitive content. In the context of a supposedly local STT skill, that outbound flow is more dangerous because users may not expect any network disclosure.

Content

Scanner excerpt · scripts/local-stt.py (reported line 103)May include surrounding context.

python
log.write(f"Attempting send to {room_id} at {txn_id}\n")
            log.write(f"URL: {url}\n")

        resp = requests.put(url, headers=headers, json=payload, timeout=10)

        with open("/tmp/stt_matrix.log", "a") as log:
            log.write(f"Response: {resp.status_code}\n")

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/local-stt.py (reported line 158)May include surrounding context.

python
tmp_path = tmp.name

    try:
        subprocess.run(
            ['ffmpeg', '-y', '-i', audio_file, '-ar', '16000', '-ac', '1', tmp_path],
            capture_output=True, check=True
        )

Static analysis

No suspicious patterns detected.