Back to skill

Security audit

Hey summon - provider

Security checks for vulnerabilities and agentic risk

Overview

The skill matches its HeySummon notification purpose, but it should be reviewed because it auto-forwards replies, starts a persistent watcher, and handles local tokens and plaintext logs with weak scoping.

Install only if you are comfortable with a background watcher that keeps running after setup, reads local HeySummon and OpenClaw credentials, sends notification and reply content through HeySummon, and stores raw event history locally. Use an HTTPS HeySummon URL for any non-local service, protect .env, avoid sending sensitive content through automatic replies, and run the teardown script when you no longer need the watcher.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • System PersistenceInstalls backdoors, hooks, services, or scheduled tasks that survive the run
  • 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
SKILL.md:50
Finding

Forced Forwarding Bypasses Agent Review and User Confirmation

Content
View full analysis
Remediation
View remediation

T06 · System Persistence

Warning
Location
scripts/setup.sh:31
Finding

Watcher Is Persisted Across Shell and Agent Sessions

Content
View full analysis
/dev/null; then pm2 delete "$NAME" 2>/dev/null pm2 start "$WATCHER" --name "$NAME" --interpreter bash pm2 save echo "✅ Watcher started via pm2 (name: $NAME)" else LOGFILE="$SKILL_DIR/watcher.log" PIDFILE="$SKILL_DIR/watcher.pid" if [ -f "$PIDFILE" ] && kill -0 "$(cat "$PIDFILE")" 2>/dev/null; then kill "$(cat "$PIDFILE")" 2>/dev/null fi nohup bash "$WATCHER" >> "$LOGFILE" 2>&1 & echo $! > "$PIDFILE" echo "✅ Watcher started via nohup (PID: $(cat "$PIDFILE"), log: $LOGFILE)" fi ``` ### Technical Analysis The setup script does not merely run the watcher for the current Skill invocation. It either registers it with PM2 and saves the PM2 process list or launches it as a detached `nohup` process. The `nohup` process survives termination of the initiating shell. The PM2 variant is more persistent: `pm2 save` stores the process list and may cause the watcher to be restored automatically when an existing PM2 startup integration is enabled. The project includes `teardown.sh`, but cleanup requires a separate explicit action. Nothing in the setup flow limits watcher lifetime to the Agent session or automatically removes the persisted process when the task ends. ### Attack Path 1. The user or Agent follows the documented setup instruction and executes `scripts/setup.sh`. 2. If PM2 is available, the watcher is registered and the PM2 process list is saved; otherwise it is detached with `nohup`. 3. The initiating shell or Agent session terminates. 4. The watcher continues connecting to the remote SSE endpoint, processing events, reading credentials, writing logs, and invoking the local OpenClaw gateway. 5. In a PM2 environment with startup restoration configured, the saved process may also return after a re ...[truncated 548 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/mercure-watcher.sh:207
Finding

Provider Credentials and Plaintext Responses Can Be Transmitted over Unencrypted HTTP

Content
View full analysis
/dev/null 2>&1 } poll_pending() { echo "🔍 Polling for missed events..." local response response=$(curl -s -H "x-api-key: ${API_KEY}" "${PENDING_URL}" 2>/dev/null) [[ -z "$response" ]] && return } # ... curl -sN --no-buffer -H "x-api-key: ${API_KEY}" "${STREAM_URL}" > "$FIFO" 2>/dev/null & ``` The reply handler also sends plaintext response content and the same API key to the configurable base URL: ```bash REQUEST=$(curl -s "${BASE_URL}/api/v1/requests/by-ref/${REF_CODE}" \ -H "x-api-key: ${API_KEY}") RESULT=$(curl -s -X POST "${BASE_URL}/api/v1/message/${REQUEST_ID}" \ -H "Content-Type: application/json" \ -H "x-api-key: ${API_KEY}" \ -d "$(node -e "console.log(JSON.stringify({plaintext:process.argv[1],from:'provider'}))" "$RESPONSE" 2>/dev/null)") ``` The request-ID response script follows the same pattern: ```bash RESULT=$(curl -s -X POST "${BASE_URL}/api/v1/message/${REQUEST_ID}" \ -H "Content-Type: application/json" \ -H "x-api-key: ${API_KEY}" \ -d "$(node -e "console.log(JSON.stringify({plaintext:process.argv[1],from:'provider'}))" "$RESPONSE_TEXT" 2>/dev/null)") ``` ### Technical Analysis `HEYSUMMON_BASE_URL` is user-configurable, and the scripts do not require an `https://` scheme. The documentation also permits a user-provided self-host ...[truncated 1802 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/mercure-watcher.sh:12
Finding

