Back to skill

Security audit

safe-update

Security checks for vulnerabilities and agentic risk

Overview

This is a mostly coherent OpenClaw updater, but it can fetch, build, globally install, and restart code from an unverified existing Git remote, with some safety promises and documentation that do not match the script.

Review before installing. Only run this in a trusted OpenClaw checkout after verifying the upstream remote URL yourself, and prefer dry-run only after the dry-run bug is fixed. Avoid sudo/global install unless necessary, and be cautious with the documented git push --force advice.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T03 · Remote Payload Retrieval and Execution

Error

Unverified Existing Git Remote Can Supply Executed Code

scripts/update.sh:212

Vulnerability Details

File Location: scripts/update.sh, lines 212-224
Vulnerability Type: Unverified remote payload retrieval and execution
Risk Level: High

Vulnerable Code

bash
# Add upstream if needed
git remote add upstream https://github.com/openclaw/openclaw.git 2>/dev/null || true

# Fetch upstream
run_cmd git fetch upstream

# Checkout and merge
run_cmd git checkout "$BRANCH"
run_cmd git merge "upstream/$BRANCH"

# Build and install
run_cmd npm run build
run_cmd npm i -g .

Technical Analysis

The script attempts to add the expected OpenClaw repository as the upstream remote, but it suppresses errors and unconditionally continues. If an upstream remote already exists, the command fails and || true accepts the failure without verifying the existing remote URL.

The script then fetches and merges code from that potentially attacker-controlled remote. It subsequently runs npm run build and npm i -g .. npm build and installation lifecycle scripts can execute arbitrary commands with the privileges of the user running the updater. The global installation also allows the fetched package to replace or modify the globally available OpenClaw command.

Attack Path

  1. An attacker, compromised local process, or malicious repository setup changes the target repository's upstream URL to an attacker-controlled Git repository.
  2. The user invokes the update script and confirms the update.
  3. git remote add upstream ... fails because the remote already exists.
  4. The failure is silently ignored by 2>/dev/null || true.
  5. git fetch upstream retrieves attacker-controlled commits.
  6. git merge "upstream/$BRANCH" incorporates the malicious payload.
  7. npm run build or npm i -g . executes attacker-controlled npm lifecycle commands.
  8. The malicious package can replace the globally installed OpenClaw executable or perform other actions under the invoking u ...[truncated 516 chars]

Remediation

Remediation Suggestions

  • Retrieve the current URL using git remote get-url upstream before fetching.
  • Require the URL to exactly match an approved canonical URL, accounting only for explicitly supported HTTPS or SSH forms.
  • Abort with a clear security warning if the remote is missing or mismatched; do not silently ignore remote configuration errors.
  • If changing an existing remote is supported, display the old and new URLs and require explicit user confirmation before running git remote set-url.
  • Resolve the fetched branch to a commit and verify it against a trusted signed tag, signed commit, or administratively supplied commit hash before building it.
  • Review or suppress npm lifecycle scripts where feasible, and avoid elevated execution during build or installation.
  • Separate fetching, verification, building, and global installation into distinct confirmation stages.

A hardened remote check could follow this pattern:

bash
expected_url="https://github.com/openclaw/openclaw.git"

if git remote get-url upstream >/dev/null 2>&1; then
    actual_url="$(git remote get-url upstream)"
    if [ "$actual_url" != "$expected_url" ]; then
        log_error "Untrusted upstream remote: $actual_url"
        exit 1
    fi
else
    run_cmd git remote add upstream "$expected_url"
fi

T09 · Insecure Skill Coding Practices

Note

Dry-Run Mode Performs a Persistent Repository Modification

scripts/update.sh:212

Vulnerability Details

File Location: scripts/update.sh, lines 212-213
Vulnerability Type: Dry-run safety violation
Risk Level: Low

Vulnerable Code

bash
# Add upstream if needed
git remote add upstream https://github.com/openclaw/openclaw.git 2>/dev/null || true

The script separately assures users that dry-run mode makes no changes:

bash
if [ "$DRY_RUN" = "true" ]; then
    log_warn "DRY-RUN MODE: No actual changes will be made"
    echo ""
fi

Technical Analysis

Most update operations are passed through run_cmd, which only prints commands when DRY_RUN=true. The git remote add upstream command bypasses that wrapper and executes unconditionally.

Consequently, running the script with --dry-run in a repository without an upstream remote writes a new remote entry into .git/config. This contradicts the documented and runtime guarantee that no actual changes will be made.

Attack Path

  1. A user selects a Git repository that does not have an upstream remote.
  2. The user invokes scripts/update.sh --dry-run, expecting a non-mutating preview.
  3. The script displays the message that no actual changes will be made.
  4. The unconditional git remote add upstream ... command executes.
  5. The repository's .git/config is persistently modified despite dry-run mode.

Impact Assessment

The direct impact is limited to unauthorized modification of the selected repository's Git configuration under the invoking user's privileges. It does not by itself execute a remote payload during dry-run mode, because subsequent fetch, merge, build, and installation commands use run_cmd. However, it violates the safety boundary promised by dry-run mode and may affect later Git workflows or automation that relies on remote names and configuration.

Remediation

Remediation Suggestions

