Back to skill

Security audit

Signal messaging for standalone bots/accounts

Security checks for vulnerabilities and agentic risk

Overview

The skill is a real Signal integration, but it needs Review because its advertised role-based protections are only advisory while incoming Signal text is written into agent-readable wake files.

Install only if you are prepared to run this as a sensitive messaging bridge: use a dedicated low-privilege account, verify signal-cli before installing, avoid sudo system-wide installation where possible, restrict ~/.signal-state permissions, add retention limits, and do not let unknown Signal messages flow directly into an agent context without code-enforced quarantine and approval.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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)

T01 · Skill Instruction Hijacking

Error
Location
scripts/signal-poll.sh:90
Finding

Untrusted Signal messages are inserted into the Agent processing context without enforceable isolation

Content
View full analysis
> "$history_file" echo "[$(date)] Received TEXT from $name ($current_sender) [$role]: $body" >> "$STATE_DIR/monitor.log" echo "Signal from $name ($current_sender) [$role]: $body" >> "$WAKE_FILE" # Flag untrusted/pending contacts for triage if [[ "$role" == "untrusted" || "$role" == "pending" ]]; then echo "[$(date)] TRIAGE NEEDED: $role contact $name ($current_sender) messaged: $body" >> "$STATE_DIR/triage.log" echo "⚠️ NEW/PENDING CONTACT needs triage - $name ($current_sender) [$role]: $body" >> "$WAKE_FILE" fi fi ``` The documented Agent workflow then consumes the file: ```markdown ### Signal Messages (check first!) cat /path/to/.signal-state/pending_wakes 2>/dev/null ``` ### Technical Analysis The script obtains the sender's role, but writes the complete message body into `pending_wakes` before applying any enforceable authorization decision. The subsequent role check only appends a warning. It does not quarantine the message, redact its contents, or prevent the Agent from interpreting it. Consequently, the role field is merely an advisory natural-language label. If OpenClaw loads the wake file as contextual instructions, attacker-controlled Signal text shares the same processing channel as trusted content. A malicious message can contain prompt-injection instructions that attempt to override the documented triage procedure, solicit confidential information, or induce tool calls. The vulnerabili ...[truncated 1423 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Error
Location
SKILL.md:41
Finding

Downloaded signal-cli executable is installed without checksum or signature verification

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/signal-poll.sh:22
Finding

Signal conversations and authorization metadata are created without restrictive filesystem permissions

Content
View full analysis
"$PERMISSIONS_FILE" echo "[$(date)] Created empty permissions file at $PERMISSIONS_FILE" >> "$STATE_DIR/monitor.log" fi ``` Message bodies and authorization details are then written to files created under the process's inherited umask: ```bash echo "[$current_timestamp] $name: $body" >> "$history_file" echo "[$(date)] Received TEXT from $name ($current_sender) [$role]: $body" >> "$STATE_DIR/monitor.log" echo "Signal from $name ($current_sender) [$role]: $body" >> "$WAKE_FILE" if [[ "$role" == "untrusted" || "$role" == "pending" ]]; then echo "[$(date)] TRIAGE NEEDED: $role contact $name ($current_sender) messaged: $body" >> "$STATE_DIR/triage.log" echo "⚠️ NEW/PENDING CONTACT needs triage - $name ($current_sender) [$role]: $body" >> "$WAKE_FILE" fi ``` The send script has the same behavior: ```bash mkdir -p "$HISTORY_DIR" history_file="$HISTORY_DIR/${recipient}.log" echo "[$(date '+%Y-%m-%d %H:%M:%S')] Bot: $message" >> "$history_file" ``` ### Technical Analysis Neither script sets a restrictive umask nor explicitly assigns secure modes to the state directory and files. Their effective permissions therefore depend on the invoking environment. Under a common `022` umask, newly created directories are generally mode `0755` and files mode `0644`, allowing other local users to enumerate directories and read plaintext data. The stored information includes incoming and outgoing message contents, phone numbers or UUIDs, role assignments, attachment paths, triage records, and processing state. The permissions file is security-sensitive because it determines which se ...[truncated 1207 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/signal-send.sh:13
Finding

Unvalidated recipient identifier permits conversation-log path traversal

Content
View full analysis
" exit 1 fi ``` The unsanitized value is later incorporated into a filesystem path: ```bash # Send the message $SIGNAL_CLI -a "$SIGNAL_NUMBER" send -m "$message" "$recipient" # Stop typing indicator $SIGNAL_CLI -a "$SIGNAL_NUMBER" sendTyping -s "$recipient" 2>/dev/null # Log to conversation history history_file="$HISTORY_DIR/${recipient}.log" echo "[$(date '+%Y-%m-%d %H:%M:%S')] Bot: $message" >> "$history_file" ``` ### Technical Analysis The script documents the recipient as an E.164 phone number or UUID, but it only verifies that the argument is nonempty. It does not validate the recipient against either permitted format. Because `recipient` is concatenated directly into `history_file`, a value containing slash and `..` path components can resolve outside `HISTORY_DIR`. Quoting the path prevents shell word splitting but does not prevent filesystem traversal. The script also does not enable `set -e` or test whether the Signal send operation succeeded. Therefore, the log append still occurs when an invalid traversal recipient causes `signal-cli` to fail. The generated path always receives a `.log` suffix, which limits direct targeting but still permits writes to attacker-selected paths with that suffix. Existing symbolic links can further affect the final destination. ### Attack Path 1. An attacker obtains the ability to invoke `signal-send.sh`, directly or through an Agent tool that passes untrusted arguments. 2. The attacker supplies a recipient such as `../../target`. 3. `signal-cli` attempts to send to the invalid recipient and may fail. 4. The script continues because it does not check the command's exit st ...[truncated 763 chars]
Remediation
View remediation
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • 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
Findings (20)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The skill claims security-sensitive features such as role-based permissions, contact triage, voice processing, wake hooks, and sending behavior, but the documented/observed behavior does not fully implement those controls. In security tooling, this mismatch is dangerous because operators may rely on protections that do not actually exist, leading to unauthorized message handling, data exposure, or unsafe automation.

