T09 · Insecure Skill Coding Practices
- Location
scripts/restore.mjs:17- Finding
Arbitrary Shell Command Execution Through Mutable Restart Configuration
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill matches its rollback purpose, but it needs review because it installs persistent recovery hooks and can automatically overwrite OpenClaw configuration with weak safeguards.
Install only if you intentionally want a persistent local rollback system that can overwrite OpenClaw config and restart the gateway after a timer expires. Before using it on production systems, restrict rollback directory permissions, review what openclaw.json contains, validate snapshot contents before restore, avoid arbitrary shell restart commands, and make sure you have independent terminal access for manual recovery.
scripts/restore.mjs:17Arbitrary Shell Command Execution Through Mutable Restart Configuration
scripts/restore.mjs:21Unvalidated Snapshot Archive Selection and Extraction to the Filesystem Root
scripts/snapshot.mjs:55Gateway Credentials Are Stored in Plaintext Snapshot Archives Without Enforced Access Controls
Even though the matched pattern duplicates the same line, the underlying issue remains a real hazard: rm -rf is an unsafe primitive in human-run instructions and can be catastrophic if the home directory or path is resolved unexpectedly. The context makes it more sensitive because administrators using rollback tooling may assume the docs are safe and run destructive steps quickly during maintenance or recovery.
If the user wants to reinstall from scratch:
1. Back up existing snapshots: `cp -r ~/.openclaw/rollback/snapshots/ /tmp/openclaw-snapshots-backup/`
2. `rm -rf ~/.openclaw/rollback/`
3. Remove any old startup hook that points at a previous rollback install, if present.
4. Run setup again from Step 1.
5. Ask the user if they want their old snapshots restored from the backup.
Even though the matched pattern duplicates the same line, the underlying issue remains a real hazard: rm -rf is an unsafe primitive in human-run instructions and can be catastrophic if the home directory or path is resolved unexpectedly. The context makes it more sensitive because administrators using rollback tooling may assume the docs are safe and run destructive steps quickly during maintenance or recovery.
If the user wants to reinstall from scratch:
1. Back up existing snapshots: `cp -r ~/.openclaw/rollback/snapshots/ /tmp/openclaw-snapshots-backup/`
2. `rm -rf ~/.openclaw/rollback/`
3. Remove any old startup hook that points at a previous rollback install, if present.
4. Run setup again from Step 1.
5. Ask the user if they want their old snapshots restored from the backup.
Even though the matched pattern duplicates the same line, the underlying issue remains a real hazard: rm -rf is an unsafe primitive in human-run instructions and can be catastrophic if the home directory or path is resolved unexpectedly. The context makes it more sensitive because administrators using rollback tooling may assume the docs are safe and run destructive steps quickly during maintenance or recovery.
If the user wants to reinstall from scratch:
1. Back up existing snapshots: `cp -r ~/.openclaw/rollback/snapshots/ /tmp/openclaw-snapshots-backup/`
2. `rm -rf ~/.openclaw/rollback/`
3. Remove any old startup hook that points at a previous rollback install, if present.
4. Run setup again from Step 1.
5. Ask the user if they want their old snapshots restored from the backup.
The skill describes operational behaviors that read environment state, inspect local processes, and invoke local scripts, but it declares no explicit tool scope or permissions boundary. In a skill that performs file backup, restore, and restart-related actions, missing scope increases the chance the agent can invoke capabilities more broadly than intended or without clear user/auditor visibility.
The skill is explicitly designed to create persistent state across sessions through snapshots, watchdog files, startup hooks, and automatic post-restart behavior. Persistent autonomous behavior is risky here because it can continue modifying local configuration after the original conversation ends, including restoring files and restarting service state based on prior instructions.
OpenClaw Emergency Config Rollback — dead man's switch system for safely making
risky changes to OpenClaw configuration. Use this skill whenever the user mentions
wanting to make changes to openclaw.json or agent configs and wants a safety net,
says anything like "set emergency recovery", "create a snapshot", "take a backup
before changes", "set a backout timer", "restore snapshot", "accept changes",
"test emergency recovery", "run recovery test", "how does the rollback work",
"what rollback commands", or any variation of wanting to safely change OpenClaw
The activation text is overly broad and can trigger on general discussion of recovery, rollback, backups, or explanation requests, causing a high-risk operational skill to engage in contexts where the user may only want information. Because this skill can lead to destructive testing, config overwrites, and gateway restarts, over-triggering materially raises the risk of unintended disruptive actions.
The command set encourages creation and retention of persistent snapshots that become future restore targets. In this context, session persistence is more dangerous than usual because stored state can later overwrite current configuration, making stale or poisoned snapshots a long-lived recovery mechanism that outlasts the initiating session.
• "extend recovery XX minutes" — add more time to the timer • "list snapshots" — show all saved snapshots • "restore snapshot 2" — manually restore snapshot 2 or 3 • "create snapshot" — save current state as new snapshot [1]
---
This persistent restore path can overwrite the current OpenClaw configuration and trigger a gateway restart, effects that survive beyond the immediate session. In a rollback skill, persistent state is contextually more dangerous because it directly enables later destructive actions against availability and system configuration, even if the original conversation is no longer active.
### "restore snapshot [1|2|3]"
Manually restore a specific snapshot immediately.
1. Confirm with user: "This will overwrite your current OpenClaw config with
snapshot [N] '<label>' from <timestamp> and restart the gateway. Are you sure?"
2. On confirmation: run `~/.openclaw/rollback/scripts/restore.mjs <slot>`
3. Gateway restarts. Next session will detect uptime < 90 seconds.
The restore procedure instructs users to run unzip -o ... -d /, which forcibly overwrites files at absolute paths without any confirmation, dry run, or explicit warning about clobbering current state. In this skill's context, the archive is intended to restore OpenClaw configs, but because it preserves full paths and extracts to /, any unexpected or maliciously crafted archive contents could overwrite arbitrary files accessible to the user, making the operation materially dangerous.
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
Node.js is required to run OpenClaw itself, so it is always present. If `zip`
or `unzip` are missing (common on stripped Docker images), install them:
- **Ubuntu/Debian VPS:** `sudo apt-get install -y tar gzip`
- **Docker (node:22-bookworm-slim):** Set `OPENCLAW_DOCKER_APT_PACKAGES="tar gzip"`
in your Docker setup, or add to Dockerfile: `RUN apt-get update && apt-get install -y tar gzip`
The setup tells the operator to provide a restart command and says it will be stored, but the generated config hardcodes kill -USR1 1 instead. In a rollback system, using the wrong restart command can cause failed recovery, unexpected signaling of PID 1, or service disruption on platforms where that signal is incorrect.
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.
mkdir -p ~/.openclaw/rollback/snapshots
The file advertises a 'destructive' recovery test without explaining what resources, configs, or service state it will modify, and without instructing the operator to confirm before execution. In a rollback skill, ambiguity around destructive testing can lead users to trigger service restarts, config replacement, or downtime unintentionally.
The reinstall instructions include deletion of the rollback directory with rm -rf but do not place a clear, immediate warning next to the command about irreversible data loss if backups are incomplete or incorrect. In operational docs, destructive commands without strong confirmation language increase the chance of accidental deletion of snapshots or rollback state.
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.
directory is properly initialized, and that all scripts are present. If anything fails, stop and fix it before continuing.
~/.openclaw/rollback/scripts/snapshot.mjs "pre-test known-good config" "Snapshot taken before recovery test."
The document first instructs operators to use the actual restart command from rollback-config.json, but the failed-test cleanup section later hard-codes kill -USR1 1. In recovery scenarios, inconsistent restart instructions can cause the service to fail to restart, restart the wrong process, or behave differently across deployments, increasing outage duration during an already disruptive destructive test.
The header comment documents the sabotage subcommand as deliberately breaking openclaw.json into invalid JSON and verify as checking whether it became valid JSON again. In reality, lines L141-L156 mutate fields and then write the file back with JSON.stringify, preserving valid JSON; the verify logic correspondingly checks for poisoned values rather than JSON restoration alone.
The sabotage subcommand deliberately modifies a live configuration file in a destructive way without any interactive confirmation, dry-run guard, environment check, or explicit force flag. In the context of an emergency rollback skill, this is more dangerous because the tool is designed for operational use on real systems, so accidental invocation can break authentication and routing immediately and may cause service outage or lockout before recovery occurs.
The script executes a restart command from configuration via execSync with a bash shell, which turns a configuration value into arbitrary command execution. In the context of an emergency rollback skill that restores files to / and then restarts automatically, any attacker who can influence config or snapshot contents can gain reliable code execution during a privileged recovery path.
The script extracts a snapshot tarball directly to '/' with overwrite semantics, which is a safety-critical file write operation affecting the whole system. Although the file has internal comments and logging, there is no user-facing disclosure at the point of execution, and the script is explicitly designed for zero user interaction.
The Node.js snippet reads and rewrites ~/.openclaw/rollback/watchdog.json, changing the watchdog state. While the intent is described, the documentation does not clearly warn that it edits rollback metadata on disk, which affects future recovery behavior.
The documentation says the system uses zip and unzip, but the checks and install commands verify tar and gzip instead, which is inconsistent and can leave operators without the tools the rollback workflow actually needs. This is primarily a reliability and recovery-readiness issue: backups or restores may fail when urgently needed.
The inline comment on L47 says 'Restore files — unzip with full path overwrite to /', and the warning log on L53 also refers to an 'unzip exit code'. However, the implementation on L50 invokes tar -xzf, not unzip. This is a direct documentation-to-code contradiction, even though the overall restore intent is the same.
Detected: suspicious.dangerous_exec, suspicious.destructive_delete_command