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

Content
View full analysis

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
View 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

Content
View full analysis

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
View 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

Content
View full analysis

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
View 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

Content
View full analysis

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
View 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
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 197)May include surrounding context.

md
You can modify these variables at the top of `install.cjs`:

Self-Modification

High
Category
Rogue Agent
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.

Content

Scanner excerpt · SKILL.md (reported line 226)May include surrounding context.

Force Reinstall

Overwrite existing skill:

bash
node install.cjs install todoist --force

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · README.md (reported line 135)May include surrounding context.

Linux (Ubuntu/Debian):

bash
sudo apt-get install curl unzip jq

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.

Content

No source excerpt is available for this finding.

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.

Content

No source excerpt is available for this finding.

File System Enumeration

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code scans file system directories looking for sensitive files. This could be reconnaissance for credential theft.

Content

Scanner excerpt · README.md (reported line 179)May include surrounding context.

查看已安装的技能

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

Autonomous Decision Making

Medium
Category
Excessive Agency
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.

Content

Scanner excerpt · SKILL.md (reported line 28)May include surrounding context.

md
- **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

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

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.

Content

No source excerpt is available for this finding.

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.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

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.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
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.

Content

Scanner excerpt · install.cjs (reported line 139)May include surrounding context.

js
// 尝试从 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);

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

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.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
install.cjs:114