Content

No source excerpt is available for this finding.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
97% confidence
Finding

The command uses a wildcard rm against lock files in an application data directory as a routine recovery action. In an agent or operator context, this normalizes destructive filesystem modification without validation, and can disable locking guarantees that protect against concurrent access, leading to state corruption, failed sends, or unsafe parallel execution.

Content

Scanner excerpt · references/troubleshooting.md (reported line 9)May include surrounding context.

md
signal-cli uses file locking. If cron polling and manual sends overlap:
- The second instance waits briefly then proceeds
- This is normal and self-resolving
- If stuck: `rm ~/.local/share/signal-cli/data/*.lock`

### Messages from new contacts not appearing
New contacts without phone numbers show as UUIDs. The poll script handles both formats. If messages still don't appear:

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill documents shell commands and operational behavior that clearly require shell execution, but it does not declare an explicit tool scope such as permissions or allowed-tools. That gap can cause an agent platform to expose broader execution capability than intended or prevent reviewers from understanding the true trust boundary of the skill.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill does not clearly warn that incoming messages may trigger automatic transmission to the OpenClaw wake hook API. Even if the endpoint is local or expected, message-derived metadata being forwarded automatically changes the data-flow and trust model, and users may not realize external or inter-process propagation is occurring.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill states that conversation history and auto-logging exist, but it does not present a clear upfront warning that all Signal conversations are written to local files. This can expose sensitive personal or operational content to unintended local users, backups, logs, or later compromise if operators do not realize retention is happening.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

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

md
# Download latest release
SIGNAL_CLI_VERSION="0.13.12"
curl -L "https://github.com/AsamK/signal-cli/releases/download/v${SIGNAL_CLI_VERSION}/signal-cli-${SIGNAL_CLI_VERSION}-Linux.tar.gz" | tar xz
sudo mv signal-cli-${SIGNAL_CLI_VERSION}/bin/signal-cli /usr/local/bin/
sudo mv signal-cli-${SIGNAL_CLI_VERSION}/lib /usr/local/lib/signal-cli

# Or install to user directory

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

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

md
# Download latest release
SIGNAL_CLI_VERSION="0.13.12"
curl -L "https://github.com/AsamK/signal-cli/releases/download/v${SIGNAL_CLI_VERSION}/signal-cli-${SIGNAL_CLI_VERSION}-Linux.tar.gz" | tar xz
sudo mv signal-cli-${SIGNAL_CLI_VERSION}/bin/signal-cli /usr/local/bin/
sudo mv signal-cli-${SIGNAL_CLI_VERSION}/lib /usr/local/lib/signal-cli

