Back to skill

Security audit

Skill Installer

Security checks for vulnerabilities and agentic risk

Overview

This is a real ClawHub skill installer, but it has unsafe installation behavior that can replace local skills and may install unverified content from outside ClawHub.

Review this carefully before installing. It is not judged malicious from the artifacts, but it can modify your active skill directory, replace existing skills, run unpinned external CLI code, and fetch unverified GitHub ZIPs. Only run it in a disposable or backed-up environment, with trusted skill names, after removing the GitHub fallback and adding path validation, checksum or signature verification, and explicit confirmation before replacement.

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

T09 · Insecure Skill Coding Practices

Error
Location
install.cjs:111
Finding
Shell Command Injection Through User-Controlled Search and Skill Names## Vulnerability Details **File Location**: `install.cjs`, lines 111, 184, and 225 **Vulnerability Type**: OS command injection **Risk Level**: High ### Vulnerable Code ```javascript const output = execSync(`npx clawhub search ${query} 2>&1`, { encoding: 'utf-8', cwd: SKILLS_DIR }); ``` ```javascript execSync(`unzip -q "${zipPath}" -d "${extractDir}"`, { stdio: 'inherit' }); ``` ```javascript execSync(`npx clawhub install ${skillName} --force`, { encoding: 'utf-8', cwd: SKILLS_DIR, stdio: 'inherit' }); ``` ### Technical Analysis `query` and `skillName` are derived directly from command-line arguments. They are interpolated into command strings passed to `execSync`, which invokes a system shell. Shell metacharacters, command substitutions, redirections, or embedded quotation marks contained in these arguments are interpreted by the shell rather than treated solely as literal data. Quoting `zipPath` and `extractDir` does not provide sufficient protection because a malicious skill name can contain a quotation mark that terminates the quoted argument. The vulnerable search and installation fallback commands become reachable when the corresponding API operation fails. The `unzip` invocation is reached after a skill archive has been downloaded. ### Attack Path 1. An attacker causes the tool to be invoked with a crafted search query or skill name containing shell syntax. 2. For the search or installation fallback, the attacker causes or waits for the ClawHub API operation to fail. 3. The crafted value is inserted into an `execSync` command string. 4. The operating-system shell parses the injected syntax. 5. The attacker's command executes with the privileges of the user running the installer. For the extraction command, a crafted skill name can influence `zipPath` and `extractDir`; embedded shell quoting or substitution syntax can escape the intended arguments when `unzip` is invok ...[truncated 462 chars]
Remediation
## Remediation Suggestions - Replace shell-based `execSync` calls with `execFileSync` or `spawnSync`, passing arguments as an array: ```javascript execFileSync('npx', ['clawhub', 'search', query], { encoding: 'utf8', cwd: SKILLS_DIR, stdio: 'inherit', shell: false }); execFileSync('unzip', ['-q', zipPath, '-d', extractDir], { stdio: 'inherit', shell: false }); execFileSync('npx', ['clawhub', 'install', skillName, '--force'], { cwd: SKILLS_DIR, stdio: 'inherit', shell: false }); ``` - Validate skill names with a restrictive allowlist, such as `^[A-Za-z0-9._-]+$`. - Reject path separators, control characters, shell metacharacters, and names beginning with an option prefix. - Avoid invoking `npx` in a way that can download packages dynamically. Resolve and execute a trusted, pinned CLI binary instead. - Add tests covering semicolons, command substitutions, quotation marks, newlines, redirections, and option-injection payloads.

T09 · Insecure Skill Coding Practices

