Back to skill

Security audit

Gateway Watchdog

Security checks for vulnerabilities and agentic risk

Overview

This skill is a disclosed OpenClaw gateway watchdog, but it installs a persistent auto-restart LaunchAgent and has an unsafe shared temporary-file pattern that users should review before installing.

Install only if you want a user-level background job that checks the OpenClaw gateway every 5 minutes and may restart it automatically. Before loading it, verify the script path, know how to unload the LaunchAgent, and consider changing the cooldown file to a private directory such as ~/.openclaw/run to avoid shared-/tmp symlink risks.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/gateway-watchdog.sh:17
Finding

Predictable Shared Temporary File Permits Symlink-Based File Overwrite

Content
View full analysis

Vulnerability Details

File Location: scripts/gateway-watchdog.sh, lines 17 and 67–78
Vulnerability Type: Unsafe temporary file handling
Risk Level: Medium

Vulnerable Code

bash
COOLDOWN_FILE="/tmp/openclaw-gateway-restart-cooldown"
bash
is_in_cooldown() {
    if [ -f "$COOLDOWN_FILE" ]; then
        local cooldown_time
        cooldown_time=$(cat "$COOLDOWN_FILE" 2>/dev/null)
        local now
        now=$(date "+%s")
        if [ -n "$cooldown_time" ] && [ $(( now - cooldown_time )) -lt $COOLDOWN_SECONDS ]; then
            return 0  # still in cooldown
        fi
    fi
    return 1  # not in cooldown
}

set_cooldown() {
    date "+%s" > "$COOLDOWN_FILE"
}

Technical Analysis

The watchdog stores its restart cooldown state at a fixed, predictable path in the shared /tmp directory. The file is neither securely created nor checked for symbolic links before shell redirection writes to it.

A local attacker who can write to /tmp can pre-create /tmp/openclaw-gateway-restart-cooldown as a symbolic link. When set_cooldown executes, the > redirection follows that link and truncates the linked target before writing an epoch timestamp.

The service is documented as a per-user LaunchAgent, so the write occurs with the privileges of the user running the watchdog. This limits the target to files writable by that user and does not independently provide root privilege escalation.

Attack Path

  1. A local attacker identifies a file writable by the watchdog user.
  2. The attacker creates /tmp/openclaw-gateway-restart-cooldown as a symbolic link to that target.
  3. The gateway becomes unavailable, or the attacker causes its loopback health check to fail.
  4. The watchdog exhausts its HTTP and port retries.
  5. If the cooldown check does not prevent a restart, restart_gateway invokes set_cooldown.
  6. Shell redirection follows the attacker-controlled sym ...[truncated 695 chars]
Remediation
View remediation

Remediation Suggestions

  • Move the cooldown state out of shared /tmp and into a private per-user directory, such as $HOME/.openclaw/run.
  • Create that directory with mode 0700 and the state file with mode 0600.
  • Reject symbolic links and unexpected file types before reading state.
  • Write state to a securely created temporary file within the private directory and atomically rename it into place.
  • Validate cooldown content as an unsigned integer before arithmetic evaluation.
  • Use a per-user path if temporary storage remains necessary, and ensure ownership and permissions are verified.

Example hardened approach:

bash
STATE_DIR="$HOME/.openclaw/run"
COOLDOWN_FILE="$STATE_DIR/gateway-restart-cooldown"

mkdir -p "$STATE_DIR"
chmod 700 "$STATE_DIR"

set_cooldown() {
    local temporary_file
    temporary_file=$(mktemp "$STATE_DIR/.cooldown.XXXXXX") || return 1
    chmod 600 "$temporary_file"
    date "+%s" > "$temporary_file" || {
        rm -f "$temporary_file"
        return 1
    }
    mv -f "$temporary_file" "$COOLDOWN_FILE"
}
Vulnerability Patterns
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (9)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill explicitly documents shell-based behavior and launchd setup, but it does not declare any tool scope such as permissions or allowed-tools. That omission weakens reviewability and execution boundaries because consumers cannot easily tell that the skill expects shell access and persistence-related actions.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This markdown file documents creating and loading a LaunchAgent that runs every 5 minutes and is explicitly designed to restart a production gateway. That behavior affects system process management and persistence, but the instructions do not include any user-facing warning about the ongoing automatic action or its operational impact.

Content

No source excerpt is available for this finding.

Session Persistence

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

Setup (macOS launchd)

Create ~/Library/LaunchAgents/com.openclaw.gateway-watchdog.plist:

xml
<?xml version="1.0" encoding="UTF-8"?>

Session Persistence

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

Setup (macOS launchd)

Create ~/Library/LaunchAgents/com.openclaw.gateway-watchdog.plist:

xml
<?xml version="1.0" encoding="UTF-8"?>

Session Persistence

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

Setup (macOS launchd)

Create ~/Library/LaunchAgents/com.openclaw.gateway-watchdog.plist:

xml
<?xml version="1.0" encoding="UTF-8"?>

Session Persistence

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

Setup (macOS launchd)

Create ~/Library/LaunchAgents/com.openclaw.gateway-watchdog.plist:

xml
<?xml version="1.0" encoding="UTF-8"?>

Session Persistence

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

xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>

Session Persistence

Medium
Category
Rogue Agent
Confidence
78% confidence
Finding

The documented launchctl load command instructs the user to activate a recurring background agent, which establishes persistence for code execution at login/load and every 5 minutes. Even though the use case is operationally legitimate, this is security-relevant because it enables ongoing autonomous process control and restart behavior.

Content

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

Then load it:

bash
launchctl load ~/Library/LaunchAgents/com.openclaw.gateway-watchdog.plist

Usage (manual)

Session Persistence

Medium
Category
Rogue Agent
Confidence
78% confidence
Finding

The documented launchctl load command instructs the user to activate a recurring background agent, which establishes persistence for code execution at login/load and every 5 minutes. Even though the use case is operationally legitimate, this is security-relevant because it enables ongoing autonomous process control and restart behavior.

Content

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

Then load it:

bash
launchctl load ~/Library/LaunchAgents/com.openclaw.gateway-watchdog.plist

Usage (manual)

Static analysis

No suspicious patterns detected.