Back to skill

Security audit

SkillMe

Security checks for vulnerabilities and agentic risk

Overview

This skill is a visible skill search and installer, but it can install unverified remote instructions into active skill folders and runs unpinned external commands.

Review this carefully before installing. Use it only if you are comfortable with an agent searching external registries and installing skills that can affect later behavior. Prefer local workspace installs, inspect converted SKILL.md content before activation, avoid global unattended installs, and pin or otherwise verify external packages and remote skill sources.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T08 · Insecure Dependencies

Error
Location
SKILL.md:20
Finding
Unpinned npm Package Execution and Shell Injection Risk<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:20-24`, `SKILL.md:29-32`, and `SKILL.md:53` **Vulnerability Type**: Unpinned dependency execution and unsafe shell command construction **Risk Level**: High ### Vulnerable Code ```bash # Run both in parallel, capture output clawhub search "<query>" & CLAWHUB_PID=$! npx skills find <query> 2>&1 & SKILLS_PID=$! wait $CLAWHUB_PID $SKILLS_PID ``` ```bash echo "=== ClawHub ===" && clawhub search "<query>" echo "=== skills.sh ===" && npx skills find <query> 2>&1 ``` The installation example also executes the same unpinned package: ```text Install: npx skills add vercel-labs/agent-skills@react-best-practices -g -y ``` ### Technical Analysis The documented workflow executes `npx skills` without specifying an audited package version or integrity value. Depending on the local npm environment, `npx` can download and execute the package currently published under the `skills` name. The effective executable can therefore change after this skill has been reviewed. This creates a supply-chain trust boundary in which compromise of the npm package, its maintainer account, or its transitive dependencies can result in arbitrary code being run with the agent process's operating-system privileges. In addition, the parallel-search example places `<query>` directly into a shell command without quoting it. If an implementation performs literal textual substitution, shell metacharacters contained in an attacker-controlled query can terminate or extend the intended command. Although the sequential example quotes the ClawHub query, its `npx skills find <query>` invocation remains unquoted. For example, a malicious query containing command separators or command substitution syntax could be interpreted by the shell rather than passed exclusively as a search argument. The exact exploitability depends on how the agent constructs and invokes the documented command, but the instructions explicitly encourage shell execution ...[truncated 1364 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin the npm package to a specifically reviewed version rather than invoking the moving package name: ```bash npx --yes skills@<audited-version> find "$query" ``` 2. Commit and enforce a lockfile containing package integrity hashes. Prefer installation through a controlled build process over downloading packages during each skill invocation. 3. Verify the package publisher, provenance, signatures, and dependency tree before approving upgrades. 4. Avoid constructing commands through shell interpolation. Invoke executables with an argument array so the query is passed as one data argument. 5. If shell execution is unavoidable, assign the input to a variable and quote every expansion: ```bash query='<validated query>' clawhub search "$query" npx --yes skills@<audited-version> find "$query" ``` 6. Validate search queries against an appropriate length and character policy. Do not rely on validation alone as a substitute for argument-safe process invocation. 7. Run registry searches in a sandbox with minimal filesystem permissions, no unnecessary secrets in the environment, restricted network access, and no administrative privileges. 8. Remove or revise the global unattended installation example using `-g -y`; require explicit user confirmation and install into a quarantined local location first. ]]>

T01 · Skill Instruction Hijacking

