Back to skill

Security audit

OpenClaw Configuration Management & Emergency Recovery

Security checks for vulnerabilities and agentic risk

Overview

This recovery skill is purpose-aligned but has high-impact restore and startup-hook behavior with under-scoped safeguards that users should review carefully before installing.

Install only if you need an emergency rollback system and are comfortable with a persistent startup hook that can overwrite OpenClaw configuration and restart the gateway. Before use, restrict permissions on ~/.openclaw/rollback, inspect or protect snapshot archives and manifests, avoid free-form restart commands, and require explicit confirmation before restoring skills or projects.

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

Error
Location
scripts/restore.mjs:16
Finding

Persisted Restart Command Is Executed Through an Unrestricted Shell

Content
View full analysis

Vulnerability Details

File Location: scripts/restore.mjs:16-19, 66-73; references/TESTING.md:108-112
Vulnerability Type: OS command injection through persisted configuration
Risk Level: High

Vulnerable Code

js
const SLOT = parseInt(process.argv[2] || '1', 10);
const config = getConfig();
const manifest = getManifest();
const RESTART_CMD = config.restartCommand || 'kill -USR1 1';
js
// Run restart command
let restartExit = 0;
try {
  execSync(RESTART_CMD, { stdio: 'inherit', shell: '/bin/bash' });
} catch (e) {
  restartExit = e.status || 1;
}

The destructive testing instructions also execute the persisted value using eval:

bash
RESTART_CMD=$(node -e "console.log(require('$HOME/.openclaw/rollback/rollback-config.json').restartCommand)")
eval "$RESTART_CMD"

Technical Analysis

The restartCommand property is loaded from rollback-config.json as unrestricted text and passed directly to Bash. The implementation does not validate the executable, separate arguments from the command, reject shell metacharacters, or restrict the command to supported restart mechanisms.

Because Bash interprets operators such as semicolons, substitutions, redirections, and pipelines, a malicious value is not limited to restarting OpenClaw. For example, a value conceptually equivalent to a legitimate restart command followed by another shell command would execute both operations.

Setup documentation allows an alternative restart command to be supplied and persisted. The same persisted value can subsequently be invoked automatically after watchdog restoration, making exploitation possible without further confirmation at execution time.

