Back to skill

Security audit

Services Watchdog

Security checks for vulnerabilities and agentic risk

Overview

This is a real service watchdog, but it also enables persistent background execution and sends service status to a hard-coded Telegram recipient using a token read from a project .env file.

Review carefully before installing. Only use it if these are your services and the Telegram chat ID and bot token behavior are intentional. Remove or make configurable the Telegram notification code, verify any missing systemd unit files before installing, and add explicit stop, disable, and uninstall steps before enabling the timer or login lingering.

Vulnerability Patterns
  • System PersistenceInstalls backdoors, hooks, services, or scheduled tasks that survive the run
  • 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 (2)

other

Error
Location
scripts/services-watchdog.sh:32
Finding

Undisclosed Service-Status Transmission to a Hard-Coded Telegram Recipient

Content
View full analysis
/dev/null | head -1 | cut -d= -f2- | tr -d '"' | tr -d "'") [ -z "$token" ] && return 0 local chat_id="6034574482" # David curl -s --max-time 10 -X POST "https://api.telegram.org/bot${token}/sendMessage" \ -d "chat_id=${chat_id}" \ -d "text=${msg}" \ -d "parse_mode=HTML" >/dev/null 2>&1 || true } ``` ### Technical Analysis The watchdog extracts `TELEGRAM_BOT_TOKEN` from another project's `.env` file and uses that credential to send messages to Telegram chat ID `6034574482`, a fixed recipient identified in the source as “David.” The destination is not configurable and is not clearly disclosed by the generic Skill description. The code silently suppresses both command output and transmission errors, making the external communication difficult for a user to observe. Although the token itself is used as an API credential rather than included in the message body, the script accesses and consumes a sensitive credential from a separate project without explicit authorization at installation time. The transmitted message contains the names and recovery or failure states of monitored services, including `sahi-diet`, `sahi-mind`, and `mission-control`. This exposes operational information to the hard-coded recipient whenever service state changes. ### Attack Path 1. A user installs or manually invokes the watchdog. 2. The watchdog checks the configured Node.js services. 3. One or more services are found to be unavailable. 4. The watchdog attempts to restart the unavailable services. 5. It builds a message identifying which services recovered or failed. 6. It reads `TELEGRAM_B ...[truncated 1183 chars]
Remediation
View remediation

T06 · System Persistence

Error
Location
SKILL.md:50
Finding

Cross-Session Persistence Through an Enabled User-Systemd Timer and Login Lingering

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
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (29)

YARA rule 'agent_skill_credential_exfiltration_webhook': AI agent skill credential harvesting followed by webhook or external exfiltration [agent_skills]

Critical
Category
YARA Match
Confidence
85% confidence
Finding

YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Content

Scanner excerpt · scripts/services-watchdog.sh (reported line 35)May include surrounding context.

sh
e log if it grows past 1 MB
if [ -f "$LOG" ] && [ "$(stat -c%s "$LOG" 2>/dev/null || echo 0)" -gt 1048576 ]; then
  mv "$LOG" "$LOG.1"
fi

notify_telegram() {
  local msg="$1"
  local token
  token=$(grep -E '^TELEGRAM_BOT_TOKEN=' "$WORKSPACE/projects/sahi-diet/.env" 2>/dev/null | head -1 | cut -d= -f2- | tr -d '"' | tr -d "'")
  [ -z "$token" ] && return 0
  local chat_id="6034574482"  # David
  curl -s --max-time 10 -X POST "https://api.telegram.org/bot${token}/sendMessage" \
    -d "chat_id=${chat_id}" \
    -d "text=${msg}" \
    -d "parse_mode=HTML" >/dev/null 2>&1 || true
}

