Back to skill

Security audit

Post-Upgrade Auto Repair

Security checks for vulnerabilities and agentic risk

Overview

This repair skill has a plausible purpose, but it installs persistent silent automation, changes OpenClaw configuration, and can send diagnostics using the user’s AI credentials without enough control.

Review carefully before installing. Back up BOOT.md and openclaw.json first, and install only if you accept automatic startup execution, automatic configuration changes, model-account usage, and possible diagnostic data transmission to the configured provider endpoint.

Vulnerability Patterns
  • System PersistenceInstalls backdoors, hooks, services, or scheduled tasks that survive the run
  • 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
Findings (4)

T06 · System Persistence

Error
Location
install.mjs:62
Finding
Persistent startup hook overwrites existing Agent boot instructions<![CDATA[ ## Vulnerability Details **File Location**: `install.mjs:62-89` **Vulnerability Type**: Persistent startup-hook installation and boot-policy replacement **Risk Level**: High ### Vulnerable Code ```js const bootPath = join(WORKSPACE_DIR, 'BOOT.md'); const bootContent = `...`; writeFileSync(bootPath, bootContent, 'utf8'); const hookResult = run('openclaw hooks enable boot-md'); ``` The omitted template content directs the Agent to compare OpenClaw versions, execute `skills/openclaw-repair-kit/check.mjs` after version changes, write the detected version to persistent storage, and complete the operation silently using `NO_REPLY`. ### Technical Analysis The installer unconditionally writes a new `BOOT.md` using `writeFileSync`. It does not check for an existing file, merge with existing instructions, create a backup, or request approval before replacing the boot policy. It then enables the `boot-md` hook. This causes instructions supplied by the Skill to survive the initial installation and affect later gateway sessions. The installed instructions can trigger `check.mjs`, which rewrites configuration and may contact an external AI endpoint. Although startup health checks are related to the declared repair functionality, replacing the entire boot instruction file and suppressing user-visible output exceed the minimum privileges required. A manual health-check command or an explicit, narrowly scoped opt-in hook would be sufficient. ### Attack Path 1. The user runs `node install.mjs`. 2. The installer overwrites `~/.openclaw/workspace/BOOT.md`. 3. The installer enables the `boot-md` hook. 4. On a later gateway startup, the Agent loads the new persistent boot instructions. 5. When a version change is detected, the Agent executes `check.mjs` without additional confirmation. 6. The check can modify `openclaw.json` and send diagnostic information to the configured AI endpoint. 7. Existing boot instructions are lost, and the activity is intentionally comp ...[truncated 501 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Do not modify `BOOT.md` during default installation. - Offer startup integration as a separate, explicit opt-in operation. - If integration is accepted, preserve existing content and append a clearly delimited section rather than replacing the file. - Display the exact proposed instructions and require confirmation before writing them. - Create a backup and restore it if hook activation fails. - Remove the `NO_REPLY` behavior so users can see when an automatic repair check runs. - Provide an uninstall command that disables the hook and removes only the section installed by this Skill. - Prefer a dedicated, documented OpenClaw lifecycle mechanism over modifying general Agent instruction files. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
check.mjs:167
Finding
Shell command injection through untrusted diagnostic output<![CDATA[ ## Vulnerability Details **File Location**: `check.mjs:167-193` **Vulnerability Type**: OS command injection **Risk Level**: Critical ### Vulnerable Code ```js const problemReport = `... ${issues.join('\n\n')} ... ${version.trim()} ... ${status.substring(0, 1200)} ... ${configPath} ...`; const result = execSync( `node "${CC_SCRIPT}" ${JSON.stringify(problemReport)}`, { encoding: 'utf8', timeout: 60000 } ); ``` ### Technical Analysis `problemReport` includes data derived from the output of OpenClaw commands, including version, status, memory, and doctor diagnostics. The resulting string is inserted into a shell command passed to `execSync`. `JSON.stringify()` serializes a JavaScript string as JSON; it does not safely escape data for a POSIX shell. The resulting argument is generally enclosed in double quotes, under which shell constructs such as command substitution remain active. For example, attacker-controlled diagnostic text containing `$(command)` or backtick command substitution may be executed by the shell before Node.js receives the argument. The use of `execSync` is unnecessary because the code only needs to start a known Node.js script with one argument. This unnecessarily exposes a shell interpreter to data that may be influenced by configuration, providers, channel names, plugin output, or other OpenClaw components. ### Attack Path 1. An attacker or compromised OpenClaw component causes malicious text to appear in output consumed by `check.mjs`. 2. The output contains a shell expression such as `$(malicious-command)`. 3. A health-check condition causes that output to be included in `issues`, `version`, or `status`. 4. `check.mjs` embeds the resulting `problemReport` into a command string. 5. `execSync` invokes the command through a shell. 6. The shell evaluates the command substitution before starting `run.mjs`. 7. The injected command executes with the privileges of the user running the health check. Automatic execution throug ...[truncated 564 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Eliminate shell command construction. - Invoke Node.js directly with an argument array: ```js import { execFileSync } from 'child_process'; const result = execFileSync( process.execPath, [CC_SCRIPT, problemReport], { encoding: 'utf8', timeout: 60000 } ); ``` - Prefer `spawnSync` or `execFileSync` with `shell: false`. - Apply strict size limits to every diagnostic section. - Treat all command output as untrusted, even if generated by a locally installed tool. - Add regression tests containing `$()`, backticks, quotes, newlines, semicolons, and shell metacharacters. - Consider passing the report through standard input rather than a command-line argument to reduce quoting risks and prevent diagnostic data from appearing in process listings. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
run.mjs:10
Finding
Provider credential and diagnostic data sent to an unrestricted configured endpoint<![CDATA[ ## Vulnerability Details **File Location**: `run.mjs:10-52` **Vulnerability Type**: Unsafe transmission of credentials and potentially sensitive diagnostics **Risk Level**: High ### Vulnerable Code ```js const configPath = join(homedir(), '.openclaw', 'openclaw.json'); let config; try { config = JSON.parse(readFileSync(configPath, 'utf8')); } catch (e) { process.exit(1); } const primaryModel = config?.agents?.defaults?.model?.primary || ''; const providerName = primaryModel.split('/')[0]; const modelId = primaryModel.split('/').slice(1).join('/'); const provider = config?.models?.providers?.[providerName]; const apiKey = provider.apiKey; const baseUrl = provider.baseUrl.replace(/\/$/, ''); const response = await fetch(`${baseUrl}/messages`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-api-key': apiKey, 'anthropic-version': '2023-06-01' }, body: JSON.stringify({ model: modelId, max_tokens: 8192, messages: [{ role: 'user', content: task }] }) }); ``` The task produced by `check.mjs:167-180` includes issue details, the OpenClaw version, up to 1,200 characters of status output, and the local path to `openclaw.json`. ### Technical Analysis The script reads an API credential from the user's primary OpenClaw configuration and sends it in the `x-api-key` header to `${baseUrl}/messages`. The `baseUrl` comes directly from configuration and is not validated for: - HTTPS transport; - an expected provider hostname; - loopback, private-network, or link-local destinations; - redirects to a different host; - compatibility with the expected Anthropic-style API. The code calculates `useAnthropicAPI` but does not use it to restrict the request. Consequently, any selected provider is contacted using the same credential-bearing request shape. Sending an API key to its legitimate provider is necessary for the manually documented AI feature. However, automatically sending diagnostics after a background ...[truncated 1376 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Require an `https:` URL and reject embedded credentials, unexpected ports, and malformed URLs. - Validate the hostname against the provider selected by the user or require explicit approval for custom endpoints. - Disable automatic redirects or verify that every redirect remains on an approved HTTPS origin. - Require interactive consent before sending an automatically generated diagnostic report. - Display the exact report and destination before transmission. - Redact home-directory paths, account identifiers, channel identifiers, tokens, URLs containing secrets, and unexpected diagnostic fields. - Keep diagnostic submissions disabled by default for background startup checks. - Use narrowly scoped or short-lived provider credentials where supported. - Honor the provider API type and reject incompatible providers instead of always sending an Anthropic-style credential-bearing request. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
check.mjs:23
Finding
Background health check destructively rewrites the primary OpenClaw configuration<![CDATA[ ## Vulnerability Details **File Location**: `check.mjs:23-67` **Vulnerability Type**: Unsafe and non-atomic security-sensitive configuration mutation **Risk Level**: Medium ### Vulnerable Code ```js function autoFixConfig() { const fixes = []; let config; try { config = JSON.parse(readFileSync(CONFIG_PATH, 'utf8')); } catch { return fixes; } let changed = false; const feishu = config?.channels?.feishu; if (feishu?.dmAllowlist && !feishu?.allowFrom) { config.channels.feishu.allowFrom = feishu.dmAllowlist; delete config.channels.feishu.dmAllowlist; changed = true; } const telegram = config?.channels?.telegram; if (telegram?.streamMode && !telegram?.streaming) { config.channels.telegram.streaming = telegram.streamMode; delete config.channels.telegram.streamMode; changed = true; } if (config?.agents?.defaults?.model?.image) { delete config.agents.defaults.model.image; changed = true; } if (feishu?.dmPolicy === 'auto') { config.channels.feishu.dmPolicy = 'allowlist'; changed = true; } if (changed) { writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), 'utf8'); } return fixes; } ``` ### Technical Analysis The health check automatically deletes and renames fields in the user's primary `openclaw.json`. The updated document is written directly over the original file without: - obtaining user confirmation; - creating a backup; - validating the complete result against the installed OpenClaw schema; - preserving original file permissions explicitly; - using an atomic temporary-file-and-rename procedure; - rolling back if subsequent health checks fail. The changes are related to the declared repair function, but automatic modification during a persistent startup workflow gives the script more authority than is necessary for diagnosis. Field-name assumptions may also be invalid for custom plugins, intermediate releases, or configurations where the old and ne ...[truncated 1104 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Make automatic repair opt-in and show a proposed diff before applying changes. - Create a timestamped backup with restrictive permissions before modification. - Validate the modified object using the schema for the installed OpenClaw version. - Write to a temporary file in the same directory, flush it, preserve secure permissions, and atomically rename it over the original. - Restore the backup if validation or subsequent health checks fail. - Avoid deleting source fields until the replacement has been validated. - Record every change in a visible audit log. - Provide a dry-run mode and a documented rollback command. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (15)

Description-Behavior Mismatch

High
Confidence
99% confidence
Finding
The stated purpose is an OpenClaw health-check and auto-repair tool, but the implementation is actually a generic prompt relay that forwards arbitrary user input to the configured LLM provider using the user's existing credentials. This mismatch is dangerous because it hides broad model-access capability behind a benign-sounding repair-tool description, increasing the chance users will authorize or run it without realizing it can exfiltrate prompts and consume their paid API access.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The skill explicitly states it will automatically check and repair issues after restart, but the documentation does not clearly disclose that this may modify OpenClaw configuration or runtime state. Silent or poorly disclosed automatic changes can lead users to authorize behavior they do not fully understand, increasing the risk of unintended configuration drift, service disruption, or unsafe repairs.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The script automatically rewrites the user's ~/.openclaw/openclaw.json in autoFixConfig() and persists changes with writeFileSync() without prompting, previewing diffs, or creating a backup. Even if the fixes are well-intentioned, silent mutation of security- and connectivity-related configuration can break service, weaken policy settings, or overwrite user intent, especially in an upgrade-repair tool that users may run with trust.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The script constructs a problemReport containing diagnostic output, version info, status output, issue details, and the local configuration file path, then forwards it to another script advertised as contacting Claude AI for analysis. This can disclose sensitive operational metadata or secrets embedded in status/error output without informed consent or redaction, and the skill context explicitly says unknown issues are sent to an AI, which increases the likelihood of external transmission.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
The installer modifies startup behavior by writing a BOOT.md workflow that automatically executes shell commands and a skill script on every gateway start after version changes. This exceeds a simple file-copy install and creates persistent command-executing automation, which is risky because future changes to the installed skill or environment can cause code to run without fresh user approval.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The script unconditionally overwrites BOOT.md with new startup instructions, changing global agent behavior without preserving existing content or clearly warning the user. This can silently remove prior safeguards or custom startup logic and cause unexpected automated execution in a sensitive control plane file.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The installer both enables the boot-md hook and configures silent automatic execution ('NO_REPLY') without a clear safety notice or user consent. This reduces transparency and establishes persistence, making it easier for unexpected or unsafe behavior to occur unnoticed on future starts.

Context-Inappropriate Capability

Medium
Confidence
96% confidence
Finding
The script exposes a general-purpose LLM invocation interface by accepting arbitrary command-line text and sending it directly to the configured provider. In the context of a supposed repair utility, that capability is unnecessary and expands the tool into a covert wrapper around the user's API account, enabling unauthorized usage, hidden data transfer, and abuse of provider billing.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The code silently reads API credentials from the user's local OpenClaw configuration file without any up-front disclosure or consent prompt. Even if the file access is local, this is risky because users invoking a repair skill would not reasonably expect their provider credentials to be harvested and reused by a generic script.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The script sends the user's task outbound and authenticates the request with the user's API key, yet gives no user-facing warning that data will leave the machine or that their account will be charged. In this skill context, that omission is more dangerous because the manifest frames the tool as a local repair utility, so users are less likely to anticipate remote transmission of potentially sensitive operational details.

Natural-Language Policy Violations

Low
Confidence
96% confidence
Finding
Natural-language policy checks apply to all file types. The file consistently forces a specific language for description and user instructions, and there is no indication that users can opt into another language or that the skill is intentionally limited to a Chinese-speaking audience for a documented reason.

Natural-Language Policy Violations

Low
Confidence
90% confidence
Finding
User-facing comments and console output consistently assume Chinese as the interaction language, and the repair prompt sent to CC is also hardcoded in Chinese. There is no indication that users may choose another language or locale, which can violate language-choice policy absent justification.

Natural-Language Policy Violations

Low
Confidence
88% confidence
Finding
The file's human-readable title and usage instructions are presented in Chinese only, and the script's console messages are likewise Chinese-only. This can constitute a language policy violation when a skill imposes a specific language without user opt-in or documented locale scoping.

Natural-Language Policy Violations

Low
Confidence
78% confidence
Finding
The embedded instruction '不需要回复用户,静默完成即可(NO_REPLY)' directs the system to hide the automated action from the user. This is a natural-language behavior directive that reduces transparency and can conflict with policies requiring user awareness of automated actions.

Natural-Language Policy Violations

Low
Confidence
90% confidence
Finding
All visible usage and error messages in the script are written in Chinese, and there is no option for the user to select another language. This can violate language or locale policy when no explicit opt-in or documented locale restriction is provided.