Back to skill

Security audit

clawhub-install

Security checks for vulnerabilities and agentic risk

Overview

This skill openly installs ClawHub skills, but its installer can overwrite or delete local content too broadly and lacks package integrity checks.

Only install this after reviewing or fixing the installer. Prefer the official ClawHub/OpenClaw install path, or require strict skill-name validation, checksum/signature verification, safe temporary directories, archive-entry validation, and explicit confirmation before replacing existing skills.

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

T03 · Remote Payload Retrieval and Execution

Error
Location
scripts/install.sh:35
Finding
Unverified Remote Skill Payload Installation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/install.sh:35-70` **Vulnerability Type**: Unverified remote payload retrieval and installation **Risk Level**: Critical ### Vulnerable Code ```bash # Step 2: Download skill package echo "Downloading $skill_name from ClawHub..." download_url="https://wry-manatee-359.convex.site/api/v1/download?slug=${skill_name}" zip_path="/tmp/${skill_name}.zip" if curl -L -o "$zip_path" "$download_url" --fail --silent --show-error; then echo "Downloaded successfully" else echo -e "${RED}Error: Failed to download ${skill_name}. The skill may not exist or rate limited.${NC}" rm -f "$zip_path" return 1 fi # Check if zip file is valid if [ ! -s "$zip_path" ]; then echo -e "${RED}Error: Downloaded file is empty${NC}" rm -f "$zip_path" return 1 fi # Step 3: Extract to workspace/skills skills_dir="$workspace_path/skills" target_dir="$skills_dir/$skill_name" echo "Extracting to $target_dir..." # Create skills directory if not exists mkdir -p "$skills_dir" # Remove existing skill if it exists if [ -d "$target_dir" ]; then echo "Removing existing $skill_name..." rm -rf "$target_dir" fi # Create the skill directory mkdir -p "$target_dir" # Extract the zip if unzip -q "$zip_path" -d "$target_dir"; then ``` ### Technical Analysis The installer downloads a mutable archive from an external server and extracts it directly into OpenClaw's active `skills` directory. The only content validation is a nonempty-file check. It does not verify a cryptographic signature, a trusted publisher identity, a pinned digest, or an expected package manifest. The use of `curl -L` also allows redirects without validating that the final destination remains an approved host. The effective Skill content can therefore change after this installer has been reviewed. A compromise of the download service, its delivery infrastructure, or an allowed redirect target could replace a legitimate Skill with attacker-c ...[truncated 1597 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Prefer the official, authenticated Skill distribution and installation mechanism rather than bypassing its controls. 2. Require each archive to have a cryptographic signature from an explicitly trusted publisher, and verify it before extraction. 3. Pin an expected cryptographic digest for every package version. Reject any archive whose digest does not match. 4. Disable unrestricted redirects or validate the scheme and hostname of the final URL against a strict allowlist. 5. Download into an isolated staging directory and validate the archive manifest and every contained file before installation. 6. Reject unexpected executable files, symlinks, device entries, and unsupported file types. 7. Present the package identity, version, publisher, digest, and requested permissions for explicit approval. 8. Move validated content atomically into the active Skill directory rather than extracting remote content there directly. 9. Preserve the previous trusted Skill until the replacement has passed all validation, enabling safe rollback. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/install.sh:18
Finding
Path Traversal Enables Deletion and Replacement Outside the Skills Directory<![CDATA[ ## Vulnerability Details **File Location**: `scripts/install.sh:18-66` **Vulnerability Type**: User-controlled path traversal and unsafe recursive deletion **Risk Level**: High ### Vulnerable Code ```bash install_skill() { local skill_name="$1" echo -e "${YELLOW}Installing skill: ${skill_name}${NC}" # Step 1: Get workspace directory path echo "Getting workspace directory..." workspace_path=$(openclaw config get agents.defaults.workspace 2>/dev/null) if [ -z "$workspace_path" ]; then echo -e "${RED}Error: Could not get workspace path. Make sure OpenClaw is configured.${NC}" return 1 fi echo "Workspace: $workspace_path" # Step 2: Download skill package echo "Downloading $skill_name from ClawHub..." download_url="https://wry-manatee-359.convex.site/api/v1/download?slug=${skill_name}" zip_path="/tmp/${skill_name}.zip" if curl -L -o "$zip_path" "$download_url" --fail --silent --show-error; then echo "Downloaded successfully" else echo -e "${RED}Error: Failed to download ${skill_name}. The skill may not exist or rate limited.${NC}" rm -f "$zip_path" return 1 fi # Check if zip file is valid if [ ! -s "$zip_path" ]; then echo -e "${RED}Error: Downloaded file is empty${NC}" rm -f "$zip_path" return 1 fi # Step 3: Extract to workspace/skills skills_dir="$workspace_path/skills" target_dir="$skills_dir/$skill_name" echo "Extracting to $target_dir..." # Create skills directory if not exists mkdir -p "$skills_dir" # Remove existing skill if it exists if [ -d "$target_dir" ]; then echo "Removing existing $skill_name..." rm -rf "$target_dir" fi # Create the skill directory mkdir -p "$target_dir" ``` ### Technical Analysis The script accepts `skill_name` directly from a command-line argument and uses it as a filesystem path component. It applies no slug ...[truncated 1730 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Validate Skill names before using them in URLs or paths. For example, enforce a conservative slug expression such as `^[A-Za-z0-9][A-Za-z0-9._-]*$`. 2. Explicitly reject empty values, `.`, `..`, path separators, control characters, and percent-encoded path syntax. 3. Canonicalize both `skills_dir` and `target_dir` using `realpath` or equivalent logic. 4. Verify that the canonical destination is a strict child of the canonical skills directory before any deletion, creation, or extraction. 5. Refuse to operate if the destination or an ancestor is a symbolic link. 6. Avoid recursively deleting a path derived directly from user input. Move the existing validated directory to a private backup location and remove it only after successful installation. 7. Use a registry-provided immutable package identifier separately from the local directory name. 8. Add automated tests covering `../`, absolute paths, repeated separators, encoded traversal, Unicode edge cases, and symlinked destination paths. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/install.sh:35
Finding
Unsafe ZIP Extraction May Write Outside the Installation Directory<![CDATA[ ## Vulnerability Details **File Location**: `scripts/install.sh:35-70` **Vulnerability Type**: Unvalidated archive extraction **Risk Level**: High ### Vulnerable Code ```bash download_url="https://wry-manatee-359.convex.site/api/v1/download?slug=${skill_name}" zip_path="/tmp/${skill_name}.zip" if curl -L -o "$zip_path" "$download_url" --fail --silent --show-error; then echo "Downloaded successfully" else echo -e "${RED}Error: Failed to download ${skill_name}. The skill may not exist or rate limited.${NC}" rm -f "$zip_path" return 1 fi # Check if zip file is valid if [ ! -s "$zip_path" ]; then echo -e "${RED}Error: Downloaded file is empty${NC}" rm -f "$zip_path" return 1 fi # Step 3: Extract to workspace/skills skills_dir="$workspace_path/skills" target_dir="$skills_dir/$skill_name" echo "Extracting to $target_dir..." # Create skills directory if not exists mkdir -p "$skills_dir" # Remove existing skill if it exists if [ -d "$target_dir" ]; then echo "Removing existing $skill_name..." rm -rf "$target_dir" fi # Create the skill directory mkdir -p "$target_dir" # Extract the zip if unzip -q "$zip_path" -d "$target_dir"; then ``` ### Technical Analysis The script extracts an untrusted, remotely supplied ZIP archive without inspecting its entry names or types. It does not reject absolute paths, parent-directory components, symlinks, or entries whose normalized destination falls outside `target_dir`. Whether a particular crafted entry is blocked can depend on the installed `unzip` implementation and version. The script itself establishes no containment guarantee and therefore relies entirely on undocumented or environment-dependent extractor behavior. A malicious archive can attempt ZIP path traversal using entries such as `../../file`, absolute paths, or link-based path manipulation. If accepted by the extractor, these entries write outside the intended Skill directory. ### Attack Path 1. An attacker cont ...[truncated 1039 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. List and validate all archive entries before extraction. 2. Reject absolute paths, drive-prefixed paths, parent-directory components, control characters, and entries whose normalized destination escapes the staging directory. 3. Reject symlinks, hard links, device nodes, and other special entries unless they are explicitly required and safely handled. 4. Extract into a newly created private staging directory rather than directly into the active Skill directory. 5. After extraction, recursively verify that every resulting object remains beneath the staging root and has an approved file type. 6. Apply restrictive permissions and remove unexpected executable bits. 7. Atomically move the validated directory into the final location. 8. Treat extractor warnings about renamed, skipped, or traversal-like entries as fatal validation failures. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/install.sh:35
Finding
Predictable Temporary Archive Path Permits Symlink and Race Attacks<![CDATA[ ## Vulnerability Details **File Location**: `scripts/install.sh:35-48` **Vulnerability Type**: Unsafe predictable temporary file **Risk Level**: High ### Vulnerable Code ```bash # Step 2: Download skill package echo "Downloading $skill_name from ClawHub..." download_url="https://wry-manatee-359.convex.site/api/v1/download?slug=${skill_name}" zip_path="/tmp/${skill_name}.zip" if curl -L -o "$zip_path" "$download_url" --fail --silent --show-error; then echo "Downloaded successfully" else echo -e "${RED}Error: Failed to download ${skill_name}. The skill may not exist or rate limited.${NC}" rm -f "$zip_path" return 1 fi ``` ### Technical Analysis The archive path is constructed predictably in the shared `/tmp` directory. The script does not create the file atomically, verify ownership, reject symbolic links, or use a private temporary directory. A local attacker who can predict the requested Skill name may pre-create `/tmp/<skill_name>.zip` as a symbolic link to another file. When `curl -o` opens that path, it may follow the link and overwrite or truncate the linked target with the downloaded response. The attacker can also race cleanup and extraction operations involving the predictable path. The user-controlled `skill_name` further increases the range of possible temporary paths because path separators and traversal components are not rejected. ### Attack Path 1. A local attacker predicts a Skill name that a victim will install. 2. The attacker creates the corresponding predictable `/tmp/<skill_name>.zip` path as a symbolic link to a file writable by the victim. 3. The victim runs the installer. 4. `curl -o` opens the predictable path and follows the attacker-created link. 5. The linked file is overwritten with the remote archive data. 6. Depending on the selected target, the victim suffers data destruction or modification of configuration or executable content. ### Impact Assessment The attacker can cause the invoking account ...[truncated 414 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create a private temporary directory with `mktemp -d`, verify that creation succeeds, and store the archive inside it. 2. Install a cleanup trap immediately after creation, such as a trap that removes only the verified private temporary directory on exit. 3. Use restrictive permissions, preferably `0700` for the directory and `0600` for files. 4. Never derive temporary filesystem paths directly from untrusted Skill names. 5. Refuse symbolic links and verify ownership and file type before reading or replacing temporary files. 6. Keep downloading, validation, and extraction within the private temporary directory. 7. Where supported, use file-opening semantics that prevent following symbolic links. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (5)

Context-Inappropriate Capability

High
Confidence
98% confidence
Finding
The script accepts an arbitrary user-supplied skill name and uses it to construct both /tmp and installation paths, then performs destructive operations like rm -rf on the derived target directory. Because skill_name is not validated or canonicalized, values containing path traversal components or path separators could cause deletion or extraction outside the intended skills directory, making this a real arbitrary file overwrite/delete risk.

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill invokes shell-based installation behavior but declares no tool scope or permissions, which weakens containment and reviewability for a workflow that downloads remote content and installs it into the local workspace. In this context, the risk is elevated because the skill explicitly bypasses the official installation path and fetches packages from a direct URL, increasing the chance of unreviewed or tampered content being introduced.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The documentation states that existing skills may be removed and skipped but does not clearly warn that installation can overwrite or delete an existing skill directory in the configured workspace. That creates a real integrity and availability risk: users may unintentionally destroy local skill contents or replace a trusted skill with newly downloaded remote content.

External Transmission

Medium
Category
Data Exfiltration
Content
download_url="https://wry-manatee-359.convex.site/api/v1/download?slug=${skill_name}"
    zip_path="/tmp/${skill_name}.zip"

    if curl -L -o "$zip_path" "$download_url" --fail --silent --show-error; then
        echo "Downloaded successfully"
    else
        echo -e "${RED}Error: Failed to download ${skill_name}. The skill may not exist or rate limited.${NC}"
Confidence
93% confidence
Finding
The script downloads and installs code from a remote third-party endpoint directly into the local skills workspace, explicitly bypassing official installation controls and without any signature, checksum, publisher, or content verification. This creates a supply-chain risk: a compromised service, malicious skill, or man-in-the-middle at the hosting layer could deliver attacker-controlled content that the agent later executes or trusts.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The installer unconditionally removes an existing target directory with rm -rf before replacement, with no confirmation, backup, or safety check. In isolation this is unsafe behavior; combined with the unvalidated target_dir construction, it can magnify destructive impact and lead to accidental or attacker-influenced data loss.

Static analysis

No suspicious patterns detected.