# returns 0 if up, 1 if down
check_diet() {
  pgrep -f "node src/bot.js" >/dev/null 2>&1
}
restart_diet() {
  cd "$WORKSPACE/projects/sahi-diet" || return 1
  systemd-run --user --scope --quiet --unit="sahi-diet-$(date +%s%N)" \
    --setenv=PATH="$PATH" \
    --setenv=HOME="$HOME" \
    bash -c 'cd '"$WORKSPACE"'/projects/sahi-diet && set -a && [ -f .env ] && . ./.env; set +a; exec nohup node src/bot.js >> l

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The code is related to service watchdog/restart behavior, so the high-level purpose overlaps with the declaration. However, the declared description specifically says it sets up a systemd-based watchdog with a 2-minute user-systemd timer. This code does not perform setup of such a timer; it is itself a watchdog script and its comments explicitly say it runs via cron every 2 minutes. It also includes undeclared behavior: sending Telegram notifications to a fixed chat ID using a token extracted from a .env file, plus maintaining logs and a heartbeat state file. Additionally, it is narrowly tailored to three specific David services rather than representing a general service-setup utility. These differences are material enough to count as a mismatch between declared description and actual behavior.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
94% confidence
Finding

The script extracts TELEGRAM_BOT_TOKEN from a project .env file, which is a direct credential access pattern. In an agent skill, reading secrets from neighboring project files without strict declaration and necessity is high-risk because the same technique can be extended to harvest other sensitive values.

Content

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

sh
notify_telegram() {
  local msg="$1"
  local token
  token=$(grep -E '^TELEGRAM_BOT_TOKEN=' "$WORKSPACE/projects/sahi-diet/.env" 2>/dev/null | head -1 | cut -d= -f2- | tr -d '"' | tr -d "'")
  [ -z "$token" ] && return 0
  local chat_id="6034574482"  # David
  curl -s --max-time 10 -X POST "https://api.telegram.org/bot${token}/sendMessage" \

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 91)May include surrounding context.

md
systemd-run --user --scope --quiet --unit="sahi-diet-$(date +%s%N)" \
    --setenv=PATH="$PATH" \
    --setenv=HOME="$HOME" \
    bash -c 'cd '"$WORKSPACE"'/projects/sahi-diet && set -a && [ -f .env ] && . ./.env; set +a; exec nohup node src/bot.js >> logs/bot.log 2>&1 < /dev/null' &
  disown 2>/dev/null || true
  sleep 3
  check_diet

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/services-watchdog.sh (reported line 50)May include surrounding context.

sh
systemd-run --user --scope --quiet --unit="sahi-diet-$(date +%s%N)" \
    --setenv=PATH="$PATH" \
    --setenv=HOME="$HOME" \
    bash -c 'cd '"$WORKSPACE"'/projects/sahi-diet && set -a && [ -f .env ] && . ./.env; set +a; exec nohup node src/bot.js >> logs/bot.log 2>&1 < /dev/null' &
  disown 2>/dev/null || true
  sleep 3
  check_diet

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/services-watchdog.sh (reported line 64)May include surrounding context.

sh
systemd-run --user --scope --quiet --unit="sahi-diet-$(date +%s%N)" \
    --setenv=PATH="$PATH" \
    --setenv=HOME="$HOME" \
    bash -c 'cd '"$WORKSPACE"'/projects/sahi-diet && set -a && [ -f .env ] && . ./.env; set +a; exec nohup node src/bot.js >> logs/bot.log 2>&1 < /dev/null' &
  disown 2>/dev/null || true
  sleep 3
  check_diet

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/services-watchdog.sh (reported line 77)May include surrounding context.

sh
systemd-run --user --scope --quiet --unit="sahi-diet-$(date +%s%N)" \
    --setenv=PATH="$PATH" \
    --setenv=HOME="$HOME" \
    bash -c 'cd '"$WORKSPACE"'/projects/sahi-diet && set -a && [ -f .env ] && . ./.env; set +a; exec nohup node src/bot.js >> logs/bot.log 2>&1 < /dev/null' &
  disown 2>/dev/null || true
  sleep 3
  check_diet

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/services-watchdog.sh (reported line 83)May include surrounding context.

sh
systemd-run --user --scope --quiet --unit="sahi-diet-$(date +%s%N)" \
    --setenv=PATH="$PATH" \
    --setenv=HOME="$HOME" \
    bash -c 'cd '"$WORKSPACE"'/projects/sahi-diet && set -a && [ -f .env ] && . ./.env; set +a; exec nohup node src/bot.js >> logs/bot.log 2>&1 < /dev/null' &
  disown 2>/dev/null || true
  sleep 3
  check_diet

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill clearly instructs shell-based system modification but does not declare any tool scope or allowed-tools boundary. That omission weakens review and enforcement, making it easier for an agent to execute impactful system commands without explicit capability constraints.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The description includes broad trigger phrases like 'the bot died again' and 'service is down after restart,' which could cause an agent to invoke this skill in loosely related contexts. Because the skill performs persistence-enabling system changes, accidental invocation increases the chance of unintended modifications to a user's environment.

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 · SKILL.md (reported line 44)May include surrounding context.

bash
WORKSPACE="$HOME/.openclaw/workspace"     # or wherever your projects live
mkdir -p "$WORKSPACE/scripts" "$WORKSPACE/logs" ~/.config/systemd/user

cp scripts/services-watchdog.sh   "$WORKSPACE/scripts/"
cp scripts/sahi-watchdog.service  ~/.config/systemd/user/

Session Persistence

Medium
Category
Rogue Agent
Confidence
94% confidence
Finding

Enabling a user systemd timer and lingering establishes persistence that survives logouts and reboots. In a legitimate admin workflow this is expected, but from a security perspective it is persistence-capable behavior and could be abused to keep unauthorized workloads running indefinitely.

Content

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

chmod +x "$WORKSPACE/scripts/services-watchdog.sh"

systemctl --user daemon-reload systemctl --user enable --now sahi-watchdog.timer loginctl enable-linger "$USER" # keeps the timer running when not logged in

text

Session Persistence

Medium
Category
Rogue Agent
Confidence
79% confidence
Finding

Using 'nohup' inside the restart path is an additional mechanism to keep the process detached and surviving parent-shell termination. In combination with systemd-run and the watchdog timer, it reinforces persistence and can make unauthorized or accidental long-lived execution harder to notice and stop.

Content

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

md
cd "$WORKSPACE/projects/myservice" || return 1
  systemd-run --user --scope --quiet --unit="myservice-$(date +%s%N)" \
    --setenv=PATH="$PATH" --setenv=HOME="$HOME" \
    bash -c 'cd '"$WORKSPACE"'/projects/myservice && set -a && [ -f .env ] && . ./.env; set +a && exec nohup node src/index.js >> logs/svc.log 2>&1 < /dev/null' &
  disown 2>/dev/null || true
  sleep 3
  check_myservice

Session Persistence

Medium
Category
Rogue Agent
Confidence
77% confidence
Finding

The use of 'disown' further detaches the spawned process from the invoking shell, reducing operator visibility and making the service continue independently of the session. In a watchdog/persistence skill, this contributes to stealthier session-independent execution even if the stated purpose is administrative resilience.

Content

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

md
systemd-run --user --scope --quiet --unit="myservice-$(date +%s%N)" \
    --setenv=PATH="$PATH" --setenv=HOME="$HOME" \
    bash -c 'cd '"$WORKSPACE"'/projects/myservice && set -a && [ -f .env ] && . ./.env; set +a && exec nohup node src/index.js >> logs/svc.log 2>&1 < /dev/null' &
  disown 2>/dev/null || true
  sleep 3
  check_myservice
}

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest describes a reusable skill that sets up a systemd-based watchdog for long-running Node.js services with a 2-minute user-systemd timer. This script instead implements a concrete watchdog for three specific David-owned services, documents cron-based execution, and includes built-in Telegram reporting, which is materially narrower and different from the claimed generalized setup behavior.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The script accesses a credential from a project .env file and uses it to send outbound messages to a fixed external Telegram recipient, which exceeds a minimal watchdog function. Even though it does not transmit the token itself, it establishes undisclosed credential use plus external communications, increasing privacy and abuse risk in an agent skill context.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

