Back to skill

Security audit

auto-rollback

Security checks for vulnerabilities and agentic risk

Overview

This rollback skill has a coherent safety purpose, but it needs Review because its launchd rollback implementation has unsafe script generation and can falsely report protection when scheduling fails.

Review this carefully before installing. The skill is not trying to hide its launchd rollback behavior, but it should validate state, fail closed when scheduling fails, and avoid generating executable shell source from environment-controlled values before being used as a safety mechanism for OpenClaw configuration changes.

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

T09 · Insecure Skill Coding Practices

Warning
Location
auto-rollback.sh:128
Finding

Environment-Controlled Paths Are Embedded into an Executable Rollback Script Without Shell Escaping

Content
View full analysis
"$rollback_script" <> "\$LOG_FILE" echo "\$1" } check_gateway_health() { if ! pgrep -f "openclaw.*gateway" >/dev/null 2>&1; then return 1 fi if curl -s -o /dev/null -w "%{http_code}" "http://127.0.0.1:\$GATEWAY_PORT/health" 2>/dev/null | grep -q "200"; then return 0 fi return 1 } log "🚨 rollback task started" if check_gateway_health; then log "✅ Gateway is already healthy, cancelling rollback" rm -f "\$STATE_FILE" "\$OPENCLAW_HOME_DIR/\$LAUNCHD_LABEL.plist" "\$OPENCLAW_HOME_DIR/.rollback_execute.sh" exit 0 fi log "❌ Gateway still unhealthy, restoring backup: \$BACKUP_FILE" cp "\$BACKUP_FILE" "$CONFIG_FILE" || { log "❌ Failed to restore backup" exit 1 } log "🔄 Restarting Gateway" "\$OPENCLAW_CMD" gateway restart || log "❌ Gateway restart command failed" sleep 5 if check_gateway_health; then log "🎉 Rollback completed and Gateway is healthy" else log "⚠️ Rollback completed but Gat ...[truncated 2364 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
auto-rollback.sh:300
Finding

Mutable Rollback State Can Cause Path Traversal During Plist Deletion

Content
View full analysis
/dev/null && log "✅ launchd job unloaded" || log "⚠️ launchd unload failed or job already ran" rm -f "$plist_file" "$OPENCLAW_HOME_DIR/.rollback_execute.sh" "$STATE_FILE" ``` The same pattern is present in the BOOT integration: ```bash LABEL=$(jq -r '.launchd_label // empty' "$STATE") PLIST="$HOME/.openclaw/${LABEL}.plist" ``` ```bash if [ -n "$LABEL" ] && [ -f "$PLIST" ]; then launchctl unload "$PLIST" 2>/dev/null || true rm -f "$PLIST" rm -f "$HOME/.openclaw/.rollback_execute.sh" echo "[$(date -Iseconds)] BOOT: rollback cancelled (label=$LABEL)" >> "$LOG" fi ``` ### Technical Analysis The expected label is a constant, `ai.openclaw.rollback`, but cancellation trusts the `launchd_label` property stored in `rollback-pending.json`. No validation requires that the stored value match this constant or prohibits path separators and `..` components. A malicious label such as `../../Library/LaunchAgents/target` produces a path outside the intended `~/.openclaw` directory after filesystem path resolution: ```text ~/.openclaw/../../Library/LaunchAgents/target.plist ``` If that file exists and is writable by the current user, the cancellation logic can pass it to `launchctl unload` and delete it with `rm -f`. Exploitation requires the attacker to modify or replace the rollback state file. This generally implies some existing access to the user's OpenClaw state directory, which limits severity, but the flaw expand ...[truncated 1156 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
auto-rollback.sh:282
Finding

Rollback Protection Is Reported as Pending Even When launchd Registration Fails

Content
View full analysis
/dev/null && log "✅ launchd job loaded" || log "⚠️ launchd load failed or job already exists" write_state_file "$backup_file" "$rollback_time" "$reason" || { log "❌ Failed to write state file" rm -f "$plist_file" "$rollback_script" exit 1 } log "✅ State file written: $STATE_FILE" log "📋 Next step: $OPENCLAW_CMD gateway restart" log "⚠️ If Gateway stays unhealthy, rollback will run in ${ROLLBACK_DELAY_MINUTES} minutes" ``` The generated scheduled script removes its plist and itself but does not explicitly unload the launchd job: ```bash if check_gateway_health; then log "✅ Gateway is already healthy, cancelling rollback" rm -f "\$STATE_FILE" "\$OPENCLAW_HOME_DIR/\$LAUNCHD_LABEL.plist" "\$OPENCLAW_HOME_DIR/.rollback_execute.sh" exit 0 fi ``` ```bash rm -f "\$STATE_FILE" "\$OPENCLAW_HOME_DIR/\$LAUNCHD_LABEL.plist" "\$0" ``` ### Technical Analysis The Skill’s central security property is that a rollback task will execute after ten minutes if Gateway remains unhealthy. That property depends on successful launchd registration. However, any failure from `launchctl load` is ignored. The script proceeds to create the state file and tells the user that rollback will run. Registration can fail because of a malformed environment, an existing label, launchd state, permissions, or other operational errors. The scheduled script also deletes the plist without explicitly unloading or removing the registered launchd service. launchd maintains loaded job state independently of the plist file, so deleting the source plist is ...[truncated 2265 chars]
Remediation
View remediation
Vulnerability Patterns
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • 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 (30)

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
85% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · BOOT.md (reported line 31)May include surrounding context.

