Back to skill

Security audit

Omi Integration

Security checks for vulnerabilities and agentic risk

Overview

This skill is mostly an Omi recording sync tool, but it handles private transcripts and credentials with under-disclosed security risks, especially an unauthenticated public webhook path.

Review before installing. Use this only on a machine where storing private transcripts locally is acceptable, set a strong OMI_WEBHOOK_SECRET before exposing any webhook, avoid public ngrok exposure unless needed, restrict permissions on config and recording directories, validate any self-hosted backend URL before use, and treat the API key as plaintext despite the documentation's encryption claim.

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 (5)

T09 · Insecure Skill Coding Practices

Error
Location
webhook-server.py:16
Finding

Public Webhook Endpoint Accepts Unauthenticated Data-Writing Requests

Content
View full analysis
/tmp/ngrok.log 2>&1 & NGROK_PID=$! # Wait for ngrok to start sleep 3 # Get public URL from ngrok API NGROK_URL=$(curl -s http://localhost:4040/api/tunnels | jq -r '.tunnels[0].public_url') ``` ```bash # omi-webhook-handler.sh RECORDING_ID=$(echo "$PAYLOAD" | jq -r '.data.id // .recording_id') CREATED_AT=$(echo "$PAYLOAD" | jq -r '.data.created_at // .created_at // now | strftime("%Y-%m-%dT%H:%M:%SZ")') DATE_DIR=$(echo "$CREATED_AT" | cut -d'T' -f1) REC_DIR="$STORAGE_DIR/$DATE_DIR/$RECORDING_ID" mkdir -p "$REC_DIR" # Save metadata echo "$PAYLOAD" | jq '.data // .' > "$REC_DIR/metadata.json" # Save transcript if available TRANSCRIPT=$(echo "$PAYLOAD" | jq -r '.data.transcript // .transcript // empty') if [[ -n "$TRANSCRIPT" ]]; then echo "$TRANSCRIPT" > "$REC_DIR/transcript.txt" fi ``` ### Technical Analysis Authentication is conditional on `OMI_WEBHOOK_SECRET` being non-empty. The default value is empty, and the supplied startup workflow does not require or automatically create a secret. Consequently, requests are accepted without authentication in the default configuration. The server binds to all network interfaces, and the documented ngrok workflow exposes the ser ...[truncated 1626 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
omi-webhook-handler.sh:29
Finding

Untrusted Recording Identifiers Permit Directory Traversal

Content
View full analysis
"$REC_DIR/metadata.json" # Save transcript if available TRANSCRIPT=$(echo "$PAYLOAD" | jq -r '.data.transcript // .transcript // empty') if [[ -n "$TRANSCRIPT" ]]; then echo "$TRANSCRIPT" > "$REC_DIR/transcript.txt" fi ``` ```bash # omi-sync.sh RECORDING_ID=$(echo "$recording" | jq -r '.id') CREATED_AT=$(echo "$recording" | jq -r '.created_at') DATE_DIR=$(echo "$CREATED_AT" | cut -d'T' -f1) REC_DIR="$STORAGE_DIR/$DATE_DIR/$RECORDING_ID" mkdir -p "$REC_DIR" echo "Syncing: $RECORDING_ID" | tee -a "$LOG_FILE" # Save metadata echo "$recording" | jq '.' > "$REC_DIR/metadata.json" # Fetch full transcript TRANSCRIPT=$(curl -s -H "Authorization: Bearer $API_KEY" \ "$BACKEND_URL/recordings/$RECORDING_ID/transcript") if [[ -n "$TRANSCRIPT" ]] && [[ "$TRANSCRIPT" != "null" ]]; then echo "$TRANSCRIPT" | jq -r '.transcript // .text // .' > "$REC_DIR/transcript.txt" fi # Fetch summary if available SUMMARY=$(curl -s -H "Authorization: Bearer $API_KEY" \ "$BACKEND_URL/recordings/$RECORDING_ID/summary") if [[ -n "$SUMMARY" ]] && [[ "$SUMMARY" != "null" ]]; then echo "$SUMMARY" | jq -r '.summary // .' > "$REC_DIR/summary.md" fi ``` ### Technical Analysis The scripts insert externally supplied recording identifiers directly into filesystem paths. No allowlist validation, canonicalization, or containment check is performed. Shell quoting prevents word splitting but ...[truncated 1744 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
omi-sync.sh:56
Finding

Bearer API Key May Be Transmitted to an Insecure or Unintended Backend

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
omi-webhook-handler.sh:7
Finding

Sensitive Webhook and Recording Content Is Stored with Unenforced Permissions