Error
Location
install.cjs:169
Finding
Path Traversal Enables Deletion and Modification Outside Intended Directories## Vulnerability Details **File Location**: `install.cjs`, lines 169-205 **Vulnerability Type**: Path traversal and unsafe recursive deletion **Risk Level**: High ### Vulnerable Code ```javascript const zipPath = path.join(TEMP_DIR, `${skillName}.zip`); const extractDir = path.join(TEMP_DIR, skillName); if (fs.existsSync(extractDir)) { fs.rmSync(extractDir, { recursive: true }); } fs.mkdirSync(extractDir, { recursive: true }); ``` ```javascript const sourceDir = path.join(extractDir, skillDir); const targetDir = path.join(SKILLS_DIR, skillName); const versionMatch = skillDir.match(/^(.+)-v?\d+\.\d+\.\d+$/); const finalName = versionMatch ? versionMatch[1] : skillName; const finalTargetDir = path.join(SKILLS_DIR, finalName); if (fs.existsSync(finalTargetDir)) { console.log(`🗑️ 删除旧版本: ${finalTargetDir}`); fs.rmSync(finalTargetDir, { recursive: true }); } fs.renameSync(sourceDir, finalTargetDir); ``` ### Technical Analysis `skillName` originates from a command-line argument and is used as a filesystem path component without validation. A name containing traversal sequences such as `../` can cause normalized paths to escape `TEMP_DIR` or `SKILLS_DIR`. These attacker-influenced paths are passed to recursive deletion, directory creation, archive writing, and rename operations. No canonicalization or containment check verifies that the resulting paths remain descendants of the intended root directories. The variable `finalName` may also inherit the unsafe `skillName`, so the installation destination remains vulnerable even after the version-handling logic. ### Attack Path 1. The installer is invoked with a skill name containing one or more `../` traversal components. 2. `path.join` normalizes the path and may produce a location outside `/tmp/clawhub-downloads` or the configured skills directory. 3. Once the download stage succeeds, the installer checks whether the attacker-selected ext ...[truncated 829 chars]
Remediation
## Remediation Suggestions - Restrict skill names to a safe identifier format: ```javascript function validateSkillName(name) { if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(name)) { throw new Error('Invalid skill name'); } if (name === '.' || name === '..') { throw new Error('Invalid skill name'); } } ``` - Resolve each destination against its intended root and enforce containment: ```javascript function safeChildPath(root, child) { const canonicalRoot = path.resolve(root); const candidate = path.resolve(canonicalRoot, child); if ( candidate !== canonicalRoot && !candidate.startsWith(canonicalRoot + path.sep) ) { throw new Error('Path escapes the permitted root'); } return candidate; } ``` - Never recursively delete a path until its canonical location has been verified. - Reject path separators, traversal components, null bytes, and platform-specific separator variants. - Use a newly created per-operation temporary directory through `fs.mkdtempSync` instead of a predictable, shared path. - Consider refusing symbolic links at destination boundaries and checking the real path of existing parent directories before deletion or replacement.

T08 · Insecure Dependencies

Error
Location
install.cjs:137
Finding
Unverified GitHub Search Result Is Installed as a Trusted Skill## Vulnerability Details **File Location**: `install.cjs`, lines 137-145 and 168-201 **Vulnerability Type**: Dependency substitution through an untrusted fallback source **Risk Level**: High ### Vulnerable Code ```javascript const githubUrl = `https://api.github.com/search/repositories?q=${encodeURIComponent(skillName)}+clawhub+skill`; const data = await httpGet(githubUrl, { 'User-Agent': 'OpenClaw' }); const result = JSON.parse(data); if (result.items && result.items.length > 0) { const repo = result.items[0]; return { name: skillName, github_url: repo.html_url, download_url: `${repo.html_url}/archive/refs/heads/main.zip` }; } ``` ```javascript const downloadUrl = details.download_url || `${CLAWHUB_API}/api/skills/${skillName}/download`; const zipPath = path.join(TEMP_DIR, `${skillName}.zip`); await downloadFile(downloadUrl, zipPath); const extractDir = path.join(TEMP_DIR, skillName); fs.mkdirSync(extractDir, { recursive: true }); execSync(`unzip -q "${zipPath}" -d "${extractDir}"`, { stdio: 'inherit' }); // ... fs.renameSync(sourceDir, finalTargetDir); ``` ### Technical Analysis When ClawHub metadata retrieval fails, the installer performs a general GitHub repository search and selects `result.items[0]`. The repository is not verified against an authoritative owner, registry record, package identity, signature, or expected cryptographic digest. The installer then downloads the mutable `main` branch. Repository search ranking and branch contents can change after this project has been reviewed. An attacker can create or optimize a repository matching the search terms and potentially become the first result. The downloaded repository is extracted and moved directly into the active skills directory. Consequently, an unrelated or malicious repository can be substituted for the requested skill. ### Attack Path 1. An attacker publishes a GitHub repository ...[truncated 1231 chars]
Remediation
## Remediation Suggestions - Remove the repository-search fallback entirely. - Resolve skills only through an authenticated, canonical registry mapping that binds each skill name to an approved publisher and repository. - Pin downloads to immutable version tags or commit hashes rather than `main`. - Require a trusted cryptographic digest or digital signature for every downloaded archive. - Verify the repository owner, repository identifier, package name, requested version, and digest before extraction. - Stage downloaded skills in quarantine and inspect their metadata, instructions, scripts, and archive entries before activation. - Fail closed when canonical metadata cannot be retrieved instead of selecting an approximate search result.

T08 · Insecure Dependencies