md
if [ -n "$LABEL" ] && [ -f "$PLIST" ]; then
      launchctl unload "$PLIST" 2>/dev/null || true
      rm -f "$PLIST"
      rm -f "$HOME/.openclaw/.rollback_execute.sh"
      echo "[$(date -Iseconds)] BOOT: rollback cancelled (label=$LABEL)" >> "$LOG"
    else
      echo "[$(date -Iseconds)] BOOT: rollback state present but plist missing (label=$LABEL)" >> "$LOG"

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

This markdown file documents a startup checklist fragment that unloads a launchd plist and deletes multiple local files to cancel a pending rollback. While the snippet logs to a file, the surrounding markdown does not warn the user that running it will perform destructive state changes affecting rollback behavior and local system files.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
87% confidence
Finding

This duplicate finding points to the same issue: a persistence-related plist filename is constructed from untrusted JSON state and later acted upon. In the context of a rollback skill that manages launchd jobs, path control over the plist can affect what persistence artifact is modified or removed.

Content

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

md
if [ -f "$STATE" ]; then
  LABEL=$(jq -r '.launchd_label // empty' "$STATE")
  PLIST="$HOME/.openclaw/${LABEL}.plist"

  echo "[$(date -Iseconds)] BOOT: detected rollback state file: $STATE" >> "$LOG"
  echo "[$(date -Iseconds)] BOOT: waiting for Gateway health check" >> "$LOG"

Session Persistence

Medium
Category
Rogue Agent
Confidence
87% confidence
Finding

This duplicate finding points to the same issue: a persistence-related plist filename is constructed from untrusted JSON state and later acted upon. In the context of a rollback skill that manages launchd jobs, path control over the plist can affect what persistence artifact is modified or removed.

Content

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

md
if [ -f "$STATE" ]; then
  LABEL=$(jq -r '.launchd_label // empty' "$STATE")
  PLIST="$HOME/.openclaw/${LABEL}.plist"

  echo "[$(date -Iseconds)] BOOT: detected rollback state file: $STATE" >> "$LOG"
  echo "[$(date -Iseconds)] BOOT: waiting for Gateway health check" >> "$LOG"

Session Persistence

Medium
Category
Rogue Agent
Confidence
90% confidence
Finding

At this point the script uses the previously constructed PLIST path in a file-existence check before unloading the corresponding launchd job. Because PLIST originates from unvalidated state-file data, the script can be tricked into operating on unintended files or jobs if the state file is attacker-controlled.

Content

Scanner excerpt · BOOT.md (reported line 28)May include surrounding context.

md
done

  if [ "$HEALTHY" = true ]; then
    if [ -n "$LABEL" ] && [ -f "$PLIST" ]; then
      launchctl unload "$PLIST" 2>/dev/null || true
      rm -f "$PLIST"
      rm -f "$HOME/.openclaw/.rollback_execute.sh"

Session Persistence

Medium
Category
Rogue Agent
Confidence
91% confidence
Finding

The script calls launchctl unload on a plist path derived from untrusted state content. If an attacker can alter the rollback state file, they may cause unloading of an unintended launch agent, disrupting services or altering persistence behavior within the user context.

Content

Scanner excerpt · BOOT.md (reported line 29)May include surrounding context.

