Back to skill

Security audit

Post Update Maintenance

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly honest about doing OpenClaw maintenance, but its high-impact config and plugin changes rely on under-hardened local execution and file-write paths.

Install only if you intentionally want an attended maintenance skill that can update OpenClaw plugins, rewrite openclaw.json, restart the gateway, and keep persistent backups/logs. Prefer dry-run first, verify post-update-awareness is from a trusted install location, and avoid running --apply in profile directories writable by other users.

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

T08 · Insecure Dependencies

Warning
Location
scripts/_lib.sh:53
Finding

Unverified External Skill Code Is Sourced and Executed

Content
View full analysis
/dev/null || continue local out if out=$(resolve_pua_scripts 2>/dev/null) && [ -n "$out" ]; then echo "$out" return 0 fi fi done ``` The resolved dependency is later executed in `scripts/detect-drift.sh`, lines 24–34: ```bash AWARENESS_SCRIPTS="$(pum_resolve_awareness)" GW="$(pum_current_gateway_version)" if [ -z "$GW" ]; then echo "BLOCKED no-gateway-version: openclaw -V returned nothing parseable" >&2 exit 2 fi # Invoke via bash because clawhub install does not preserve exec bits. bash "$AWARENESS_SCRIPTS/check-plugin-drift.sh" "$GW" "$PROFILE" ``` ### Technical Analysis The resolver searches several mutable user-level directories and sources the first readable `resolve.sh` it finds. In Bash, `source` does not merely parse function definitions: it executes every top-level command in the selected file in the current shell process. The implementation does not verify: - The installed dependency version, despite declaring `post-update-awareness >= 0.3.1`. - A cryptographic checksum or package signature. - File ownership or whether the file is group- or world-writable. - Whether the canonical path rema ...[truncated 1907 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/clean-stale-config.sh:108
Finding

Predictable Temporary File Allows Symlink-Based File Clobbering

Content
View full analysis
/dev/null 2>&1; then if ! jq --argjson keys "$TARGETS_JSON" \ '(.plugins.entries // {}) as $e | .plugins.entries = (reduce $keys[] as $k ($e; del(.[$k])))' \ "$CFG" > "$TMP"; then rm -f "$TMP" echo "BLOCKED jq-failed" >&2 exit 2 fi else if ! TARGETS_JSON="$TARGETS_JSON" python3 - "$CFG" "$TMP" <<'PY' import json, os, sys src, dst = sys.argv[1], sys.argv[2] targets = json.loads(os.environ["TARGETS_JSON"]) with open(src) as f: data = json.load(f) entries = data.get("plugins", {}).get("entries", {}) for k in targets: entries.pop(k, None) data.setdefault("plugins", {})["entries"] = entries with open(dst, "w") as f: json.dump(data, f, indent=2) f.write("\n") PY then rm -f "$TMP" echo "BLOCKED python-fallback-failed" >&2 exit 2 fi fi # Atomic move. mv "$TMP" "$CFG" ``` ### Technical Analysis The temporary pathname is constructed from the configuration filename and the process ID: ```bash TMP="$CFG.pum.tmp.$$" ``` Process IDs are observable or guessable, and the code does not create the file with exclusive semantics. Both output implementations follow symbolic links: - Shell redirection with `> "$TMP"` opens and truncates the existing symlink target. - Python’s `open(dst, "w")` similarly follows a pre-existing symlink. The subsequent `mv` makes replacement of `openclaw.json` atomic only after the temporary output has been generated. It does not protect against a symlink attack during temporary-file creation. No `mktemp`, `O_EXCL`, `O_NOFOLLOW`, regular-file check, ...[truncated 1425 chars]
Remediation
View remediation
&2 exit 2 } trap 'rm -f -- "$TMP"' EXIT HUP INT TERM ``` 2. Ensure that the generated pathname is a regular file and not a symbolic link before writing. 3. For stronger guarantees, open the file using exclusive creation and no-follow semantics such as `O_CREAT | O_EXCL | O_NOFOLLOW`. 4. Verify that the profile directory has trusted ownership and is not writable by untrusted users. 5. Preserve the intended owner and permission mode when replacing `openclaw.json`. 6. Use `mv -- "$TMP" "$CFG"` after successful generation and validation. 7. Clear the cleanup trap only after the replacement succeeds. 8. Where crash durability matters, flush the temporary file and containing directory before and after replacement. ]]>
Vulnerability Patterns
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (8)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The code only implements the stale-config cleanup portion of the declared description. It removes stale plugins.entries.* nodes from openclaw.json, supports dry-run by default, applies changes only with --apply, restarts the gateway, and performs rollback on unhealthy state. However, the declared purpose claims a broader post-update fixer that also syncs drifted externalized plugins and reuses post-update-awareness’s drift detector. None of that plugin-sync behavior appears here, and the only detector used is detect-stale-config.sh, not an evident post-update-awareness dependency. The health check is for gateway/runtime health, not channel health as described. Because the declared description presents a materially broader remediation capability than this code actually provides, this chunk is a mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description presents a remediation/maintenance skill with multiple corrective actions and safety gating for mutations. The supplied code chunk only wraps an existing drift-detection script from post-update-awareness and returns advisory output. While the dependency on post-update-awareness is consistent, the actual behavior is materially narrower and different in purpose: detection only, not fixing. That is a significant description-to-behavior mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The declared description presents a broader post-update fixer workflow with multiple remediation actions and guarded mutations. The supplied code only detects stale config warnings by scraping CLI output and emitting matching stale entry identifiers. Its behavior is advisory and read-only. While stale-config detection is related to one part of the description, the primary declared functionality includes several substantial capabilities not present in the code chunk, so the description does not accurately represent what this code actually does.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The declared description presents a remediation skill whose main function is to fix issues found by post-update-awareness after an OpenClaw update. In contrast, the supplied code is a narrow preflight guard: it checks prerequisites, blocks if the gateway is unhealthy, validates config access, creates a backup, and records a channel snapshot. Those actions are maintenance-safety/setup behavior, not the described repair actions. Some details may be supporting infrastructure for a larger skill, but taken as supplied, this chunk's primary behavior materially differs from the declared purpose.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The core plugin-sync behavior matches the description well: it requires the awareness component, detects drift, defaults to dry-run, applies plugin updates only with --apply, restarts the gateway, checks health, and restores config on unhealthy state. However, the declared description also claims it 'prints a patch for stale openclaw.json entries,' which this script never does; it only backs up and potentially restores config. Also, the description says mutations are gated behind '--apply or explicit user confirmation,' but the code itself has no interactive confirmation path—only the --apply flag enables mutation, while --yes is merely a signal to skip a caller-owned prompt placeholder. These are material description-to-behavior gaps, though there are no obvious unrelated or dangerous extra capabilities beyond the declared maintenance task.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description presents a remediation tool whose main purpose is to fix issues found after an OpenClaw update, including syncing plugins, restarting the gateway, and generating config patches, with guarded mutation behavior. The supplied code chunk does none of those things. Its sole function is to assess channel health by diffing pre- and post-snapshots and printing advisory status lines. While 'verifies channel health' is one declared subtask, that is only a small subset of the described skill, and the script's actual primary purpose is limited to verification within a preflight/postflight snapshot workflow. This is therefore a material description-to-behavior mismatch.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding

Without declared permissions the skill's intent is opaque and cannot be validated.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This code overwrites the active config file with a backup and immediately restarts the gateway, which is a safety-critical operation affecting system state and availability. Although the header documents the helper's purpose, there is no inline confirmation, visible user-facing log/print, or caution near the destructive action itself in this shared library.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.