Back to skill

Security audit

OpenClaw Updater

Security checks for vulnerabilities and agentic risk

Overview

This OpenClaw updater is mostly coherent, but it needs review because its maintenance scripts make broad local changes and contain unsafe handling of secrets, temporary state, and global package rollback.

Install only if you are comfortable reviewing and hardening the shell scripts first. At minimum, avoid running rollback from untrusted /tmp state, do not source the Telegram env file as shell code, store update state under a private user-owned directory, validate npm rollback versions, and use a narrowly scoped Telegram bot token.

Vulnerability Patterns
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (5)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/update.sh:50
Finding
Arbitrary Shell Code Execution Through Notification Configuration<![CDATA[ ## Vulnerability Details **File Location**: `scripts/update.sh`, lines 50-52 **Vulnerability Type**: Executable configuration file / shell code injection **Risk Level**: High ### Vulnerable Code ```bash ENV_FILE="${OPENCLAW_DIR}/.telegram-notify.env" if [ -f "$ENV_FILE" ]; then set -a; source "$ENV_FILE"; set +a fi ``` ### Technical Analysis The notification configuration is documented as a key-value environment file, but the script loads it with Bash's `source` builtin. `source` does not parse data-only environment assignments; it interprets the entire file as shell code. Consequently, command substitutions, functions, redirections, pipelines, and arbitrary commands placed in `.telegram-notify.env` execute with the privileges of the user running `update.sh`. Checking only that the path is a regular file does not verify ownership, permissions, or content safety. For example, a malicious configuration could contain: ```bash TELEGRAM_BOT_TOKEN="$(malicious-command)" TELEGRAM_CHAT_ID="123" ``` The command would execute immediately while the file is sourced. ### Attack Path 1. An attacker gains the ability to create or modify `$OPENCLAW_DIR/.telegram-notify.env`, such as through another compromised process, an insecure restore, or overly permissive file permissions. 2. The attacker inserts shell commands or command substitution syntax into the file. 3. The victim runs `bash scripts/update.sh`, including with `--dry-run` or `--test-notify`. 4. Bash sources the file before processing the requested operation. 5. The injected command executes as the victim user. ### Impact Assessment Successful exploitation provides arbitrary command execution with the privileges of the user invoking the updater. The attacker could read or modify user-accessible files, steal OpenClaw or Telegram credentials, alter workspaces, tamper with update state, or establish user-level persistence. This code does not independently elevate privileges beyond those of the invo ...[truncated 14 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Do not use `source` for a data-only configuration file. - Parse only an explicit allowlist of keys, such as `TELEGRAM_BOT_TOKEN` and `TELEGRAM_CHAT_ID`, without shell evaluation. - Reject command substitutions, unexpected keys, malformed lines, and duplicate assignments. - Verify that the file is a regular file owned by the current user and is not group- or world-writable. - Require restrictive permissions such as mode `0600`. - Prefer a structured format such as JSON and parse it with a non-executing parser. A safe implementation should read values as literal data and never evaluate the file as Bash syntax. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/find-workspaces.sh:7
Finding
JavaScript Code Injection Through OPENCLAW_CONFIG Path<![CDATA[ ## Vulnerability Details **File Location**: `scripts/find-workspaces.sh`, lines 7-14 **Vulnerability Type**: JavaScript source injection **Risk Level**: Medium ### Vulnerable Code ```bash CONFIG="${OPENCLAW_CONFIG:-$HOME/.openclaw/openclaw.json}" if [ ! -f "$CONFIG" ]; then echo "❌ Config not found: $CONFIG" >&2 exit 1 fi # Extract workspace paths from config using node node -e " const c = require('$CONFIG'); ``` ### Technical Analysis The environment-controlled `CONFIG` value is interpolated directly into source code passed to `node -e`. Shell quoting does not make the value safe inside the generated JavaScript program. A path containing a single quote followed by valid JavaScript can terminate the string literal used by `require(...)` and inject additional statements. The preliminary `-f` check only requires that a file exist at the crafted path; it does not prevent source-code injection. The issue is distinct from normal JSON parsing because the path itself becomes part of executable JavaScript source before Node.js loads the configuration. ### Attack Path 1. An attacker controls the `OPENCLAW_CONFIG` environment variable or influences the environment used to invoke the script. 2. The attacker creates an existing filename whose path contains characters that escape the JavaScript string and append JavaScript statements. 3. The victim runs `find-workspaces.sh` directly or indirectly through `pre-update.sh` or `update.sh`. 4. The crafted path is inserted into the `node -e` program. 5. Node.js evaluates the injected JavaScript with the victim user's privileges. ### Impact Assessment Successful exploitation permits arbitrary JavaScript and operating-system command execution as the invoking user through Node.js APIs such as `child_process`. The attacker could access user files, OpenClaw configuration, workspace contents, and credentials available to that user. Exploitation requires control over the environment variable and the ability to c ...[truncated 31 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Pass the configuration path as a positional argument rather than embedding it in JavaScript source: ```bash node - "$CONFIG" <<'NODE' const fs = require('fs'); const configPath = process.argv[2]; const c = JSON.parse(fs.readFileSync(configPath, 'utf8')); /* Process c without evaluating configPath or configuration contents. */ NODE ``` Additionally: - Parse the configuration with `JSON.parse` rather than `require`. - Validate that the resolved path points to an expected user-owned configuration location. - Reject non-regular files and symbolic links where they are unnecessary. - Ensure failures are reported rather than suppressing all Node.js errors. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/pre-update.sh:34
Finding
Predictable Shared Temporary Files Permit Disclosure, Tampering, and File Overwrite<![CDATA[ ## Vulnerability Details **File Location**: `scripts/pre-update.sh`, lines 34-49 **Vulnerability Type**: Insecure temporary-file handling **Risk Level**: High ### Vulnerable Code ```bash # 2. Backup openclaw.json if [ -f "$OPENCLAW_DIR/openclaw.json" ]; then cp "$OPENCLAW_DIR/openclaw.json" /tmp/openclaw.json.bak echo "✅ Config backed up to /tmp/openclaw.json.bak" fi # 3. Run backup script if provided if [ -n "$BACKUP_SCRIPT" ] && [ -x "$BACKUP_SCRIPT" ]; then echo "📦 Running backup script..." "$BACKUP_SCRIPT" fi # 4. Record current version for rollback VERSION=$(openclaw --version 2>/dev/null || echo "unknown") echo "$VERSION" > /tmp/openclaw-prev-version.txt echo "✅ Current version: $VERSION (saved to /tmp/openclaw-prev-version.txt)" ``` The files are later trusted by `scripts/rollback.sh`: ```bash if [ -f /tmp/openclaw-prev-version.txt ]; then PREV_VERSION=$(cat /tmp/openclaw-prev-version.txt) fi if [ -f /tmp/openclaw.json.bak ]; then read -p "Restore openclaw.json from backup? [y/N] " yn if [[ "$yn" =~ ^[Yy]$ ]]; then cp /tmp/openclaw.json.bak "$OPENCLAW_DIR/openclaw.json" fi fi ``` ### Technical Analysis The scripts store sensitive and security-relevant state under fixed, globally predictable names in `/tmp`. They do not use exclusive creation, a private temporary directory, restrictive permissions, ownership validation, or symbolic-link protections. `openclaw.json` may contain sensitive service configuration or credentials. Its resulting accessibility depends on the user's umask and existing destination state. An attacker with local access to the shared temporary directory may race file creation, replace artifacts between update and rollback, or pre-create symbolic links. The shell redirection used for the version file follows symbolic links, while `cp` may overwrite a pre-existing destination target. The rollback script subsequently treats the contents of these files as trusted backup material. ### Attack Path 1 ...[truncated 1118 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Set a restrictive umask before creating state: ```bash umask 077 ``` - Store rollback data under a private, user-owned state directory, for example `$OPENCLAW_DIR/update-state`, rather than in shared `/tmp`. - If temporary storage is required, create a private directory with `mktemp -d` and verify its owner and mode. - Create files atomically and exclusively; do not follow symbolic links. - Verify that existing files are regular files owned by the current user before reading them. - Write to a new protected file and atomically rename it into place. - Apply mode `0600` to configuration backups. - Remove stale state securely after rollback or when it is no longer needed. - Bind backup metadata to the intended installation and validate it before restoration. ]]>

T08 · Insecure Dependencies

Error
Location
scripts/rollback.sh:38
Finding
Untrusted Rollback Version Controls Global npm Package Installation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/rollback.sh`, lines 38-40 and 60-61 **Vulnerability Type**: Unvalidated dependency selection from tamperable state **Risk Level**: High ### Vulnerable Code ```bash if [ -f /tmp/openclaw-prev-version.txt ]; then PREV_VERSION=$(cat /tmp/openclaw-prev-version.txt) echo "📌 Previous version: $PREV_VERSION" else echo "❌ No previous version recorded. Specify manually:" echo " npm install -g openclaw@<version>" exit 1 fi ``` ```bash # 3. Rollback package echo "⏪ Rolling back to openclaw@$PREV_VERSION..." npm install -g "openclaw@$PREV_VERSION" ``` ### Technical Analysis The rollback version is read from a predictable, mutable file in shared temporary storage and used directly to construct an npm package specification. Shell quoting prevents shell word splitting and direct shell metacharacter execution, but it does not prove that the value is an expected OpenClaw semantic version. npm package installation is a code-execution boundary because installed packages can define lifecycle scripts. A tampered package specification can affect npm resolution and cause installation of unintended package content or an unsafe version. The use of `-g` also modifies the user's global npm environment and may affect system-wide locations depending on npm configuration and execution privileges. ### Attack Path 1. A local attacker creates or modifies `/tmp/openclaw-prev-version.txt`. 2. The attacker places an npm-compatible, attacker-influenced, or otherwise unsafe package version/specification in the file. 3. The victim executes `rollback.sh` and approves the rollback, or executes it with `--confirm`. 4. The script passes the unvalidated value to `npm install -g`. 5. npm resolves and installs the selected content. 6. Any applicable package lifecycle scripts execute with the privileges of the victim running rollback. ### Impact Assessment Successful exploitation may install unintended code globally and exe ...[truncated 332 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Store the previous version in a private, user-owned state directory rather than `/tmp`. - Verify file ownership, permissions, type, and installation identity before consuming rollback state. - Require the value to match a strict version allowlist, such as the exact semantic-version syntax emitted by the installed OpenClaw release. - Reject tags, URLs, file paths, Git references, whitespace, control characters, and other npm specification forms. - Record and verify package integrity information where supported. - Use `npm view` or equivalent trusted metadata checks to confirm that the exact expected version exists before installation. - Avoid privileged or global installation when a scoped user installation is sufficient. - Consider disabling lifecycle scripts where operationally compatible, while recognizing that this can affect packages that legitimately require them. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/update.sh:59
Finding
Telegram Bot Token Exposed in Process Command-Line Arguments<![CDATA[ ## Vulnerability Details **File Location**: `scripts/update.sh`, lines 59-67 **Vulnerability Type**: Credential exposure through process arguments **Risk Level**: Medium ### Vulnerable Code ```bash notify() { local msg="$1" local result result=$(curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \ -d chat_id="${TELEGRAM_CHAT_ID}" \ -d text="${msg}" \ -d parse_mode="Markdown" 2>&1) if echo "$result" | grep -q '"ok":true'; then ``` ### Technical Analysis The Telegram Bot API requires the token in the URL path. This implementation expands the token directly into curl's command-line arguments. While curl is running, the complete URL may be visible through process inspection interfaces or process-accounting systems to users and monitoring tools with sufficient local visibility. The script also prints the complete API response when notification fails. Although Telegram responses do not normally echo the bot token, error output should still be treated carefully because it may contain operational metadata. ### Attack Path 1. The victim invokes an update or notification test. 2. The script launches curl with the Telegram bot token embedded in its URL argument. 3. A local attacker or monitoring process with permission to inspect command lines observes the curl process during execution or retrieves it from process-accounting data. 4. The attacker extracts the bot token. 5. The attacker uses the token to make Telegram Bot API requests as the configured bot. The observation window may be short, but repeated updates, notification tests, or system instrumentation can make collection practical. ### Impact Assessment A stolen token permits unauthorized use of the affected Telegram bot within the capabilities granted by the Telegram Bot API and the bot's configured chat access. An attacker may send spoofed notifications, access bot-visible update data where permitted by the API, disrupt operational alerting, or ...[truncated 69 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Avoid exposing the token in ordinary process arguments where the operating environment provides a safer API-client mechanism. - Use a dedicated Telegram client or HTTP library that constructs the request within the process rather than passing the secret to a child process. - If curl must be used, evaluate a protected temporary curl configuration or other mechanism appropriate to the platform, ensuring the protected file is mode `0600`, securely created, and removed after use. - Restrict process inspection and process-accounting access on the host. - Run the updater under a dedicated, least-privileged account where feasible. - Rotate the Telegram bot token if command-line exposure may already have occurred. - Avoid logging full request URLs or enabling shell tracing around notification code. ]]>
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
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (15)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
This mismatch is more security-relevant because the skill introduces external Telegram API notification behavior and persistent secret loading that are not central to the declared updater purpose. Undeclared networked side effects and secret handling can surprise operators and expand the attack surface, especially when the skill is trusted as a local update helper.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
This mismatch is more security-relevant because the skill introduces external Telegram API notification behavior and persistent secret loading that are not central to the declared updater purpose. Undeclared networked side effects and secret handling can surprise operators and expand the attack surface, especially when the skill is trusted as a local update helper.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
This mismatch is more security-relevant because the skill introduces external Telegram API notification behavior and persistent secret loading that are not central to the declared updater purpose. Undeclared networked side effects and secret handling can surprise operators and expand the attack surface, especially when the skill is trusted as a local update helper.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill instructs the user to run multiple shell commands and scripts, but the manifest declares no explicit tool scope or allowed-tools. In an agent ecosystem, missing scope boundaries increases the chance the skill is invoked with broader shell access than intended, reducing enforceability of least privilege.

Session Persistence

Medium
Category
Rogue Agent
Content
The update script sends success/failure notifications via Telegram Bot API (bypasses OpenClaw gateway, so it works even if the update breaks the gateway).

Create `~/.openclaw/.telegram-notify.env`:

```
TELEGRAM_BOT_TOKEN=<your-bot-token>
Confidence
83% confidence
Finding
The skill instructs storing a long-lived Telegram bot token and chat ID in a persistent plaintext env file under ~/.openclaw. Persistent local secrets increase the risk of token theft via filesystem compromise, backup leakage, or accidental inclusion in logs or archives, and this skill also encourages external notifications that depend on that secret.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
```

```bash
chmod 600 ~/.openclaw/.telegram-notify.env
```

The bot token is the same one used by your OpenClaw Telegram channel. Chat ID can be found via `openclaw directory`.
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The restore instructions perform overwriting operations on ~/.openclaw without an explicit confirmation, dry-run, or warning about data loss. In an update/recovery workflow, this can cause accidental destruction of current configuration or workspace state, especially if the backup path or timestamp is wrong.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
echo "Usage: bash rollback.sh [OPTIONS]"
      echo ""
      echo "Options:"
      echo "  --confirm  Skip confirmation prompt and proceed"
      echo "  --help, -h Show this help"
      exit 0
      ;;
Confidence
85% 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.

Description-Behavior Mismatch

Medium
Confidence
93% confidence
Finding
The updater script includes Telegram notification behavior and credential handling that are not reflected in the stated skill scope, which broadens the trust boundary without clear disclosure. Hidden or under-documented outbound messaging in an updater is security-relevant because it can transmit operational metadata and conditions users to grant network access and secrets beyond what is needed for updates.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The script reads bot credentials from environment or a local env file and performs outbound network calls to Telegram, which is unrelated to the minimum mechanics needed to update software. This creates an unnecessary exfiltration-capable path from a privileged maintenance script and expands the consequences if the script, env file, or notification content are abused.

External Transmission

Medium
Category
Data Exfiltration
Content
notify() {
  local msg="$1"
  local result
  result=$(curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
    -d chat_id="${TELEGRAM_CHAT_ID}" \
    -d text="${msg}" \
    -d parse_mode="Markdown" 2>&1)
Confidence
94% confidence
Finding
Use of the Telegram endpoint confirms third-party external transmission from the updater script. Even though the content appears limited to status messages, the skill context makes this more dangerous because update scripts often run with elevated trust and access, so any unnecessary egress channel increases exposure and the potential for future abuse or unnoticed data leakage.

External Transmission

Medium
Category
Data Exfiltration
Content
notify() {
  local msg="$1"
  local result
  result=$(curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
    -d chat_id="${TELEGRAM_CHAT_ID}" \
    -d text="${msg}" \
    -d parse_mode="Markdown" 2>&1)
Confidence
94% confidence
Finding
Use of the Telegram endpoint confirms third-party external transmission from the updater script. Even though the content appears limited to status messages, the skill context makes this more dangerous because update scripts often run with elevated trust and access, so any unnecessary egress channel increases exposure and the potential for future abuse or unnoticed data leakage.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The notification text is hard-coded in Chinese, which forces a specific language for users receiving update messages. The file does not provide any opt-in, configuration, or justification for this locale restriction, so it appears to violate the language/locale policy requirement.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The failure alert text is written only in Chinese and does not offer an alternative language or user-controlled locale setting. Because this script emits user-facing operational messages, forcing a single language without opt-in is a policy concern.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
Both success and unchanged-version Telegram messages use Chinese-only text, and the script contains no mechanism for users to choose their preferred language. This creates a natural-language locale policy violation for user-facing output.

Static analysis

No suspicious patterns detected.