md
if [ "$HEALTHY" = true ]; then
    if [ -n "$LABEL" ] && [ -f "$PLIST" ]; then
      launchctl unload "$PLIST" 2>/dev/null || true
      rm -f "$PLIST"
      rm -f "$HOME/.openclaw/.rollback_execute.sh"
      echo "[$(date -Iseconds)] BOOT: rollback cancelled (label=$LABEL)" >> "$LOG"

Session Persistence

Medium
Category
Rogue Agent
Confidence
92% confidence
Finding

The script removes the plist file at a path influenced by untrusted state data. That can lead to deletion of unintended files within the user's permissions if the label contains traversal or otherwise manipulates the constructed path.

Content

Scanner excerpt · BOOT.md (reported line 30)May include surrounding context.

md
if [ "$HEALTHY" = true ]; then
    if [ -n "$LABEL" ] && [ -f "$PLIST" ]; then
      launchctl unload "$PLIST" 2>/dev/null || true
      rm -f "$PLIST"
      rm -f "$HOME/.openclaw/.rollback_execute.sh"
      echo "[$(date -Iseconds)] BOOT: rollback cancelled (label=$LABEL)" >> "$LOG"
    else

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

md
rm -f "$HOME/.openclaw/.rollback_execute.sh"
      echo "[$(date -Iseconds)] BOOT: rollback cancelled (label=$LABEL)" >> "$LOG"
    else
      echo "[$(date -Iseconds)] BOOT: rollback state present but plist missing (label=$LABEL)" >> "$LOG"
    fi

    rm -f "$STATE"

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

md
rm -f "$HOME/.openclaw/.rollback_execute.sh"
      echo "[$(date -Iseconds)] BOOT: rollback cancelled (label=$LABEL)" >> "$LOG"
    else
      echo "[$(date -Iseconds)] BOOT: rollback state present but plist missing (label=$LABEL)" >> "$LOG"
    fi

    rm -f "$STATE"

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 · auto-rollback.sh (reported line 168)May include surrounding context.

sh
rm -f "$HOME/.openclaw/.rollback_execute.sh"
      echo "[$(date -Iseconds)] BOOT: rollback cancelled (label=$LABEL)" >> "$LOG"
    else
      echo "[$(date -Iseconds)] BOOT: rollback state present but plist missing (label=$LABEL)" >> "$LOG"
    fi

    rm -f "$STATE"

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 · auto-rollback.sh (reported line 188)May include surrounding context.

sh
rm -f "$HOME/.openclaw/.rollback_execute.sh"
      echo "[$(date -Iseconds)] BOOT: rollback cancelled (label=$LABEL)" >> "$LOG"
    else
      echo "[$(date -Iseconds)] BOOT: rollback state present but plist missing (label=$LABEL)" >> "$LOG"
    fi

    rm -f "$STATE"

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 · auto-rollback.sh (reported line 206)May include surrounding context.

sh
rm -f "$HOME/.openclaw/.rollback_execute.sh"
      echo "[$(date -Iseconds)] BOOT: rollback cancelled (label=$LABEL)" >> "$LOG"
    else
      echo "[$(date -Iseconds)] BOOT: rollback state present but plist missing (label=$LABEL)" >> "$LOG"
    fi

    rm -f "$STATE"

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 · auto-rollback.sh (reported line 235)May include surrounding context.

sh
rm -f "$HOME/.openclaw/.rollback_execute.sh"
      echo "[$(date -Iseconds)] BOOT: rollback cancelled (label=$LABEL)" >> "$LOG"
    else
      echo "[$(date -Iseconds)] BOOT: rollback state present but plist missing (label=$LABEL)" >> "$LOG"
    fi

    rm -f "$STATE"

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 · auto-rollback.sh (reported line 237)May include surrounding context.

sh
rm -f "$HOME/.openclaw/.rollback_execute.sh"
      echo "[$(date -Iseconds)] BOOT: rollback cancelled (label=$LABEL)" >> "$LOG"
    else
      echo "[$(date -Iseconds)] BOOT: rollback state present but plist missing (label=$LABEL)" >> "$LOG"
    fi

    rm -f "$STATE"

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 · auto-rollback.sh (reported line 238)May include surrounding context.

sh
rm -f "$HOME/.openclaw/.rollback_execute.sh"
      echo "[$(date -Iseconds)] BOOT: rollback cancelled (label=$LABEL)" >> "$LOG"
    else
      echo "[$(date -Iseconds)] BOOT: rollback state present but plist missing (label=$LABEL)" >> "$LOG"
    fi

    rm -f "$STATE"

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 · auto-rollback.sh (reported line 270)May include surrounding context.

