Back to skill

Security audit

Openclaw Migrate

Security checks for vulnerabilities and agentic risk

Overview

This migration skill is coherent, but it copies secrets and scheduled jobs to another host with broad defaults and unsafe shell-command handling, so it needs careful review before installation.

Install only if you fully trust the destination host and are prepared for it to receive copied OpenClaw memory, configuration, API tokens, and scheduled jobs. Review and rotate sensitive tokens where appropriate, avoid hostile or untrusted SSH inputs, and prefer a version that uses safe argument handling, opt-in secret migration, and OpenClaw-specific cron migration instead of replacing the whole crontab.

Vulnerability Patterns
  • System PersistenceInstalls backdoors, hooks, services, or scheduled tasks that survive the run
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (4)

T06 · System Persistence

Error
Location
main.js:254
Finding

Automatic Remote Crontab Replacement Creates Persistent Execution

Content
View full analysis
/dev/null || echo ""'); const crons = result.stdout; if (crons.trim()) { // Save to remote const cmd = `ssh ${user}@${host} "echo '${crons.replace(/'/g, "'\\''")}' | crontab -"`; await execCmd(cmd); log('Cron jobs synced', 'green'); } else { log('No cron jobs to sync', 'gray'); } ``` ### Technical Analysis The migration reads the invoking user's entire local crontab and pipes it to `crontab -` on the target. This is a persistence mechanism because every transferred entry can continue executing after the migration process terminates and across future login sessions or reboots. The operation is performed automatically after the general migration confirmation. Users are not shown the cron entries, asked for separate consent, or allowed to select only OpenClaw-related jobs. In addition, `crontab -` replaces the target user's complete existing crontab rather than safely merging OpenClaw-specific entries. The cron content is also embedded in a shell command. Replacing single quotes alone is not sufficient protection in the surrounding nested shell context. Shell substitutions and other metacharacters in cron data may be interpreted while constructing or executing the SSH command. Although cron migration is disclosed in `README.md` and `SKILL.md`, transferring every user job exceeds the minimum scope necessary to migrate OpenClaw. Only explicitly identified OpenClaw jobs should be considered. ### Attack Path 1. An attacker, compromised application, or untrusted installer places a malicious entry in the source user's crontab. 2. The user starts the ...[truncated 970 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
main.js:81
Finding

Shell Command Injection Through User-Controlled SSH Parameters

Content
View full analysis
{ const sshCmd = `ssh ${options.key ? `-i ${options.key}` : ''} ${user}@${host} "${cmd}"`; exec(sshCmd, { timeout: options.timeout || 60000 }, (error, stdout, stderr) => { ``` ```js // Ensure remote directory exists const remoteDir = path.dirname(file.remote).replace('~', '/home/' + user); await sshExec(host, user, `mkdir -p "${remoteDir}"`, { key, ignoreError: true }); // SCP file const scpCmd = `scp ${key ? `-i ${key}` : ''} -r "${file.local}" ${user}@${host}:"${file.remote}"`; await execCmd(scpCmd, { timeout: 60000 }); ``` ```js // Get target host info config.host = await prompt('New host IP/hostname: '); config.user = await prompt('SSH user (default: crix): ') || 'crix'; config.key = await prompt('SSH key path (optional, press Enter for default): ') || ''; ``` ### Technical Analysis The target hostname, SSH username, and key path originate from interactive input and are saved to `config.json`. These values are subsequently concatenated into command strings passed to `child_process.exec()`. `exec()` invokes a shell, so metacharacters such as command separators, command substitutions, redirects, and quoting characters are interpreted as shell syntax. No strict validation or reliable shell escaping is applied to `host`, `user`, or `key`. The same unsafe construction is used for SSH and SCP. Consequently, merely testing a configured connection can trigger a malicious value; a full migration is not required. The presence of an SSH key path in `README.md` is not itself unsafe, and the implementation does not write to the private key. The vulnerability is that the path is treated as executable shell text instead of an ...[truncated 1003 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
main.js:228
Finding

API Tokens Are Unsafely Embedded in Shell Commands and Plaintext Profile Files

Content
View full analysis
`export ${k}="${v}"`).join('\n'); const profileLine = `\n# OpenClaw Migrated ENV\n${envLines}\n`; for (const profile of ['.bashrc', '.profile', '.zshrc']) { try { const checkCmd = `ssh ${user}@${host} "grep -q '# OpenClaw Migrated' ~/.${profile} 2>/dev/null || echo '${profileLine}' >> ~/.${profile}"`; await execCmd(checkCmd); } catch (e) {} } ``` ### Technical Analysis Sensitive values, including Home Assistant, GitHub, Brave, and Google credentials, are read from the process environment. They are inserted directly into generated shell source and then embedded in an SSH command passed to `exec()`. The values are not encoded or escaped for either of the nested shell contexts. A value containing command substitution, quotes, backticks, newlines, or other shell syntax can alter local or remote command execution. It is not sufficient that the generated export statement uses double quotes because that still permits command substitution when the profile is sourced. The generated command can expose secrets to process inspection and diagnostic tooling. The credentials are also writt ...[truncated 1680 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
main.js:276
Finding

Unpinned Global Installation of OpenClaw Introduces Supply-Chain Risk

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

Credential Access

High
Category
Privilege Escalation
Confidence
90% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · README.md (reported line 51)May include surrounding context.

$ openclaw-migrate setup New host IP/hostname: 192.168.1.50 SSH user: crix SSH key path: ~/.ssh/id_rsa

text

## Usage

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The tool explicitly collects and migrates multiple sensitive environment variables, including unrelated third-party secrets such as GITHUB_TOKEN, BRAVE_API_KEY, and GOOGLE credentials, to another host. For a migration utility, bulk secret exfiltration to a remote machine materially increases exposure, especially because these secrets may grant access beyond OpenClaw itself and are transferred without scope limitation or per-secret confirmation.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

Sensitive environment variables are selected for transfer and later written to remote shell startup files without a dedicated warning or consent step. Because these values include tokens and service account material, silent migration can cause users to disclose credentials to a host they did not intend to fully trust.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The code copies the user's entire local crontab to the remote host, which is outside the narrow scope of migrating OpenClaw. This can recreate unrelated scheduled tasks, propagate persistence mechanisms, overwrite the destination crontab, and unintentionally execute privileged or security-sensitive jobs on another system.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The skill is presented as a one-command SSH migration that auto-installs software, syncs configuration, and copies cron jobs to another machine. These actions can materially change the target system and scheduled tasks, but the documentation does not warn users about system integrity impact or recommend reviewing what will be modified before execution.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The markdown explicitly states that environment variables such as HA_TOKEN, GITHUB_TOKEN, and API keys will be synced to another host. This is a privacy- and security-sensitive behavior, but the README does not include a warning about credential transfer, trust requirements for the target host, or the risk of copying secrets to a new system.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill explicitly states it migrates OpenClaw config, skills, memory, and tokens to another host, but it does not prominently warn users that this operation transfers sensitive credentials and private agent state over SSH to a potentially different trust boundary. Users could run the migration without appreciating that API tokens, Home Assistant secrets, and other sensitive data will be replicated onto the destination system, increasing the risk of credential exposure or compromise if the target host is untrusted or misconfigured.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The migration flow and system data sections indicate that cron jobs and gateway configuration are copied and that the gateway is started on the new host, yet the documentation does not clearly warn that this may activate automated tasks and network-facing services on the destination. This can unexpectedly duplicate scheduled execution, expose services, or cause conflicting automation behavior if the old and new hosts run concurrently.

Content

No source excerpt is available for this finding.

File System Enumeration

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code scans file system directories looking for sensitive files. This could be reconnaissance for credential theft.

Content

Scanner excerpt · main.js (reported line 134)May include surrounding context.

js
// Check openclaw workspace
  const workspacePath = path.join(process.env.HOME || '/home/crix', '.openclaw');
  if (fs.existsSync(workspacePath)) {
    // Walk directory
    const walk = (dir, prefix = '') => {
      const items = fs.readdirSync(dir);
      for (const item of items) {

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The cron synchronization step occurs automatically once migration is confirmed, but there is no explicit warning that scheduled tasks will be created or overwrite the remote crontab. This can surprise users and cause unintended execution of commands on the new host, including jobs unrelated to OpenClaw.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
90% confidence
Finding

Reading the local crontab and reinstalling it on a remote host creates persistence on the destination system and can carry over automated execution mechanisms unrelated to this application. In the context of an agent skill, this is more dangerous because it extends behavior across hosts and may perpetuate scheduled execution without focused user understanding.

Content

Scanner excerpt · main.js (reported line 257)May include surrounding context.

js
log('Syncing cron jobs...', 'cyan');
  
  try {
    const result = await execCmd('crontab -l 2>/dev/null || echo ""');
    const crons = result.stdout;
    
    if (crons.trim()) {

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
main.js:70