Attack Path

  1. An attacker or unsafe setup workflow places a shell payload in the restartCommand field of ~/.openclaw/rollback/rollback-config.json.
  2. A config restore is initiated manually, or the watchdog expires and invokes ` ...[truncated 1078 chars]
Remediation
View remediation

Remediation Suggestions

  • Replace the free-form command string with a structured restart configuration containing a fixed method and validated arguments.
  • Define an allowlist of supported methods, such as systemd-user, systemd-system, docker-compose, and pid1-signal.
  • Invoke the selected executable using spawnSync or execFileSync with an argument array and shell: false.
  • Validate service and container names against a strict pattern such as ^[A-Za-z0-9_.-]+$.
  • Reject shell operators, substitutions, newlines, redirections, and unrecognized executables during setup.
  • Remove eval from references/TESTING.md; use the same structured restart helper used by the restore implementation.
  • Protect rollback-config.json with mode 0600 and verify that it is owned by the expected gateway account before use.
  • Log the selected restart method and argument array rather than an executable shell string.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/snapshot.mjs:52
Finding

Sensitive OpenClaw Configuration Backups Are Created Without Explicit Restrictive Permissions

Content
View full analysis

Vulnerability Details

File Location: scripts/snapshot.mjs:52-59, 64, 117; scripts/recovery-test.mjs:106-112; scripts/utils.mjs:39-43
Vulnerability Type: Insecure storage of sensitive configuration data
Risk Level: Medium

Vulnerable Code

js
function stageFile(src) {
  if (!existsSync(src)) return false;
  const dest = join(stageDir, src);
  mkdirSync(dirname(dest), { recursive: true });
  copyFileSync(src, dest);
  filesCaptured.push(src);
  return true;
}

// 1) Stage openclaw.json (root master config)
stageFile(OC_JSON);
js
copyFileSync(tmpZip, snap1); unlinkSync(tmpZip);

The recovery test also creates a plaintext copy of the complete configuration:

js
if (!existsSync(OC_JSON)) {
  console.error(`ERROR: openclaw.json not found at ${OC_JSON}`);
  process.exit(1);
}

copyFileSync(OC_JSON, RECOVERY_FILE);
const config = getConfig();

Generic state files are written without an explicit mode:

js
export function writeJson(filepath, data) {
  mkdirSync(dirname(filepath), { recursive: true });
  writeFileSync(filepath, JSON.stringify(data, null, 2) + '\n');
}

Technical Analysis

The snapshot process archives the complete openclaw.json, and the recovery test stores another plaintext copy as openclaw.recovery. The recovery-test implementation demonstrates that the configuration may contain gateway.auth.token.

Neither the JavaScript implementation nor the setup process shown in the audit explicitly enforces mode 0700 on rollback directories or mode 0600 on snapshots, recovery files, manifests, watchdog state, and logs. Effective permissions therefore depend on the process umask and inherited permissions.

On a system with a permissive umask or shared group access, another local principal may be able to read these files. Excluding auth-profiles.json does not protect credentials embedded directly in openclaw.json.

...[truncated 1164 chars]

Remediation
View remediation

Remediation Suggestions

  • Create ~/.openclaw/rollback, all target directories, and temporary staging directories with mode 0700.
  • Create archives, manifests, logs, watchdog state, rollback configuration, and openclaw.recovery with mode 0600.
  • Apply chmodSync after copyFileSync, because copied permissions and umask behavior can vary.
  • Set a restrictive process umask such as process.umask(0o077) at script startup.
  • During installation, audit and repair permissions on existing rollback files.
  • Consider removing secrets from openclaw.json and referencing a protected credential store instead.
  • Consider authenticated encryption for snapshots when they must contain credentials.
  • Delete or securely retain openclaw.recovery after testing according to an explicit retention policy.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/utils.mjs:346
Finding

Mutable Snapshot Archives Are Extracted Over the Filesystem Root Without Integrity or Entry Validation

Content
View full analysis

Vulnerability Details

File Location: scripts/utils.mjs:346-353; scripts/restore.mjs:44-54
Vulnerability Type: Unsafe archive extraction and insufficient snapshot integrity validation
Risk Level: High

Vulnerable Code

js
/** Extract a tar.gz into /, overwriting. Returns exit code (0 = success). */
export function extractArchive(zipPath) {
  try {
    execSync(`tar -xzf "${zipPath}" -C /`, { stdio: 'ignore' });
    return 0;
  } catch (e) {
    return e.status || 1;
  }
}

The automatic config restore uses the same extraction model:

js
// Restore files — unzip with full path overwrite to /
let unzipExit = 0;
try {
  execSync(`tar -xzf "${zipPath}" -C /`, { stdio: 'ignore' });
} catch (e) {
  unzipExit = e.status || 1;
  appendLog(RESTORE_LOG, `RESTORE WARNING — unzip exit code: ${unzipExit}`);
}

Technical Analysis

Snapshot files are extracted directly with tar -C /, allowing archive entries to overwrite files accessible from the filesystem root. Before extraction, the implementation does not:

  • Verify a cryptographic digest or signature.
  • Verify archive ownership and permissions.
  • Enumerate and validate archive entries.
  • Reject absolute paths or parent-directory traversal.
  • Reject symbolic links or hard links.
  • Constrain entries to the configuration, skills, or selected project roots.
  • Stage extraction in an isolated directory.
  • Validate manifest-provided snapshot filenames against a fixed pattern.

The archives are intended to preserve filesystem-relative paths, so broad overwrite behavior is part of the design. However, this means a replaced or crafted snapshot can attempt to restore unrelated files. Actual writes remain limited by the operating-system privileges of the restore process.

Additionally, zipPath is interpolated into a shell command. For config restoration, part of that path can originate from the mutable manifest thro ...[truncated 1719 chars]

Remediation
View remediation

Remediation Suggestions

  • Validate snapshot filenames against a fixed allowlist or the strict pattern ^snapshot-[1-3]\.tar\.gz$.
  • Do not interpolate archive paths into a shell. Use spawnSync('tar', ['-xzf', zipPath, '-C', destination], { shell: false }).
  • Generate and store a SHA-256 digest for every snapshot at creation time and verify it before restoration.
  • For stronger protection against local tampering, authenticate snapshot metadata with a key stored outside the rollback directory.
  • List archive entries before extraction and reject absolute paths, .. components, device files, symbolic links, hard links, and entries outside explicitly approved roots.
  • Extract into a new mode-0700 temporary directory first.
  • Copy only allowlisted files from staging to their intended destinations using filesystem APIs.
  • For config snapshots, permit only the configured openclaw.json and documented workspace identity files.
  • For skills and projects, verify that each restored destination remains within its configured canonical root after resolving paths.
  • Abort restoration on any extraction error; do not disarm the watchdog or restart the gateway after a failed restore.
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (33)

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

md
- `memory/`
- `auth-profiles.json`
- `~/.openclaw/` root (already covered by config snapshots)
- All working content, repositories, large data files, .env

---

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
90% 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 · references/SETUP.md (reported line 344)May include surrounding context.

md
1. Back up existing snapshots:
   `cp -r ~/.openclaw/rollback/ /tmp/openclaw-rollback-backup/`
   (this preserves config, skills, and projects histories)
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.

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 · references/SETUP.md (reported line 344)May include surrounding context.

md
1. Back up existing snapshots:
   `cp -r ~/.openclaw/rollback/ /tmp/openclaw-rollback-backup/`
   (this preserves config, skills, and projects histories)
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.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
90% 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 · references/SETUP.md (reported line 344)May include surrounding context.

md
1. Back up existing snapshots:
   `cp -r ~/.openclaw/rollback/ /tmp/openclaw-rollback-backup/`
   (this preserves config, skills, and projects histories)
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.

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/projects-snapshot.mjs (reported line 64)May include surrounding context.

js
// .openclaw/workspace.state.json — single specific file under a hidden subdir
// comms/ — tree structure only

const EXCLUDE_IN_SUBDIR = ['node_modules', 'memory', '.git', '.env']; // extra-defensive

/**
 * Build a per-project staged archive.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script performs a full archive extraction to '/' which can overwrite existing system files, and the header explicitly states it must run with zero user interaction. While comments describe the action for developers, there is no user-facing confirmation or disclosure in the script before this destructive operation.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The extractArchive helper unpacks a tarball directly into '/' using tar -xzf, which can overwrite arbitrary files represented in the archive. In this skill, archives are created from absolute OpenClaw-related paths and later restored by a recovery feature, so the overwrite behavior is intentional, but it is still dangerous because a malformed, tampered, or path-traversing archive could modify system files outside the intended scope with no validation or safety checks in this function.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill directs the agent to run numerous local commands and scripts, but it declares no explicit tool scope or allowed-tools boundary. In practice this means a broad operational skill capable of filesystem inspection, process probing, and script execution can be invoked without a clear least-privilege contract, increasing the chance of unintended command execution or misuse.

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

md
and projects snapshot &recovery for OpenClaw. Use this skill whenever the user 
  wants to take a backup, restore a backup, set a dead-man's-switch recovery timer 
  for config changes, or test the recovery pipeline. Trigger phrases include: "set
  emergency recovery", "create snapshot", "take a backup before changes", "set
  a backout timer", "restore snapshot", "accept changes", "test emergency
  recovery", "run recovery test", "snapshot all skills", "snapshot global
  skills", "snapshot <agent> skills", "list skills snapshots", "restore all

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The trigger conditions are very broad and include many natural-language variants around recovery, rollback, testing, and backup behavior. That raises the risk of accidental activation of a highly privileged, destructive skill in contexts where the user did not explicitly request snapshotting, restoration, timer arming, or gateway restart behavior.

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

• "extend recovery XX minutes" — add more time to the timer • "list snapshots" — show all saved config snapshots • "restore snapshot 2" — manually restore snapshot 2 or 3 • "create snapshot" — save current state as new snapshot [1]

text

---

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

md
### "restore snapshot [1|2|3]"
Manually restore a specific config 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>`

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skills restore commands can overwrite global or agent skill directories, yet the skill text does not require an explicit confirmation prompt before restoration. Because skills influence future agent behavior, restoring them without a hard confirmation can silently replace trusted logic, reintroduce vulnerable code, or disrupt system behavior across agents.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The project restore commands can overwrite project manifests, tool scripts, skills, and state files, but no explicit user confirmation is required. This creates a direct path to destructive rollback of project configuration and local tooling, potentially breaking environments or reintroducing unsafe project-level code and MCP settings.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The document instructs users to extract tar.gz archives containing absolute paths directly to '/'. Even in a recovery context, this is a destructive overwrite operation that can replace configuration files without an explicit warning about replacement risk, archive trust, or the need to inspect contents first. If a snapshot is stale, corrupted, or tampered with, the restore can clobber live configuration or write to unintended locations.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The restart examples include disruptive actions such as restarting services and bringing docker compose stacks down and back up, but they are presented without an explicit caution about service interruption. In an emergency guide this may be operationally necessary, yet omitting a warning increases the chance of accidental downtime or use in the wrong environment.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