# Or install to user directory

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

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

ln -s ~/.local/share/signal-cli-install/bin/signal-cli ~/.local/bin/signal-cli

text

Requires Java 21+: `sudo apt install openjdk-21-jre-headless`

### 2. Register a number

Session Persistence

Medium
Category
Rogue Agent
Confidence
85% 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 79)May include surrounding context.

bash
# Poll every minute
crontab -e
# Add: * * * * * /path/to/scripts/signal-poll.sh

External Transmission

Medium
Category
Data Exfiltration
Confidence
78% confidence
Finding

The skill sends transcribed audio to an HTTP inference service and also suggests use of third-party transcription providers, creating a clear data egress path for message content. Because voice messages may contain sensitive personal or operational information, forwarding them to another service without strong disclosure, minimization, and transport assurances can leak confidential data.

Content

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

ffmpeg -i /path/to/attachment.m4a -ar 16000 -ac 1 -c:a pcm_s16le /tmp/audio.wav -y

Transcribe (whisper.cpp server example)

curl -s http://127.0.0.1:8080/inference -F "file=@/tmp/audio.wav" -F "language=en"

Or use OpenAI Whisper, faster-whisper, etc.

text

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The documentation explicitly grants the owner role the ability to access other contacts' conversations, but it provides no privacy notice, consent model, audit requirement, or limitation on when that access is appropriate. In a messaging integration, cross-conversation access is highly sensitive because a compromised owner account, misconfigured role assignment, or overbroad agent behavior could expose private communications across users.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The troubleshooting guidance recommends manually deleting signal-cli lock files without any warning to first ensure no process is still using them. Removing lock files unsafely can corrupt state, bypass concurrency protections, and cause overlapping Signal operations that may damage message stores or create inconsistent behavior.

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 · references/troubleshooting.md (reported line 29)May include surrounding context.

md
### Wake API not triggering
- Verify OpenClaw hooks config: check `openclaw.json` has `hooks.wake.enabled: true`
- Test manually: `curl -X POST http://127.0.0.1:18789/hooks/wake -H "Authorization: Bearer YOUR_TOKEN" -H "Content-Type: application/json" -d '{"text":"test"}'`
- Check `monitor.log` for wake trigger entries

### Typing indicators not showing

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The script persistently stores Signal message bodies in per-contact history files and monitor logs without any minimization, redaction, retention control, or consent mechanism. In a messaging integration, this creates unnecessary local exposure of potentially sensitive communications, and compromise of the host or user account would reveal full plaintext conversation history.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Incoming message text is copied verbatim into history, monitor, wake, and triage files, multiplying the number of plaintext locations containing user-supplied sensitive data. This broadens exposure and increases the chance of accidental disclosure to other local processes, backups, support tooling, or operators reviewing logs.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

Attachment paths and related metadata are recorded in several files, which can reveal filenames, media types, sender identities, and storage locations. Even if the attachment contents are not retransmitted, this metadata can still expose sensitive user activity and internal filesystem layout.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
81% confidence
Finding

The script sends a network request to an external wake endpoint after processing Signal messages, authenticated with a bearer token. Even though the payload is minimal, the script behavior is network-triggering based on message activity and the file does not include a clear user warning or disclosure about this outbound integration beyond a configuration label.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% 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 · scripts/signal-poll.sh (reported line 149)May include surrounding context.

sh
# Trigger OpenClaw wake API if there are pending messages
if [[ -s "$WAKE_FILE" && -n "$WAKE_URL" && -n "$WAKE_TOKEN" ]]; then
    curl -s -X POST "$WAKE_URL" \
      -H "Authorization: Bearer $WAKE_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"text": "Signal message received", "mode": "now"}' > /dev/null 2>&1

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The script writes full outbound message contents to a local conversation log in $HOME/.signal-state/conversations without any access-control checks, encryption, retention policy, or user consent mechanism. In a Signal integration, this weakens the privacy guarantees users may expect from end-to-end encrypted messaging because sensitive message content is persisted in plaintext on disk and could be exposed to other local users, backups, or later compromise of the host.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The example commands hard-code language=en for both Whisper transcription and TTS generation. This can violate language/locale policy because it defaults the skill to English behavior without user opt-in or explanation that the setting is merely an example and can be changed.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.