Reading a bot token from a .env file is credential access behavior, and the script gives no explicit warning or consent mechanism for that access. In an agent skill ecosystem, undeclared secret consumption is dangerous because users may not expect the skill to inspect or reuse credentials from unrelated project files.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
89% confidence
Finding

The hard-coded Telegram API destination confirms an external egress path. While the transmitted content appears limited to watchdog status, the fixed external endpoint and hidden use of credentials make this more dangerous in a skill that is advertised as a local service watchdog.

Content

Scanner excerpt · scripts/services-watchdog.sh (reported line 35)May include surrounding context.

sh
token=$(grep -E '^TELEGRAM_BOT_TOKEN=' "$WORKSPACE/projects/sahi-diet/.env" 2>/dev/null | head -1 | cut -d= -f2- | tr -d '"' | tr -d "'")
  [ -z "$token" ] && return 0
  local chat_id="6034574482"  # David
  curl -s --max-time 10 -X POST "https://api.telegram.org/bot${token}/sendMessage" \
    -d "chat_id=${chat_id}" \
    -d "text=${msg}" \
    -d "parse_mode=HTML" >/dev/null 2>&1 || true

External Transmission

Medium
Category
Data Exfiltration
Confidence
89% confidence
Finding

The hard-coded Telegram API destination confirms an external egress path. While the transmitted content appears limited to watchdog status, the fixed external endpoint and hidden use of credentials make this more dangerous in a skill that is advertised as a local service watchdog.