Warning
Location
install.cjs:41
Finding
Unrestricted Redirects and Unbounded Archive Downloads## Vulnerability Details **File Location**: `install.cjs`, lines 41-43 and 56-77 **Vulnerability Type**: Unvalidated remote content retrieval **Risk Level**: Medium ### Vulnerable Code ```javascript } else if (res.statusCode === 302 || res.statusCode === 301) { // Follow redirect httpGet(res.headers.location, headers).then(resolve).catch(reject); } ``` ```javascript function downloadFile(url, destPath) { return new Promise((resolve, reject) => { const file = fs.createWriteStream(destPath); const request = https.get(url, (response) => { if (response.statusCode === 302 || response.statusCode === 301) { // Follow redirect downloadFile(response.headers.location, destPath) .then(resolve) .catch(reject); return; } response.pipe(file); file.on('finish', () => { file.close(); resolve(destPath); }); }); request.on('error', (err) => { fs.unlink(destPath, () => {}); reject(err); }); }); } ``` ### Technical Analysis Redirect destinations are followed without validating the destination hostname against an allowlist. There is also no redirect-count limit, archive-size limit, content-type validation, successful-status check for the final download response, timeout, checksum verification, or signature verification. Because download URLs can come from remote metadata and the GitHub fallback, a compromised or malicious source can redirect the installer to unexpected HTTPS hosts. The final response body is written to disk regardless of whether it represents an expected successful ZIP response. Recursive redirects can also consume resources, while an unbounded response can fill available disk space. Any resulting file is subsequently supplied to `unzip` as part of the installation flow. ### Attack Path 1. A metadata source supplies a malicious download URL, or a ...[truncated 1044 chars]
Remediation
## Remediation Suggestions - Parse every initial and redirected URL before issuing a request. - Require HTTPS and enforce an explicit allowlist of approved registry and archive hosts. - Limit redirect depth, for example to three redirects, and reject missing or malformed `Location` headers. - Correctly resolve relative redirect locations against the current URL. - Reject final responses outside the expected successful status range. - Enforce connection, response, and total-operation timeouts. - Set a strict maximum archive size and abort the request when it is exceeded. - Download to a unique temporary file and remove partial files on every failure path. - Validate expected content type and ZIP structure, while treating content type only as an additional check. - Verify a registry-provided cryptographic digest or signature before extracting the archive. - Inspect archive entry paths and reject traversal paths, absolute paths, symbolic-link escapes, and unsupported entry types before installation.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
Findings (25)

Ae1

High
Category
analysis-evasion
Content
You can modify these variables at the top of `install.cjs`:
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Self-Modification

High
Category
Rogue Agent
Content
### Force Reinstall

Overwrite existing skill:

