Back to skill

Security audit

Skillstore

Security checks for vulnerabilities and agentic risk

Overview

This skill is a disclosed skill manager, but it can install unverified GitHub repositories as active skills and can write scaffold files outside the intended skills folder if given a crafted name.

Install only if you are comfortable with a tool that can fetch third-party GitHub repositories into your active OpenClaw skills folder. Review the selected repository manually before installing, avoid choosing unknown GitHub results, and do not pass path components such as ../ or slashes to the create/new command.

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

Error
Location
main.js:268
Finding

Unverified GitHub Repositories Can Be Installed as Trusted Skills

Content
View full analysis

Vulnerability Details

File Location: main.js:268-290
Vulnerability Type: Unsafe third-party component installation
Risk Level: High

Vulnerable Code

javascript
async function installFromGitHub(repo, name) {
  log(`\nInstalling ${name} from GitHub...`, 'cyan');

  const skillsDir = path.join(__dirname, '..');
  const targetDir = path.join(skillsDir, name);

  if (fs.existsSync(targetDir)) {
    log(`Skill "${name}" already exists`, 'yellow');
    return false;
  }

  const cmd = `git clone https://github.com/${repo}.git "${targetDir}"`;

  return new Promise((resolve) => {
    exec(cmd, (error) => {
      if (error) {
        err(`Failed to install: ${error.message}`);
        resolve(false);
        return;
      }

      log(`Installed to ${targetDir}`, 'green');

Technical Analysis

The application searches GitHub for repositories based on user-supplied keywords and allows a selected repository to be cloned directly into the active skills directory. Before installation, it does not:

  • Restrict repositories to trusted owners or an approved registry.
  • Pin the installation to an immutable commit.
  • verify a signature, checksum, or release provenance.
  • Inspect executable files or skill instructions.
  • Require a security review before making the downloaded repository available as a skill.

The search relevance threshold is only a textual similarity measure and provides no assurance about repository authenticity or safety. An attacker can create a repository whose name and description contain expected OpenClaw keywords so that it appears in search results.

Although this function clones rather than directly executes the repository, installed skills are components intended to be loaded or invoked later. Consequently, mutable, unverified remote content is introduced into a trusted execution environment.

Attack Path

  1. An attacker publishes a GitHub repository with a name and description matching a commonly searched ...[truncated 1190 chars]
Remediation
View remediation

Remediation Suggestions

  1. Restrict installation to an allowlist of verified repository owners and repositories, or use a curated skill registry.
  2. Resolve the selected repository to an immutable commit and clone or check out that exact revision.
  3. Display the complete repository owner, URL, commit hash, and verification status before requesting explicit installation approval.
  4. Verify signed commits or releases where available and validate downloaded content against trusted checksums.
  5. Stage repositories in a quarantine directory instead of immediately placing them in the active skills directory.
  6. Scan staged content for executable scripts, dangerous lifecycle hooks, suspicious instructions, symbolic links, and secret-access behavior.
  7. Require a separate activation step after review.
  8. Run third-party skills in a sandbox with minimal filesystem, network, environment-variable, and tool permissions.
  9. Prefer spawn or execFile with separate arguments over constructing a shell command, even after repository validation.

T09 · Insecure Skill Coding Practices

Warning
Location
main.js:301
Finding

Path Traversal Through an Unsanitized Skill Name

Content
View full analysis

Vulnerability Details

File Location: main.js:301-305, 366-370, 465-468
Vulnerability Type: Path traversal and arbitrary directory creation
Risk Level: Medium

Vulnerable Code

javascript
function createNewSkill(name) {
  log(`\nCreating new skill: ${name}`, 'cyan');

  const skillsDir = path.join(__dirname, '..');
  const targetDir = path.join(skillsDir, name);

  if (fs.existsSync(targetDir)) {
    err(`Skill "${name}" already exists!`);
    return false;
  }

  fs.mkdirSync(targetDir, { recursive: true });
javascript
  for (const [filename, content] of Object.entries(templates)) {
    fs.writeFileSync(path.join(targetDir, filename), content);
  }

  fs.chmodSync(path.join(targetDir, 'main.js'), '755');
javascript
  if (query.startsWith('create ') || query.startsWith('new ')) {
    const name = query.replace(/^(create|new)\s+/, '');
    createNewSkill(name);
    return;
  }

Technical Analysis

The explicit create and new command path passes the supplied skill name to createNewSkill without validation. The name is then appended to the skills directory with path.join.

A name containing parent-directory components such as ../ can cause the resulting path to escape the intended skills root. The function recursively creates the resolved directory and writes SKILL.md, README.md, config.json, .gitignore, and main.js into it. It also marks the generated main.js as executable.

The existence check does not enforce containment. It only prevents creation when the final target directory already exists. Therefore, a previously nonexistent path outside the skills directory remains writable if the current process has permission.

The generated templates also interpolate the untrusted name into JavaScript, Markdown, and JSON without context-appropriate escaping. This can produce malformed or attacker-controlled generated content, although the confirmed direct security boundary violation is filesy ...[truncated 1403 chars]

Remediation
View remediation

Remediation Suggestions

  1. Accept only a strict skill slug, for example: /^[a-z0-9][a-z0-9_-]{0,63}$/
  2. Reject names containing path separators, . or .. path components, control characters, leading hyphens, or whitespace.
  3. Calculate and validate canonical paths before creating any directory:
javascript
const skillsRoot = path.resolve(__dirname, '..');
const targetDir = path.resolve(skillsRoot, name);
const relative = path.relative(skillsRoot, targetDir);

if (!relative || relative.startsWith('..') || path.isAbsolute(relative)) {
  throw new Error('Invalid skill path');
}
  1. Perform the containment check immediately before every filesystem write.
  2. Consider using fs.mkdirSync(targetDir, { recursive: false }) after validating that the direct parent is the expected skills root.
  3. Detect and reject symbolic-link components to prevent link-based escapes.
  4. Generate JSON with JSON.stringify rather than direct string interpolation.
  5. Escape untrusted values according to their JavaScript and Markdown output contexts.
  6. Add tests covering ../, nested traversal, path separators, control characters, symbolic links, and excessively long names.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (8)

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill clones and installs remote code from GitHub via a shell command, which gives the tool a software installation capability far beyond passive search. In this context, that is dangerous because search results are pulled from GitHub dynamically and then converted into local code on disk, creating a supply-chain risk and potential command injection exposure if repository-derived values are not strictly validated.

Content

No source excerpt is available for this finding.

Session Persistence

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

Content

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

md
# SkillStore - OpenClaw Skill Manager

Search, install, and create OpenClaw skills with intelligent matching.

## Skill Metadata

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill explicitly presents GitHub results as installable choices but does not warn the user that selecting such a result will fetch and install code from a remote repository. This creates a supply-chain and social-engineering risk because users may treat search results as trusted options and install unreviewed third-party code without understanding the trust boundary.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

Line L26 states that all formal documentation for projects must be in English only. This is a natural-language locale policy constraint that forces a specific language and does not offer user choice or provide a documented justification for the restriction.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The header comment says the skill manager provides 'Intelligent search with semantic matching and threshold filtering', which frames the behavior as search-oriented. However, the implementation includes GitHub cloning to install code and scaffolding/writing new skill files, which are materially different side-effecting operations.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · main.js (reported line 187)May include surrounding context.

js
try {
    const results = await httpGet(
      `https://api.github.com/search/repositories?q=openclaw+${encodeURIComponent(query)}+in:name,description&per_page=15`
    );
    
    if (!results.items) return [];

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The code proceeds to installation once a numeric choice is entered, without a second explicit confirmation that remote code will be cloned locally. Because the selection UI mixes search and install flow, a user may reasonably think they are only choosing a search result, not authorizing code acquisition from an external source.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

The createNewSkill function creates a directory, writes several files, and changes permissions, but it only logs that creation is happening rather than explicitly warning or confirming the filesystem changes. For a code file, safety-relevant file writes should have some form of user disclosure beyond implicit behavior unless clearly documented elsewhere.

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
main.js:282