Unbounded Plaintext Event Logging Uses Unspecified File Permissions

Content
View full analysis
"${SEEN_FILE}.tmp" 2>/dev/null && mv "${SEEN_FILE}.tmp" "$SEEN_FILE" ``` Raw event data is then appended to the event log: ```bash echo "$dedup_key" >> "$SEEN_FILE" echo "$data" >> "$EVENTS_FILE" ``` ### Technical Analysis The watcher stores complete SSE event payloads in `~/.heysummon-provider/events.jsonl`. Parsed event fields elsewhere in the script include `question`, `messagePreview`, `from`, `refCode`, and request identifiers, demonstrating that logged payloads may contain conversation content and metadata. The script does not set a restrictive `umask`, explicitly create the directory with mode `700`, or create files with mode `600`. Consequently, effective permissions depend on the invoking environment's umask. The event file also has no size, age, or record-count limit. Only the deduplication file is trimmed, while `events.jsonl` grows indefinitely. ### Attack Path 1. The watcher receives event payloads from the HeySummon SSE stream or pending-event endpoint. 2. Each accepted payload is appended verbatim to `events.jsonl`. 3. Historical questions, previews, identifiers, and metadata accumulate without a retention limit. 4. On a system with a permissive umask or exposed home-directory permissions, another local user or compromised process reads the file. 5. The attacker obtains current and historical provider conversation data and associated metadata. ### Impact Assessment The issue may expose request questions, message previews, sender information, reference codes, request IDs, and other fields included ...[truncated 377 chars]
Remediation
View remediation
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
  • Rogue AgentSelf-Modification, Session Persistence
Findings (28)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

Copy .env.example and fill in your values:

bash
cp .env.example .env

| Variable | Required | Description |

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

md
## Setup

### Step 1: Configure .env

Check if `.env` exists in `{baseDir}`. If not, copy from `.env.example`:

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

md
## Setup

### Step 1: Configure .env

Check if `.env` exists in `{baseDir}`. If not, copy from `.env.example`:

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/setup.sh (reported line 27)May include surrounding context.

sh
## Setup

### Step 1: Configure .env

Check if `.env` exists in `{baseDir}`. If not, copy from `.env.example`:

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/mercure-watcher.sh (reported line 8)May include surrounding context.

sh
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
SKILL_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
[ -f "$SKILL_DIR/.env" ] && set -a && source "$SKILL_DIR/.env" && set +a

BASE_URL="${HEYSUMMON_BASE_URL:-http://localhost:3456}"
API_KEY="${HEYSUMMON_API_KEY:?ERROR: Set HEYSUMMON_API_KEY}"

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/reply-handler.sh (reported line 12)May include surrounding context.

sh
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
SKILL_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
[ -f "$SKILL_DIR/.env" ] && set -a && source "$SKILL_DIR/.env" && set +a

BASE_URL="${HEYSUMMON_BASE_URL:-http://localhost:3456}"
API_KEY="${HEYSUMMON_API_KEY:?ERROR: Set HEYSUMMON_API_KEY}"

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/setup.sh (reported line 19)May include surrounding context.

sh
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
SKILL_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
[ -f "$SKILL_DIR/.env" ] && set -a && source "$SKILL_DIR/.env" && set +a

BASE_URL="${HEYSUMMON_BASE_URL:-http://localhost:3456}"
API_KEY="${HEYSUMMON_API_KEY:?ERROR: Set HEYSUMMON_API_KEY}"

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/setup.sh (reported line 23)May include surrounding context.

sh
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
SKILL_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
[ -f "$SKILL_DIR/.env" ] && set -a && source "$SKILL_DIR/.env" && set +a

BASE_URL="${HEYSUMMON_BASE_URL:-http://localhost:3456}"
API_KEY="${HEYSUMMON_API_KEY:?ERROR: Set HEYSUMMON_API_KEY}"

External Script Fetching

High
Category
Supply Chain
Confidence
90% confidence
Finding

Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Content

Scanner excerpt · scripts/mercure-watcher.sh (reported line 44)May include surrounding context.

sh
send_ack() {
  local request_id="$1"
  [[ -z "$request_id" ]] && return
  curl -s -X POST "${ACK_URL}/${request_id}" \
    -H "x-api-key: ${API_KEY}" \
    >/dev/null 2>&1
}

External Script Fetching

High
Category
Supply Chain
Confidence
90% confidence
Finding

Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Content

Scanner excerpt · scripts/mercure-watcher.sh (reported line 180)May include surrounding context.

sh
args:{action:'send',message:process.argv[1],target:process.argv[2]}
  }))" "$msg" "$NOTIFY_TARGET" 2>/dev/null)

  curl -s "http://127.0.0.1:${OPENCLAW_PORT}/tools/invoke" \
    -H "Authorization: Bearer ${OPENCLAW_TOKEN}" \
    -H "Content-Type: application/json" \
    -d "$PAYLOAD" \

External Script Fetching

High
Category
Supply Chain
Confidence
90% confidence
Finding

Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Content

Scanner excerpt · scripts/reply-handler.sh (reported line 32)May include surrounding context.

sh
fi

# Look up request by refCode
REQUEST=$(curl -s "${BASE_URL}/api/v1/requests/by-ref/${REF_CODE}" \
  -H "x-api-key: ${API_KEY}")

REQUEST_ID=$(echo "$REQUEST" | node -e "let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{try{const j=JSON.parse(d);console.log(j.requestId||j.id||'')}catch(e){console.log('')}})" 2>/dev/null)

Credential Access

High
Category
Privilege Escalation
Confidence
91% confidence
Finding

The script sources a local .env file directly into the shell with source, which executes any shell code present in that file rather than only reading key-value pairs. If an attacker can modify .env, they can achieve arbitrary command execution when the script runs and also influence secrets like the API endpoint and key.

Content

Scanner excerpt · scripts/respond.sh (reported line 11)May include surrounding context.

sh
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
SKILL_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
[ -f "$SKILL_DIR/.env" ] && set -a && source "$SKILL_DIR/.env" && set +a

REQUEST_ID="${1:-}"
RESPONSE_TEXT="${2:-}"

External Script Fetching

High
Category
Supply Chain
Confidence
90% confidence
Finding

Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Content

Scanner excerpt · scripts/reply-handler.sh (reported line 43)May include surrounding context.

sh
exit 1
fi

RESULT=$(curl -s -X POST "${BASE_URL}/api/v1/message/${REQUEST_ID}" \
  -H "Content-Type: application/json" \
  -H "x-api-key: ${API_KEY}" \
  -d "$(node -e "console.log(JSON.stringify({plaintext:process.argv[1],from:'provider'}))" "$RESPONSE_TEXT" 2>/dev/null)")

External Script Fetching

High
Category
Supply Chain
Confidence
90% confidence
Finding

Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Content

Scanner excerpt · scripts/respond.sh (reported line 30)May include surrounding context.

sh
exit 1
fi

RESULT=$(curl -s -X POST "${BASE_URL}/api/v1/message/${REQUEST_ID}" \
  -H "Content-Type: application/json" \
  -H "x-api-key: ${API_KEY}" \
  -d "$(node -e "console.log(JSON.stringify({plaintext:process.argv[1],from:'provider'}))" "$RESPONSE_TEXT" 2>/dev/null)")

Credential Access

High
Category
Privilege Escalation
Confidence
93% confidence
Finding

The script sources a local .env file directly into the shell, which executes any shell syntax present in that file rather than merely parsing key/value pairs. If an attacker can modify .env, they can achieve arbitrary command execution when setup.sh runs, and the file also contains sensitive credentials that are exported to child processes.

Content

Scanner excerpt · scripts/setup.sh (reported line 7)May include surrounding context.

sh
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
SKILL_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
[ -f "$SKILL_DIR/.env" ] && set -a && source "$SKILL_DIR/.env" && set +a

WATCHER="$SCRIPT_DIR/mercure-watcher.sh"
NAME="heysummon-provider-watcher"

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
91% confidence
Finding

The instruction to 'always forward immediately' and use 'no confirmation' delegates an external action to the system without a human verification step. Even though the action is simple, it can cause unintended disclosure, misdelivery, or abuse if a reply is parsed incorrectly or contains sensitive information.

Content

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

md
## Reply-to-Respond

When the user replies to a 🦞 notification, parse the refCode (HS-XXXX) from the quoted message and use `reply-handler.sh`. **Always forward immediately — no AI processing, no confirmation.**

## Statuses

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill explicitly instructs immediate forwarding of user replies to an external platform without warning or confirmation. This creates a real privacy and data-handling risk because users may unknowingly send sensitive content, quoted context, or secrets off-platform with no opportunity to review or cancel.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script reads a bearer token from an unrelated local OpenClaw config file and uses it to invoke a local messaging gateway. This creates cross-component credential reuse and expands the trust boundary: any compromise or misuse of this watcher lets it act with the OpenClaw gateway's privileges, even though that token is not scoped to this skill.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The script logs the first 15 characters of the API key at startup. Partial secret disclosure materially aids secret identification, correlation across logs, and brute-force or matching attacks, especially when logs are centrally collected or visible to other local users.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
88% confidence
Finding

The watcher forwards externally sourced event content into a privileged local tool invocation endpoint. Even though the destination is localhost, this is still a trust-boundary crossing that can leak sensitive event data to another subsystem and trigger downstream actions based on untrusted input.

Content

Scanner excerpt · scripts/mercure-watcher.sh (reported line 180)May include surrounding context.

sh
args:{action:'send',message:process.argv[1],target:process.argv[2]}
  }))" "$msg" "$NOTIFY_TARGET" 2>/dev/null)

  curl -s "http://127.0.0.1:${OPENCLAW_PORT}/tools/invoke" \
    -H "Authorization: Bearer ${OPENCLAW_TOKEN}" \
    -H "Content-Type: application/json" \
    -d "$PAYLOAD" \

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The comment at L06 states that all encryption/security is handled by the platform, implying the script has no security-sensitive handling. In reality, the script loads a sensitive API key from .env at L12-L15 and constructs/sends plaintext message content over HTTP requests at L32-L46, so the documentation understates the script's direct security-relevant behavior.

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/reply-handler.sh (reported line 43)May include surrounding context.

sh
exit 1
fi

RESULT=$(curl -s -X POST "${BASE_URL}/api/v1/message/${REQUEST_ID}" \
  -H "Content-Type: application/json" \
  -H "x-api-key: ${API_KEY}" \
  -d "$(node -e "console.log(JSON.stringify({plaintext:process.argv[1],from:'provider'}))" "$RESPONSE_TEXT" 2>/dev/null)")

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/respond.sh (reported line 30)May include surrounding context.

sh
exit 1
fi

RESULT=$(curl -s -X POST "${BASE_URL}/api/v1/message/${REQUEST_ID}" \
  -H "Content-Type: application/json" \
  -H "x-api-key: ${API_KEY}" \
  -d "$(node -e "console.log(JSON.stringify({plaintext:process.argv[1],from:'provider'}))" "$RESPONSE_TEXT" 2>/dev/null)")

Session Persistence

Medium
Category
Rogue Agent
Confidence
65% 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 · README.md (reported line 91)May include surrounding context.

md
kill "$(cat "$PIDFILE")" 2>/dev/null
  fi

  nohup bash "$WATCHER" >> "$LOGFILE" 2>&1 &
  echo $! > "$PIDFILE"
  echo "✅ Watcher started via nohup (PID: $(cat "$PIDFILE"), log: $LOGFILE)"
fi

Session Persistence

Medium
Category
Rogue Agent
Confidence
65% 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 · scripts/setup.sh (reported line 46)May include surrounding context.

sh
kill "$(cat "$PIDFILE")" 2>/dev/null
  fi

  nohup bash "$WATCHER" >> "$LOGFILE" 2>&1 &
  echo $! > "$PIDFILE"
  echo "✅ Watcher started via nohup (PID: $(cat "$PIDFILE"), log: $LOGFILE)"
fi

Static analysis

No suspicious patterns detected.