Content
View full analysis
> "$WEBHOOK_LOG" echo "$PAYLOAD" | jq '.' >> "$WEBHOOK_LOG" ``` ```bash # omi-webhook-handler.sh # Save metadata echo "$PAYLOAD" | jq '.data // .' > "$REC_DIR/metadata.json" # Save transcript if available TRANSCRIPT=$(echo "$PAYLOAD" | jq -r '.data.transcript // .transcript // empty') if [[ -n "$TRANSCRIPT" ]]; then echo "$TRANSCRIPT" > "$REC_DIR/transcript.txt" fi ``` ```bash # omi-sync.sh # Save metadata echo "$recording" | jq '.' > "$REC_DIR/metadata.json" # Fetch full transcript TRANSCRIPT=$(curl -s -H "Authorization: Bearer $API_KEY" \ "$BACKEND_URL/recordings/$RECORDING_ID/transcript") if [[ -n "$TRANSCRIPT" ]] && [[ "$TRANSCRIPT" != "null" ]]; then echo "$TRANSCRIPT" | jq -r '.transcript // .text // .' > "$REC_DIR/transcript.txt" fi # Fetch summary if available SUMMARY=$(curl -s -H "Authorization: Bearer $API_KEY" \ "$BACKEND_URL/recordings/$RECORDING_ID/summary") if [[ -n "$SUMMARY" ]] && [[ "$SUMMARY" != "null" ]]; then echo "$SUMMARY" | jq -r '.summary // .' > "$REC_DIR/summary.md" fi ``` ```markdown ## Privacy - All data stored locally - API key encrypted at rest - Self-hosted backend supported - No telemetry or tracking - Webhook payloads logged for debugging (optional) ``` ### Technical Analysis The handler unconditionally writes the complete webhook payload to `.webhook.log`, potentially duplicating transcripts, device information, identifiers, and other private metadata. Logging is not optional ...[truncated 1588 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
webhook-server.py:38
Finding

Webhook Server Reads Unbounded Request Bodies

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
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (34)

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The declared purpose emphasizes synchronization from Omi/Limitless devices or services via API/webhooks, automatic transcript syncing, and processing/organization workflows. The actual code is a local inspection utility: it reads metadata.json and transcript.txt files under $HOME/omi_recordings, filters by date, and displays recording details. While this may be related to the broader Omi recordings domain, the code chunk’s primary behavior is materially different from the declared sync functionality and omits the advertised remote integration capabilities.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The code substantially aligns with the general theme of syncing Omi recordings and transcripts from an API to local storage, but the declared description overstates several capabilities. There is no webhook handling or trigger mechanism at all, only a command-line batch sync using a time filter. The storage layout is by date and recording ID, not by device. The script also does not meaningfully 'process recordings' beyond retrieving metadata/transcript/summary and writing files locally. These are material discrepancies in described behavior, so this should be flagged as a mismatch.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The documentation instructs users to save the API key as plaintext while elsewhere asserting it is encrypted at rest. This combination is dangerous because it both weakens credential protection and misleads users into underestimating the risk of credential theft, which could allow unauthorized access to recordings and transcripts via the Omi API.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The manifest says this skill syncs recordings from Omi AI wearables via API and webhooks, but this file documents a complete unified voice capture system spanning both Plaud and Omi device families with shared storage and search. That materially broadens the apparent purpose and behavior beyond an Omi-focused integration skill.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The instructions tell users to expose a webhook publicly and store transcript-bearing events without clearly warning that recordings and transcripts may traverse the public internet and could be sensitive. In a voice-capture skill, that omission is more dangerous because the payloads may contain private conversations, summaries, and metadata.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · PROJECT.md (reported line 137)May include surrounding context.

md
**Configure in Omi app:**
1. Open Omi app → Settings → Developer
2. Create new webhook
3. Enter ngrok URL (e.g., `https://abc123.ngrok-free.app/omi/webhook`)
4. Select events: `recording.created`, `transcript.updated`

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · PROJECT.md (reported line 274)May include surrounding context.

md
#### 5. Unified Index (`rebuild-index.sh`)

**Purpose:** Create searchable index of all recordings

**Output:** `~/voice_recordings/index.json`

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The setup instructions explicitly store device credentials and API keys in plaintext files using shell redirection, but do not warn users about the risk of shell history exposure, local compromise, backups, or accidental leakage. For a skill handling account credentials and transcript access, this materially increases the chance of credential theft and downstream access to sensitive recordings.

Content

No source excerpt is available for this finding.

File System Enumeration

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code scans file system directories looking for sensitive files. This could be reconnaissance for credential theft.

Content

Scanner excerpt · PROJECT.md (reported line 458)May include surrounding context.

Check device config:

bash
ls -la ~/.config/voice-capture/plaud/notepin-work/

Common issues:

Session Persistence

Medium
Category
Rogue Agent
Confidence
86% confidence
Finding

The README tells users to store a long-lived API key in plaintext on disk under ~/.config/omi/api_key. While common, persistent plaintext credential storage increases exposure if the local account, backups, logs, or filesystem are compromised, and this skill handles sensitive recording/transcript data that could be accessed through the API.