The watchdog disarm section tells users to kill processes by pattern and directly edit a state file, but it does not explicitly warn that this can terminate the wrong process or leave recovery state inconsistent if the file is malformed or unexpected. In a broken-system recovery scenario this is understandable, but the lack of caution and validation makes accidental disruption more likely.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · references/SETUP.md (reported line 33)May include surrounding context.

md
or `gzip` are missing (rare, but possible 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`

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · scripts/detect-restart-command.mjs (reported line 54)May include surrounding context.

js
or `gzip` are missing (rare, but possible 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`

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · scripts/detect-restart-command.mjs (reported line 71)May include surrounding context.

js
or `gzip` are missing (rare, but possible 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`

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
80% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · references/SETUP.md (reported line 40)May include surrounding context.

md
---

## Step 1 — Detect the Restart Command (do NOT ask the user)

The restart command is the most critical piece of setup — a wrong value
means auto-recovery can't actually recover. **Detect it. Don't ask the user

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
80% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · references/SETUP.md (reported line 43)May include surrounding context.

md
## Step 1 — Detect the Restart Command (do NOT ask the user)

The restart command is the most critical piece of setup — a wrong value
means auto-recovery can't actually recover. **Detect it. Don't ask the user
to pick from a list.** Users often don't know which install method is in
use on their own machine, and guessing wrong silently breaks the
dead-man's-switch.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · references/SETUP.md (reported line 91)May include surrounding context.

text

If `active`, the restart command is:
`sudo systemctl restart openclaw-gateway`

**Probe 2 — Docker Compose** *(container host)*

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The document says the restart command must be detected and confirmed because using the wrong command can silently break or misfire recovery, but the sample config-writing step hardcodes kill -USR1 1. If copied as written, the recovery system may signal PID 1 on expiry, which can restart or disrupt the container/init process instead of OpenClaw, causing failed recovery or service interruption.

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 · references/SETUP.md (reported line 165)May include surrounding context.


Step 2 — Create Directory Structure

bash
mkdir -p ~/.openclaw/rollback/snapshots

Static analysis

Detected: suspicious.dangerous_exec, suspicious.destructive_delete_command

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
hooks/watchdog-recovery/handler.ts:55

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/detect-restart-command.mjs:24

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/projects-snapshot.mjs:120

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/recovery-test.mjs:39

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/restore-if-armed.mjs:34

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/restore.mjs:50

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/snapshot.mjs:99

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/utils.mjs:299

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/watchdog-clear.mjs:32

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/watchdog-set.mjs:46

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/watchdog-timer.mjs:38

Documentation contains a destructive delete command without an explicit confirmation gate.

Warn
Code
suspicious.destructive_delete_command
Location
references/SETUP.md:344