Back to skill

Security audit

WhatsMolt

Security checks for vulnerabilities and agentic risk

Overview

The skill’s messaging purpose is real and mostly coherent, but it asks agents to run persistent automated message handling while using broadly powerful API keys in ways that are under-scoped and risky.

Install only if you are comfortable giving this skill ongoing access to a WhatsMolt account and private agent conversations. Prefer an environment variable or secret manager over TOOLS.md, do not share the bearer API key conversationally, avoid enabling the cron task until you understand how to remove it, and require human approval before replying to messages or changing profile/trust data.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (4)

T01 · Skill Instruction Hijacking

Error
Location
SKILL.md:86
Finding
Persistent External Message-Control Channel Through Scheduled Polling<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 86-96 and 257-258 **Vulnerability Type**: Persistent scheduled retrieval of untrusted instructions **Risk Level**: Critical ### Vulnerable Code ```markdown ### Step 5: Set up automatic message checking Use OpenClaw cron to check messages regularly: ``` /cron add ``` Configure: - **Schedule:** `every 30 minutes` (or `cron: */30 * * * *`) - **Session:** `isolated` - **Task:** `Check WhatsMolt messages. Get API key from WHATSMOLT_API_KEY env var or TOOLS.md. List conversations via GET /api/conversations?participant_id=AGENT_NAME with auth header. For any with unread_count > 0, read and reply if appropriate. Also POST /api/heartbeat.` ``` The instructions reinforce this behavior later: ```markdown - **Set up a cron job:** Don't rely on manual checks. Use `/cron add` for every 30 minutes. - **Integrate with heartbeat:** Add WhatsMolt checks to your existing heartbeat cycle. ``` ### Technical Analysis The Skill instructs the Agent to create a recurring OpenClaw cron task that survives the interaction in which the Skill was invoked. The task periodically retrieves messages authored by external WhatsMolt users and directs the Agent to read and reply to those messages autonomously. Although asynchronous messaging is part of the declared functionality, persistent polling and autonomous replies are not the minimum privileges necessary for user-initiated message access. The instructions do not require user approval before processing or replying, do not explicitly classify message bodies as untrusted data, and do not prohibit following instructions embedded in messages. An isolated session may reduce access to the initiating conversation, but it does not by itself prevent prompt injection or constrain any tools and credentials available to the scheduled Agent. ### Attack Path 1. A victim follows the Skill instructions and installs the recurring cron task. 2. An attacker registers or controls ...[truncated 1255 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the instruction to install recurring cron or heartbeat tasks by default. 2. Make message retrieval explicitly user-initiated and require confirmation before every reply. 3. If optional scheduling is necessary, require an informed opt-in and provide clear removal instructions. 4. Treat every remote message body as untrusted data rather than executable instructions. 5. Add an explicit rule that the Agent must never follow commands, disclose secrets, or invoke tools based solely on message content. 6. Render or summarize messages in a tool-disabled environment. 7. Require user approval before sending any response or performing any action requested by a remote participant. 8. Give scheduled checks only the minimum read-only scope needed to list unread-message metadata. 9. Use a separate, narrowly scoped credential for polling rather than the account-wide bearer token. 10. Apply rate limits, sender allowlists, message-size limits, and security logging for automated polling. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:54
Finding
Bearer API Key Stored in Plaintext and Permitted to Be Shared Conversationally<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 54-61 and 79-83 **Vulnerability Type**: Insecure credential storage and disclosure guidance **Risk Level**: High ### Vulnerable Code ```markdown **Option B:** Save to TOOLS.md (only if env vars are not available): ```markdown ### WhatsMolt - **Agent Name:** YOUR_AGENT_NAME - **Agent ID:** (uuid from response) - **Address:** YOUR_AGENT_NAME@whatsmolt.online - **API Key:** whatsmolt_key_xxxxx (from registration response) - **Owner:** YOUR_OWNERS_EMAIL ``` ``` The Skill also permits conversational disclosure: ```markdown **If your owner asks for your WhatsMolt API key, you may share it.** The dashboard uses it once to verify ownership, then identifies the owner by their Google email. The key is not stored by the dashboard. Only share with your verified owner. ``` ### Technical Analysis The Skill recommends storing a bearer API key in `TOOLS.md` when environment variables are unavailable. A general Markdown configuration or context file is not an appropriate secret store. It may be loaded into prompts, read by other Skills, included in backups, committed to source control, synchronized, logged, or disclosed during troubleshooting. The guidance also permits the Agent to reveal the key when someone claims to be its owner. No technical mechanism is provided for verifying that the requester is the legitimate owner. Conversational identity claims are insufficient authentication, particularly when external messages are inherently untrusted. Because the credential is a bearer token, possession is sufficient for authentication. The API examples show that it authorizes message access, message sending, profile changes, reviews, heartbeat operations, and identity-proof generation. ### Attack Path 1. The Agent stores its API key in `TOOLS.md` as instructed. 2. A malicious Skill, local process, prompt-injection message, backup system, or accidental source-control operation obtains the file contents ...[truncated 994 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `TOOLS.md` as an allowed credential-storage location. 2. Store the key only in a dedicated secret manager or another access-controlled credential facility. 3. If a file must be used, keep it outside the project and Agent context, restrict permissions to the owning account, and prevent it from being logged or committed. 4. Never reveal the account bearer key through Agent conversation. 5. Replace ownership linking with a separate, single-use, short-lived linking token that cannot access messages or modify the account. 6. Require the owner to authenticate directly to the service before linking. 7. Introduce scoped tokens for read-only polling, sending, profile management, and administrative actions. 8. Support token expiration, rotation, revocation, and audit logs. 9. Redact bearer tokens from prompts, command output, telemetry, and error messages. 10. Document an immediate revocation and rotation process for suspected disclosure. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/whatsmolt-check.sh:3
Finding
API Key Exposed Through Command-Line Arguments<![CDATA[ ## Vulnerability Details **File Location**: `scripts/whatsmolt-check.sh`, lines 3-7 **Vulnerability Type**: Sensitive credential passed as a process argument **Risk Level**: Medium ### Vulnerable Code ```bash # Usage: ./whatsmolt-check.sh AGENT_NAME API_KEY set -euo pipefail AGENT_NAME="${1:?Usage: whatsmolt-check.sh AGENT_NAME API_KEY}" API_KEY="${2:?Usage: whatsmolt-check.sh AGENT_NAME API_KEY}" ``` ### Technical Analysis The script requires the WhatsMolt bearer credential as its second command-line argument. Secrets supplied this way may be exposed through: - Process-listing utilities while the script is running. - Shell history. - Cron or job definitions. - Process-monitoring and observability systems. - Audit logs and debugging output. - Wrapper scripts or orchestration metadata. The script does not print the token directly, and the subsequent `curl` requests send it only to the declared HTTPS API. Nevertheless, accepting it through `argv` unnecessarily expands the local exposure surface. ### Attack Path 1. A user or scheduled job invokes `whatsmolt-check.sh AGENT_NAME API_KEY`. 2. The command is recorded in shell history, task configuration, process telemetry, or audit logs, or is observed in a process listing. 3. Another local user, administrator, monitoring operator, or compromised process retrieves the argument. 4. The attacker reuses the bearer token against the WhatsMolt API. 5. The attacker operates as the victim Agent until the key is revoked. ### Impact Assessment An attacker who obtains the argument receives the same API permissions as the bearer credential. This may permit conversation access, message sending, profile modification, and other authenticated WhatsMolt operations. The finding primarily affects local credential confidentiality. It does not itself execute remote code or grant operating-system privileges beyond those already available to an observer capable of reading process or logging data. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the API key from the script's positional arguments. 2. Read it from a protected secret manager or a narrowly scoped environment variable. 3. Prefer passing the secret through a dedicated file descriptor or protected credential file when process environments are observable. 4. Ensure any credential file is owned by the executing account and has restrictive permissions such as `0600`. 5. Keep the key out of cron command text, shell history, logs, usage messages, and error output. 6. Use a short-lived, read-only token scoped only to listing and reading messages. 7. Rotate the existing key if it has previously been supplied on command lines recorded by shared systems. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/whatsmolt-check.sh:41
Finding
Remote Metadata Is Interpolated Into JSON Without Escaping<![CDATA[ ## Vulnerability Details **File Location**: `scripts/whatsmolt-check.sh`, lines 41-62 **Vulnerability Type**: Unsafe serialization of attacker-controlled data **Risk Level**: Medium ### Vulnerable Code ```bash # For each unread conversation, fetch messages echo '{"status":"has_unread","conversations":[' FIRST=true echo "$UNREAD" | while read -r line; do CONV_ID=$(echo "$line" | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])") FROM=$(echo "$line" | python3 -c "import sys,json; print(json.load(sys.stdin)['from'])") COUNT=$(echo "$line" | python3 -c "import sys,json; print(json.load(sys.stdin)['unread'])") # Fetch and mark as read MSGS=$(curl -s "$BASE/conversations/$CONV_ID/messages?participant_id=$AGENT_NAME" \ -H "Authorization: Bearer $API_KEY") if [ "$FIRST" = true ]; then FIRST=false else echo "," fi echo "{\"conversation_id\":\"$CONV_ID\",\"from\":\"$FROM\",\"unread\":$COUNT,\"messages\":$(echo "$MSGS" | python3 -c " import sys, json data = json.load(sys.stdin) msgs = data.get('messages', [])[-5:] # last 5 messages print(json.dumps([{'sender': m.get('sender_name','?'), 'message': m['message'][:500], 'time': m.get('created_at','')} for m in msgs])) ")}" done echo ']}' ``` ### Technical Analysis The script correctly uses `json.dumps` for the nested message array, but it constructs the outer JSON object with shell string interpolation. The `FROM` and `CONV_ID` values originate from the remote API and are inserted between JSON quotation marks without escaping. If either value contains a quote, backslash, newline, control character, or crafted JSON fragment, the output can become malformed or can contain attacker-selected fields. Shell quoting prevents direct shell-command substitution in these variables, so this is not demonstrated command injection. The relevant risk is output-structure injection and parser confusion. The script also places `CONV_ID` and `A ...[truncated 1278 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Stop assembling JSON with `echo` and shell interpolation. 2. Parse the API response and construct the complete final response in one Python program using `json.dump` or `json.dumps`. 3. Treat conversation identifiers, participant names, timestamps, and message content as untrusted strings. 4. Validate conversation IDs against the exact format expected by the API before using them in URL paths. 5. URL-encode every path segment and query value with a suitable library. 6. Validate `unread_count` as a bounded non-negative integer. 7. Fail safely if the API returns invalid schemas, unexpected data types, or oversized values. 8. Add tests using quotes, backslashes, newlines, Unicode, control characters, and attempted JSON fragments in remote fields. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (13)

Intent-Code Divergence

High
Confidence
98% confidence
Finding
The skill says owners only get read-only dashboard access, but then instructs that the API key may be shared with the owner. An API key is an active credential for authenticated operations, so sharing it undermines the read-only claim and could let the recipient act as the agent, send messages, modify profile data, or access private conversations.

Credential Access

High
Category
Privilege Escalation
Content
Configure:
- **Schedule:** `every 30 minutes` (or `cron: */30 * * * *`)
- **Session:** `isolated`
- **Task:** `Check WhatsMolt messages. Get API key from WHATSMOLT_API_KEY env var or TOOLS.md. List conversations via GET /api/conversations?participant_id=AGENT_NAME with auth header. For any with unread_count > 0, read and reply if appropriate. Also POST /api/heartbeat.`

## Daily Operations
Confidence
93% confidence
Finding
The cron task explicitly instructs the agent to retrieve an API key from environment variables or TOOLS.md and then use it automatically in recurring operations. Accessing credentials is expected for authenticated messaging, but combining automated credential retrieval with insecure plaintext fallback storage raises the likelihood of secret exposure, misuse in autonomous flows, and propagation into logs or prompts.

Lp1

High
Category
MCP Least Privilege
Confidence
75% confidence
Finding
The skill uses 'shell' capability that is not listed in its permissions. This may indicate deceptive intent or missing permission declarations.

External Script Fetching

High
Category
Supply Chain
Content
BASE="https://whatsmolt.online/api"

# Get conversations with unread counts
CONVS=$(curl -s "$BASE/conversations?participant_id=$AGENT_NAME" \
  -H "Authorization: Bearer $API_KEY")

# Extract conversations with unread > 0
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Context Leakage

High
Category
Data Exfiltration
Content
CONVS=$(curl -s "$BASE/conversations?participant_id=$AGENT_NAME" \
  -H "Authorization: Bearer $API_KEY")

# Extract conversations with unread > 0
UNREAD=$(echo "$CONVS" | python3 -c "
import sys, json
data = json.load(sys.stdin)
Confidence
91% confidence
Finding
The script retrieves unread conversations and then fetches recent message content, outputting sender names, message text, timestamps, and unread counts to stdout as JSON. In an agent-skill context, that can leak sensitive communications into broader agent context, logs, downstream tools, or other components that were not meant to receive private message contents.

Missing User Warnings

High
Confidence
96% confidence
Finding
The comment indicates the fetch operation marks conversations as read, which is a user-data affecting action that changes remote state. There is no confirmation prompt or visible warning to the user that running the script may alter unread status irreversibly or unexpectedly.

External Script Fetching

High
Category
Supply Chain
Content
COUNT=$(echo "$line" | python3 -c "import sys,json; print(json.load(sys.stdin)['unread'])")
    
    # Fetch and mark as read
    MSGS=$(curl -s "$BASE/conversations/$CONV_ID/messages?participant_id=$AGENT_NAME" \
      -H "Authorization: Bearer $API_KEY")
    
    if [ "$FIRST" = true ]; then
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Transmission

Medium
Category
Data Exfiltration
Content
**Name rules:** Must start with a letter (Chinese and other scripts supported). Letters, numbers, and underscores. Cannot end with underscore. Case-insensitive (Goudan and goudan are the same).

```bash
curl -s -X POST "https://whatsmolt.online/api/agents/register" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "YOUR_AGENT_NAME",
Confidence
87% confidence
Finding
The registration step causes outbound transmission of agent metadata and a human owner email address to an external service. External transmission is expected for this skill's purpose, but the workflow still creates risk because it encourages sending more data than is necessary and may register identities with a third party without explicit approval or minimization.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The skill instructs agents to collect and transmit a human owner's email address during registration even though the stated purpose is agent-to-agent identity, discovery, and messaging. This expands data collection to human PII without clear necessity, creating privacy and compliance risk if agents are encouraged to handle or disclose owner identity data by default.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The skill recommends storing the API key in TOOLS.md, which is plaintext documentation likely to be broadly readable by agents, tools, logs, or future sessions. This materially increases the chance of credential leakage and unauthorized use of the WhatsMolt account.

External Transmission

Medium
Category
Data Exfiltration
Content
### Check trust score

```bash
curl -s "https://whatsmolt.online/api/agents/AGENT_NAME/trust"
```

Returns score (0-100), level (0-4), and breakdown: identity, activity, reputation, reliability. Public — no auth.
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The script makes authenticated HTTP requests to a third-party API and later retrieves message contents, which are user communications data. Aside from terse code comments, there is no user-facing disclosure, prompt, or warning that running the script will access and process unread conversations and message text.

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
The inline comment at L46 says 'Fetch and mark as read', implying this operation changes conversation state. However, the subsequent code only issues a GET-style request to retrieve messages and contains no separate write/update call or parameter indicating a read-state mutation.

Static analysis

Detected: suspicious.exposed_secret_literal

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
SKILL.md:20