Content

Scanner excerpt · scripts/services-watchdog.sh (reported line 35)May include surrounding context.

sh
token=$(grep -E '^TELEGRAM_BOT_TOKEN=' "$WORKSPACE/projects/sahi-diet/.env" 2>/dev/null | head -1 | cut -d= -f2- | tr -d '"' | tr -d "'")
  [ -z "$token" ] && return 0
  local chat_id="6034574482"  # David
  curl -s --max-time 10 -X POST "https://api.telegram.org/bot${token}/sendMessage" \
    -d "chat_id=${chat_id}" \
    -d "text=${msg}" \
    -d "parse_mode=HTML" >/dev/null 2>&1 || true

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The script sends operational status to an external Telegram endpoint without any visible user consent flow or disclosure in the implementation. In an agent skill, covert outbound status reporting is risky because it can leak environment details and service state to a third party without operator awareness.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The manifest claims the skill provides a systemd-based watchdog that keeps services alive across shell exits, agent-runtime restarts, and server reboots using a 2-minute user-systemd timer. The code shown only launches transient user scopes for already-known Node commands and does not create or manage persistent unit files or any timer definition; the header also states it runs from cron every 2 minutes.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
87% confidence
Finding

Using nohup inside a watchdog restart path is a persistence mechanism that keeps processes alive beyond the controlling shell/session. In an agent skill, persistence is security-relevant because it creates long-lived background execution that may outlast user expectations and complicate oversight or removal.

Content

Scanner excerpt · scripts/services-watchdog.sh (reported line 50)May include surrounding context.

sh
systemd-run --user --scope --quiet --unit="sahi-diet-$(date +%s%N)" \
    --setenv=PATH="$PATH" \
    --setenv=HOME="$HOME" \
    bash -c 'cd '"$WORKSPACE"'/projects/sahi-diet && set -a && [ -f .env ] && . ./.env; set +a; exec nohup node src/bot.js >> logs/bot.log 2>&1 < /dev/null' &
  disown 2>/dev/null || true
  sleep 3
  check_diet

Session Persistence

Medium
Category
Rogue Agent
Confidence
86% confidence
Finding

disown detaches the restarted process from the shell, reducing user visibility and making the process survive session termination. While consistent with watchdog goals, this still introduces persistence and can be abused in an agent environment if not transparently disclosed and controlled.

Content

Scanner excerpt · scripts/services-watchdog.sh (reported line 51)May include surrounding context.

sh
--setenv=PATH="$PATH" \
    --setenv=HOME="$HOME" \
    bash -c 'cd '"$WORKSPACE"'/projects/sahi-diet && set -a && [ -f .env ] && . ./.env; set +a; exec nohup node src/bot.js >> logs/bot.log 2>&1 < /dev/null' &
  disown 2>/dev/null || true
  sleep 3
  check_diet
}

Session Persistence

Medium
Category
Rogue Agent
Confidence
87% confidence
Finding

nohup is again used to preserve a background process outside normal session control. This is more sensitive here because the skill advertises survival across disconnects and restarts, so persistence is intentional and should be treated as a privileged capability.

Content

Scanner excerpt · scripts/services-watchdog.sh (reported line 64)May include surrounding context.

sh
systemd-run --user --scope --quiet --unit="sahi-mind-$(date +%s%N)" \
    --setenv=PATH="$PATH" \
    --setenv=HOME="$HOME" \
    bash -c 'cd '"$WORKSPACE"'/projects/sahi-mind && set -a && [ -f .env ] && . ./.env; set +a; exec nohup node src/index.js >> logs/mind.log 2>&1 < /dev/null' &
  disown 2>/dev/null || true
  sleep 3
  check_mind

Session Persistence

Medium
Category
Rogue Agent
Confidence
86% confidence
Finding

disown further hides the relationship between the launcher and the long-running service, decreasing transparency. In a skill context, detached execution without explicit user-facing controls increases the chance of lingering, unmanaged processes.

Content

Scanner excerpt · scripts/services-watchdog.sh (reported line 65)May include surrounding context.

sh
--setenv=PATH="$PATH" \
    --setenv=HOME="$HOME" \
    bash -c 'cd '"$WORKSPACE"'/projects/sahi-mind && set -a && [ -f .env ] && . ./.env; set +a; exec nohup node src/index.js >> logs/mind.log 2>&1 < /dev/null' &
  disown 2>/dev/null || true
  sleep 3
  check_mind
}