sh
rm -f "$HOME/.openclaw/.rollback_execute.sh"
      echo "[$(date -Iseconds)] BOOT: rollback cancelled (label=$LABEL)" >> "$LOG"
    else
      echo "[$(date -Iseconds)] BOOT: rollback state present but plist missing (label=$LABEL)" >> "$LOG"
    fi

    rm -f "$STATE"

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 · auto-rollback.sh (reported line 273)May include surrounding context.

sh
rm -f "$HOME/.openclaw/.rollback_execute.sh"
      echo "[$(date -Iseconds)] BOOT: rollback cancelled (label=$LABEL)" >> "$LOG"
    else
      echo "[$(date -Iseconds)] BOOT: rollback state present but plist missing (label=$LABEL)" >> "$LOG"
    fi

    rm -f "$STATE"

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 · auto-rollback.sh (reported line 274)May include surrounding context.

sh
rm -f "$HOME/.openclaw/.rollback_execute.sh"
      echo "[$(date -Iseconds)] BOOT: rollback cancelled (label=$LABEL)" >> "$LOG"
    else
      echo "[$(date -Iseconds)] BOOT: rollback state present but plist missing (label=$LABEL)" >> "$LOG"
    fi

    rm -f "$STATE"

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 · auto-rollback.sh (reported line 275)May include surrounding context.

sh
rm -f "$HOME/.openclaw/.rollback_execute.sh"
      echo "[$(date -Iseconds)] BOOT: rollback cancelled (label=$LABEL)" >> "$LOG"
    else
      echo "[$(date -Iseconds)] BOOT: rollback state present but plist missing (label=$LABEL)" >> "$LOG"
    fi

    rm -f "$STATE"

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 · auto-rollback.sh (reported line 279)May include surrounding context.

sh
rm -f "$HOME/.openclaw/.rollback_execute.sh"
      echo "[$(date -Iseconds)] BOOT: rollback cancelled (label=$LABEL)" >> "$LOG"
    else
      echo "[$(date -Iseconds)] BOOT: rollback state present but plist missing (label=$LABEL)" >> "$LOG"
    fi

    rm -f "$STATE"

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 · auto-rollback.sh (reported line 282)May include surrounding context.

sh
rm -f "$HOME/.openclaw/.rollback_execute.sh"
      echo "[$(date -Iseconds)] BOOT: rollback cancelled (label=$LABEL)" >> "$LOG"
    else
      echo "[$(date -Iseconds)] BOOT: rollback state present but plist missing (label=$LABEL)" >> "$LOG"
    fi

    rm -f "$STATE"

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 · auto-rollback.sh (reported line 286)May include surrounding context.

sh
rm -f "$HOME/.openclaw/.rollback_execute.sh"
      echo "[$(date -Iseconds)] BOOT: rollback cancelled (label=$LABEL)" >> "$LOG"
    else
      echo "[$(date -Iseconds)] BOOT: rollback state present but plist missing (label=$LABEL)" >> "$LOG"
    fi

    rm -f "$STATE"

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 · auto-rollback.sh (reported line 306)May include surrounding context.

sh
rm -f "$HOME/.openclaw/.rollback_execute.sh"
      echo "[$(date -Iseconds)] BOOT: rollback cancelled (label=$LABEL)" >> "$LOG"
    else
      echo "[$(date -Iseconds)] BOOT: rollback state present but plist missing (label=$LABEL)" >> "$LOG"
    fi

    rm -f "$STATE"

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 · auto-rollback.sh (reported line 309)May include surrounding context.

sh
rm -f "$HOME/.openclaw/.rollback_execute.sh"
      echo "[$(date -Iseconds)] BOOT: rollback cancelled (label=$LABEL)" >> "$LOG"
    else
      echo "[$(date -Iseconds)] BOOT: rollback state present but plist missing (label=$LABEL)" >> "$LOG"
    fi

    rm -f "$STATE"

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 · auto-rollback.sh (reported line 311)May include surrounding context.

sh
rm -f "$HOME/.openclaw/.rollback_execute.sh"
      echo "[$(date -Iseconds)] BOOT: rollback cancelled (label=$LABEL)" >> "$LOG"
    else
      echo "[$(date -Iseconds)] BOOT: rollback state present but plist missing (label=$LABEL)" >> "$LOG"
    fi

    rm -f "$STATE"

Static analysis

No suspicious patterns detected.