Route the remote creation through the same dry-run-aware command wrapper used for the other mutating operations:

bash
if ! git remote get-url upstream >/dev/null 2>&1; then
    run_cmd git remote add upstream https://github.com/openclaw/openclaw.git
fi

Additionally:

  • Audit every command for filesystem, repository, package, and service side effects.
  • Ensure all mutating commands are guarded by run_cmd or an equivalent centralized dry-run mechanism.
  • Add an automated test that snapshots .git/config and relevant files before and after a dry run and fails if any state changes.
  • Avoid suppressing configuration errors with || true; distinguish an existing remote from genuine command failures.
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (11)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The code is broadly aligned with the declared purpose of updating OpenClaw from source, supporting custom directory/branch, building, installing, and restarting. However, there is a material description-behavior mismatch in one stated operation: the description says it supports rebasing, but the script actually performs git merge upstream/$BRANCH after git checkout, not a rebase. Additionally, the script performs undeclared backup of user config/auth files in ~/.openclaw, modifies git configuration by adding an upstream remote, and runs version/health/status checks. Those extra actions are related to the update workflow, but they are still undeclared capabilities affecting additional resources. Because the primary purpose matches but key implementation differs on rebasing and includes extra state-changing behavior, this should be flagged as a mismatch.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
## ⚠️ Important Warnings

- This script performs **git rebase** and **git push --force** - may lose local changes if not properly committed
- Uses **npm i -g .** for global installation - may require sudo
- Uses **systemctl --user restart** - will restart the OpenClaw service
- **Backup your config before running!** (see below)
Confidence
94% confidence
Finding

The skill explicitly references git push --force, a destructive parameter that can overwrite remote history and remove collaborators' commits if misused. In an automated or semi-automated update workflow, normalizing force-push behavior increases the chance of irreversible repository damage and can be abused to rewrite audit history.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
## Notes

- **Rebase may cause conflicts** - if conflicts occur, resolve manually and continue
- **Force push** - after rebase, if pushing to fork, use `git push --force`
- **Service reinstall** - will update version in systemd unit file
- **User confirms restart** - Gateway will not restart until you confirm
- **Backup first** - always backup before updating!
Confidence
95% confidence
Finding

The troubleshooting/notes section again encourages git push --force after a rebase, reinforcing a risky pattern for history-rewriting operations. In the context of a skill intended to automate updates, this guidance can lead users to overwrite remote branch history and mask or destroy prior states.

Vague Triggers

Medium
Confidence
93% confidence
Finding

The manifest uses broad trigger phrases like general update/sync/rebuild requests, which can cause the skill to activate in contexts where the user did not intend a full source update workflow. Because this skill performs repository mutation, global installation, and service operations, over-broad activation materially raises the risk of accidental execution.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
## ⚠️ Important Warnings

- This script performs **git rebase** and **git push --force** - may lose local changes if not properly committed
- Uses **npm i -g .** for global installation - may require sudo
- Uses **systemctl --user restart** - will restart the OpenClaw service
- **Backup your config before running!** (see below)
Confidence
91% confidence
Finding

The workflow performs a global package installation with npm i -g ., which may require elevated privileges. Running build/install steps with sudo or equivalent increases the blast radius of any malicious or compromised package scripts in the repository and can lead to full user or system compromise.

Intent-Code Divergence

Medium
Confidence
93% confidence
Finding

The skill states that execution must wait for user confirmation, but also advertises a script that automatically completes all steps. In a skill that performs rebases, global installs, and service changes, bypassing or undermining confirmation increases the chance of destructive actions being run without informed consent.

Session Persistence

Medium
Category
Rogue Agent
Content
# 2. Backup config files (good practice before update!)
echo "=== Backing up config files ==="
mkdir -p ~/.openclaw/backups
BACKUP_SUFFIX=$(date +%Y%m%d-%H%M%S)

# Backup main config
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.

Description-Behavior Mismatch

Medium
Confidence
88% confidence
Finding

The manifest describes updating from source by pulling, rebasing, building, installing, and restarting the service. However, the documented execution steps also run openclaw daemon install --force, which is a stronger operation than a restart because it reinstalls service configuration/system integration, not just restarts an existing service.

Session Persistence

Medium
Category
Rogue Agent
Content
log_info "Backing up config files..."
    
    local backup_dir="$HOME/.openclaw/backups"
    mkdir -p "$backup_dir"
    
    local backup_suffix=$(date +%Y%m%d-%H%M%S)
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.

Description-Behavior Mismatch

Medium
Confidence
89% confidence
Finding

The script goes beyond a local source update by performing a global npm install and restarting a user service, which changes system-wide behavior and immediately activates newly fetched code. In the context of an update skill, this increases risk because unreviewed upstream code is not only built but also installed and executed, reducing the user's chance to inspect or stage the change safely.

Intent-Code Divergence

Low
Confidence
81% confidence
Finding

The script presents a pre-run checklist telling the user to ensure they have already backed up configuration files, but the code later automatically performs those backups itself via backup_config. This is not just incomplete documentation: the user-facing intent suggests backup is a prerequisite external to the script, while the implementation handles it internally.

Static analysis

No suspicious patterns detected.