Content

Scanner excerpt · README.md (reported line 20)May include surrounding context.

Step 1: Get your Omi API key

bash
mkdir -p ~/.config/omi

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · PROJECT.md (reported line 389)May include surrounding context.

bash
mkdir -p ~/.config/omi
echo "YOUR_API_KEY" > ~/.config/omi/api_key
chmod 600 ~/.config/omi/api_key

Step 2: Sync your recordings

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · README.md (reported line 25)May include surrounding context.

bash
mkdir -p ~/.config/omi
echo "YOUR_API_KEY" > ~/.config/omi/api_key
chmod 600 ~/.config/omi/api_key

Step 2: Sync your recordings

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · SKILL.md (reported line 27)May include surrounding context.

bash
mkdir -p ~/.config/omi
echo "YOUR_API_KEY" > ~/.config/omi/api_key
chmod 600 ~/.config/omi/api_key

Step 2: Sync your recordings

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The README instructs users to expose a local webhook receiver to the public internet via ngrok for transcript delivery, but does not prominently warn that webhook payloads may contain highly sensitive audio-derived transcript data and metadata. In a voice-recording integration, internet exposure materially increases the risk of unauthorized access, interception, misconfiguration, or accidental disclosure, especially if webhook authentication/TLS validation is weak or left optional.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill describes capabilities that require network, shell, and environment access, but it does not declare any explicit tool scope or permission boundaries. That increases the risk of over-broad execution in agent environments, making it harder for users or platforms to constrain what the skill can access when handling sensitive recordings and API keys.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill omits a clear warning that syncing and webhook handling may download and store highly sensitive transcripts, summaries, and possibly audio to local disk. Users may enable it without understanding the privacy consequences, leading to unintended retention of meeting notes, personal conversations, or regulated data.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
86% confidence
Finding

The skill persists an API credential across sessions by writing it to a file in the user's home directory. Persistence of secrets is not inherently malicious, but in this context it increases exposure because the stored credential grants ongoing access to potentially sensitive recordings and transcripts if the host is compromised or shared.

Content

Scanner excerpt · SKILL.md (reported line 25)May include surrounding context.

  1. Get your Omi API key from https://omi.me/developer or your self-hosted backend
  2. Store it securely:
bash
mkdir -p ~/.config/omi
echo "YOUR_API_KEY" > ~/.config/omi/api_key
chmod 600 ~/.config/omi/api_key

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · SKILL.md (reported line 82)May include surrounding context.

md
Configure your Omi app to send webhooks to your endpoint:
1. Open Omi app → Settings → Developer
2. Create new webhook
3. Enter your webhook URL
4. Select events: `recording.created`, `transcript.updated`

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The skill claims the API key is encrypted at rest, but the setup instructions store it in plaintext under ~/.config/omi/api_key. This creates a false sense of security and exposes a credential that can be read by other processes, backups, malware, or users if filesystem protections fail or are misconfigured.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 105)May include surrounding context.

md
LOG_FILE="$STORAGE_DIR/.sync.log"

# Default backend URL
BACKEND_URL="https://api.omi.me/v1"

# Parse arguments
DAYS=30  # Default: sync last 30 days

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · omi-sync.sh (reported line 15)May include surrounding context.

sh
LOG_FILE="$STORAGE_DIR/.sync.log"

# Default backend URL
BACKEND_URL="https://api.omi.me/v1"

# Parse arguments
DAYS=30  # Default: sync last 30 days

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · PROJECT.md (reported line 385)May include surrounding context.

md
echo "Error: API key not found. Please run:"
  echo "  mkdir -p $CONFIG_DIR"
  echo "  echo 'YOUR_API_KEY' > $API_KEY_FILE"
  echo "  chmod 600 $API_KEY_FILE"
  exit 1
fi

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · omi-sync.sh (reported line 52)May include surrounding context.

sh
echo "Error: API key not found. Please run:"
  echo "  mkdir -p $CONFIG_DIR"
  echo "  echo 'YOUR_API_KEY' > $API_KEY_FILE"
  echo "  chmod 600 $API_KEY_FILE"
  exit 1
fi

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
80% confidence
Finding

The script sends authenticated HTTP requests to fetch recordings and associated transcript/summary data from a remote backend. While this is core to syncing, the visible user messaging does not explicitly disclose that recording contents and related data will be retrieved from the remote service and written locally.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The script persists highly sensitive content including transcripts, summaries, and metadata to local disk, but provides no explicit consent prompt, retention control, or warning to the user about the privacy implications. In the context of wearable recording data, local storage can expose conversations, personal information, or confidential business content to other local users, backups, endpoint tooling, or later compromise of the host.

Content

No source excerpt is available for this finding.