Error
Location
scripts/convert_skillssh.py:96
Finding
Untrusted Mutable GitHub Instructions Written Directly into Active Skill Directories<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:76-84`; `scripts/convert_skillssh.py:96-100`, `scripts/convert_skillssh.py:214-233`, and `scripts/convert_skillssh.py:252-255` **Vulnerability Type**: Mutable remote skill retrieval and instruction hijacking **Risk Level**: High ### Vulnerable Code The installation instructions direct the converter's output into the selected active skill location: ```bash python3 /root/.openclaw/workspace/skills/skill-finder/scripts/convert_skillssh.py \ "<url-or-slug>" \ --output /path/to/chosen/location/<skill-name>/SKILL.md ``` The converter retrieves the remote file without a commit pin, checksum, signature, content-size limit, or trust verification: ```python def fetch_url(url: str) -> str: """Fetch content from URL.""" try: with urllib.request.urlopen(url, timeout=15) as resp: return resp.read().decode("utf-8") except urllib.error.HTTPError as e: if e.code == 404: raise ValueError(f"Skill not found at {url} (404). Check the owner/repo/skill-name.") raise ValueError(f"HTTP {e.code} fetching {url}: {e.reason}") except Exception as e: raise ValueError(f"Failed to fetch {url}: {e}") ``` Most of the untrusted instruction body is retained without security validation: ```python def convert(content: str, skill_name: str) -> str: """Convert a skills.sh SKILL.md into OpenClaw format.""" fm, body = parse_frontmatter(content) existing_name = fm.get("name", skill_name) existing_desc = fm.get("description", "") when_to_use, clean_body = extract_when_to_use(body) description = build_description(existing_name, existing_desc, when_to_use) # Build output output_lines = [ "---", f"name: {existing_name}", f"description: {description}", "---", "", clean_body.strip(), ] return "\n".join(output_lines) + "\n" ``` The resulting instructions are written directly ...[truncated 3580 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Resolve every accepted repository reference to an immutable Git commit and download content only from that commit. Do not install directly from mutable `main` or `master` branches. 2. Require an expected SHA-256 checksum or a verified publisher signature before conversion and installation. 3. Download converted skills into a non-active quarantine directory first. 4. Display the source repository, resolved commit, checksum, complete converted content, and a meaningful diff to the user before activation. 5. Require explicit confirmation after review and before moving the file into an active skill directory. 6. Add static policy checks for: - Attempts to override system or safety instructions. - Requests to access credentials, tokens, private keys, or unrelated files. - Commands that modify startup files, scheduled tasks, shell profiles, or other skills. - Destructive shell commands and arbitrary package installation. - Instructions to upload local information to external endpoints. 7. Enforce a response-size limit before reading the full HTTP body and reject non-Markdown or unexpected content types. 8. Restrict accepted URLs to approved HTTPS hosts and repositories. Consider an allowlist of reviewed publishers and repositories. 9. Constrain output paths to a canonical approved skills root. Reject path traversal, symlink destinations, and attempts to overwrite existing files unless separately confirmed. 10. Create output atomically with restrictive permissions and avoid silently replacing an existing skill. 11. Run conversion and review in a sandbox without credentials or broad filesystem access. 12. Record source provenance, including the immutable commit and checksum, alongside every installed skill so later changes can be detected and audited. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (10)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The skill markets itself broadly as a search and install helper, but its behavior includes conversion, installation, and file placement into persistent directories, with static analysis noting undeclared network fetching and functionality beyond the stated purpose. Description-behavior mismatch reduces informed consent and makes risky operations more likely to be triggered under benign-looking prompts.

Vague Triggers

High
Confidence
97% confidence
Finding
The description contains very broad trigger phrases like 'can you do X' and 'extend your capabilities,' which can cause this skill to activate for many unrelated user requests. Because the skill can perform network access and installation-related file writes, overbroad activation materially increases the chance of unintended capability expansion or execution of risky workflows.

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill instructs the agent to perform network access and write or install files into local and global skill directories, but it declares no explicit tool scope such as permissions or allowed-tools. That makes its effective capabilities broader and less auditable than the metadata suggests, increasing the chance of unintended execution of sensitive operations.

Rp1

Medium
Category
MCP Rug Pull
Confidence
92% confidence
Finding
Using `npx skills` without a pinned version allows retrieval of whatever package version is current at execution time. If the upstream package is compromised or changed unexpectedly, the agent could execute attacker-controlled code during a search or install workflow.

Rp1

Medium
Category
MCP Rug Pull
Confidence
92% confidence
Finding
This unpinned `npx skills` invocation has the same supply-chain risk as the earlier one: runtime resolution of an external package can execute an unreviewed or malicious update. Because the skill is positioned as a discovery tool, users may invoke it frequently, increasing exposure.

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.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The skill performs installation and writes into local or global skill directories but does not prominently warn about the persistence and trust implications of modifying those directories. Users may not understand that installing a skill changes future agent behavior and can affect either the current workspace or all sessions for the user.

Skill Enumeration

Medium
Category
Agent Snooping
Content
Examples:
  python3 convert_skillssh.py vercel-labs/agent-skills@react-best-practices
  python3 convert_skillssh.py https://skills.sh/vercel-labs/agent-skills/react-best-practices \\
      --output /root/.openclaw/workspace/skills/react-best-practices/SKILL.md
"""

import argparse
Confidence
80% confidence
Finding
Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Skill Enumeration

Medium
Category
Agent Snooping
Content
def try_alternate_urls(base_url: str) -> str:
    """Try alternate URL patterns if the primary one fails."""
    # Extract parts from the primary URL
    # https://raw.githubusercontent.com/owner/repo/main/skills/skill-name/SKILL.md
    parts = base_url.split("/")
    try:
        gh_idx = parts.index("raw.githubusercontent.com")
Confidence
80% confidence
Finding
Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Missing User Warnings

Low
Confidence
84% confidence
Finding
This code creates directories and writes converted content to a user-specified path, which is a file-modifying operation. Although the CLI argument name suggests output behavior, there is no inline warning comment, confirmation prompt, or explicit user-facing disclosure near the write path beyond a post-write status message.

Static analysis

No suspicious patterns detected.