```bash
node install.cjs install todoist --force
Confidence
87% confidence
Finding
Documenting a `--force` mode that overwrites existing skills indicates self-modifying behavior against the user's local skill set. In the context of an agent skill installer, this is dangerous because it can replace trusted skills, break existing configurations, or facilitate persistence by swapping skill contents if used on malicious or spoofed packages.

Missing User Warnings

Medium
Confidence
87% confidence
Finding
The README encourages downloading and installing skills into a local skills directory, but does not clearly warn that this writes files to disk and may overwrite existing contents. In an installer context, omission of overwrite/write-path warnings can mislead users into running actions that alter local state or replace trusted skills unexpectedly.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
**Linux (Ubuntu/Debian)**:
```bash
sudo apt-get install curl unzip jq
```

---
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

File System Enumeration

Medium
Category
Data Exfiltration
Content
### 查看已安装的技能

```bash
ls -la /Users/xufan65/.openclaw/workspace/skills/
```

---
Confidence
60% confidence
Finding
Code scans file system directories looking for sensitive files. This could be reconnaissance for credential theft.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
- **Bypassing API rate limits** - Intelligently handles ClawHub API restrictions
- **Batch installation** - Install multiple skills in one command
- **Automatic retries** - Smart retry logic when encountering rate limits
- **Version management** - Automatically removes version numbers from skill folder names
- **Comprehensive search** - Find skills directly from ClawHub

## ✨ Features
Confidence
80% 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.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The skill advertises installation into the user's skills directory but does not clearly warn that it downloads, extracts, moves, and may overwrite files there. Users may underestimate the filesystem impact and grant trust to operations that can modify local agent behavior or destroy existing skill content.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The documentation describes direct network downloads and fallback to the ClawHub CLI but does not provide a clear privacy or system-impact warning. This matters because the tool contacts external services, downloads archives, and may execute or invoke additional tooling, which expands the attack surface and can expose user environment data or credentials.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding
The documentation instructs users to run `npx clawhub` without pinning a specific version, which can fetch and execute whatever package version is current at execution time. This creates a supply-chain risk because a compromised, malicious, or breaking upstream release could be run in the user's environment with little visibility.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding
This is the same unpinned `npx clawhub` execution pattern repeated later in the file. Recommending unversioned remote package execution increases exposure to dependency hijacking or unexpected code execution if the package changes upstream.

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
User-facing natural-language strings and usage documentation are written entirely in Chinese, and the file does not indicate that language choice is optional or that the skill is intentionally region-specific. This can violate language/locale policy when a skill effectively mandates one language without user opt-in.

Context-Inappropriate Capability

Medium
Confidence
93% confidence
Finding
The manifest describes a ClawHub skill installer with search, install, batch install, retry, and version management. While network and file operations are expected for that purpose, invoking subprocesses introduces an additional execution capability not declared in the description and can run whatever binaries are present on the host.

Rp1

Medium
Category
MCP Rug Pull
Confidence
94% confidence
Finding
The script invokes `npx clawhub search` without pinning a specific package version, so execution depends on whatever package version is currently resolved from the registry at runtime. If the package is updated maliciously, compromised upstream, or typosquatted via configuration issues, the installer may execute attacker-controlled code on the local machine.

Description-Behavior Mismatch

Medium
Confidence
96% confidence
Finding
The implementation silently switches from ClawHub to GitHub ZIP installation, which changes the trust model from a named skill registry to arbitrary repository archives. In an installer, that context makes the mismatch dangerous because users expect registry-scoped content but may instead receive attacker-controlled code from an unauthenticated fallback path.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
When ClawHub lookup fails, the installer searches GitHub and installs the first matching repository ZIP, expanding trust from a curated source to arbitrary search results. This materially increases the chance of installing malicious or unrelated code because repository search ranking is not a security control and no publisher verification is performed.

External Transmission

Medium
Category
Data Exfiltration
Content
// 尝试从 GitHub API 获取(如果技能在 GitHub 上)
    try {
      const githubUrl = `https://api.github.com/search/repositories?q=${encodeURIComponent(skillName)}+clawhub+skill`;
      const data = await httpGet(githubUrl, { 'User-Agent': 'OpenClaw' });
      const result = JSON.parse(data);
Confidence
84% confidence
Finding
The script transmits user-supplied skill names to the GitHub API as a fallback, sending potentially sensitive usage intent to a third party outside the stated ClawHub source. In isolation this is limited, but in an installer context it expands data exposure and couples installation behavior to an external service not clearly disclosed to users.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The installer deletes any existing target directory recursively and replaces it without confirmation, backup, or path safety checks. If a skill name maps unexpectedly or installation metadata is manipulated, this can destroy local data in the skills workspace and make recovery difficult.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding
The fallback install path executes `npx clawhub install ... --force` without version pinning, which causes arbitrary code from the latest resolved package to run during a high-trust installation flow. Because this path is triggered after other failures, users may not realize they are executing an unvetted external package with filesystem-modifying behavior.

Natural-Language Policy Violations

Medium
Confidence
92% confidence
Finding
The package description is written only in Chinese ("直接从 ClawHub 下载 zip 包安装技能,绕过 API 速率限制") with no indication of alternative language support or user choice. This can violate language/locale policy when a skill is presented to a broader audience without offering opt-in or localization options.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
A language or locale policy issue exists when a skill forces a specific language without user opt-in or justification. This README presents all operational guidance in Chinese and does not offer an alternative language, opt-in, or explanation that the skill is intended only for Chinese-speaking users.

Missing User Warnings

Low
Confidence
81% confidence
Finding
The README explains downloading ZIP packages and falling back to CLI/API access, but omits a clear security/privacy notice that these operations contact external services and fetch untrusted archives over the network. In an installer skill, users should be explicitly informed that installation involves remote content retrieval and associated trust assumptions.

Natural-Language Policy Violations

Low
Confidence
86% confidence
Finding
The usage examples show the tool outputting Chinese text, and the document does not indicate that language is configurable or that the skill is intended only for Chinese-speaking users. This can violate language/locale policy expectations when a skill implicitly forces a specific language without user opt-in.

Description-Behavior Mismatch

Low
Confidence
86% confidence
Finding
The manifest describes search/install with retry and version management, suggesting a self-contained installer. The implementation instead delegates to an external CLI when API or direct-download logic fails, which is a meaningful operational behavior not reflected in the description.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
install.cjs:114