Back to skill

Security audit

Openclaw Skill Scanner

Security checks for vulnerabilities and agentic risk

Overview

This is a defensive skill, but its security gate can allow unscanned installs and it runs mutable remote tooling, so it needs review before use.

Review before installing. Fix the scan wrapper so scanner errors and malformed reports fail closed, pin the ClawHub and scanner dependencies to reviewed versions, and only enable the systemd auto-quarantine path if you are comfortable with installed skills being moved automatically after high or critical findings.

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)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/scan_and_add_skill.sh:95
Finding
Scanner Errors Fail Open and Allow Unscanned Skills to Be Installed<![CDATA[ ## Vulnerability Details **File Location**: `scripts/scan_and_add_skill.sh:95-148` **Vulnerability Type**: Fail-open security validation **Risk Level**: High ### Vulnerable Code ```bash SCAN_OUT="$OUT_DIR/${DEST_NAME}_$TS.txt" set +e "$UV_BIN" run skill-scanner scan "$SRC_DIR" --format markdown --detailed --output "$REPORT" >"$SCAN_OUT" 2>&1 SCAN_CODE=$? set -e # Decide install policy: # - BLOCK only if High or Critical findings exist (unless --force) # - ALLOW Medium/Low/Info, but warn. # # Reports are markdown; we scrape the "Findings by Severity" summary. get_count() { local label="$1" # Matches lines like: "- **High:** 3" or "- **Critical:** 0" local n n=$(grep -E "\*\*${label}:\*\*" "$REPORT" 2>/dev/null | head -n 1 | sed -E 's/.*\*\*[^:]+:\*\* *([0-9]+).*/\1/') || true if [[ -z "${n:-}" || ! "$n" =~ ^[0-9]+$ ]]; then echo 0 else echo "$n" fi } CRITICAL_COUNT=$(get_count "Critical") HIGH_COUNT=$(get_count "High") MEDIUM_COUNT=$(get_count "Medium") LOW_COUNT=$(get_count "Low") INFO_COUNT=$(get_count "Info") DEST_BASE="$STATE_DIR/skills" DEST_DIR="$DEST_BASE/$DEST_NAME" BLOCKED=0 if [[ "$CRITICAL_COUNT" -gt 0 || "$HIGH_COUNT" -gt 0 ]]; then BLOCKED=1 fi if [[ $BLOCKED -eq 0 ]]; then mkdir -p "$DEST_BASE" if [[ -e "$DEST_DIR" ]]; then echo "ERROR: Destination already exists: $DEST_DIR" >&2 echo "Remove/rename it, or choose a different --name." >&2 exit 3 fi if [[ "$MEDIUM_COUNT" -gt 0 || "$LOW_COUNT" -gt 0 || "$INFO_COUNT" -gt 0 ]]; then echo "Scan result: ALLOWED WITH WARNINGS (no High/Critical)" echo " Critical: $CRITICAL_COUNT High: $HIGH_COUNT Medium: $MEDIUM_COUNT Low: $LOW_COUNT Info: $INFO_COUNT" else echo "Scan result: CLEAN (no findings)" fi # Copy the directory in a simple, predictable way. cp -a -- "$SRC_DIR" "$DEST_DIR" ``` ### Technical Analysis The script temporarily disables immediate error handling, invokes the scanner, and captures its exit status in `S ...[truncated 2080 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Make scan validation fail closed: 1. Reject any nonzero scanner exit status before parsing the report. 2. Require the report to exist, be a regular file, and be nonempty. 3. Require every expected severity field to be present exactly once and contain a valid nonnegative integer. 4. Reject malformed, incomplete, or unexpected report formats instead of converting parsing failures to zero. 5. Prefer a stable machine-readable format such as JSON over scraping Markdown. 6. Record scanner failures separately from positive security findings so operators can distinguish operational errors from detected threats. 7. Add regression tests covering scanner crashes, absent reports, empty reports, changed report formats, and malformed candidate Skills. Example hardening pattern: ```bash set +e "$UV_BIN" run skill-scanner scan "$SRC_DIR" \ --format markdown --detailed --output "$REPORT" \ >"$SCAN_OUT" 2>&1 SCAN_CODE=$? set -e if [[ $SCAN_CODE -ne 0 ]]; then echo "ERROR: Skill scan failed with status $SCAN_CODE; installation denied." >&2 echo "Scanner output: $SCAN_OUT" >&2 exit 4 fi if [[ ! -f "$REPORT" || ! -s "$REPORT" ]]; then echo "ERROR: Scanner did not produce a valid report; installation denied." >&2 exit 4 fi ``` The severity parser should also return an error rather than zero when a field cannot be found or parsed. ]]>

T08 · Insecure Dependencies

Warning
Location
scripts/clawhub_scan_install.sh:92
Finding
Unpinned Remote Scanner and ClawHub Dependencies Are Executed<![CDATA[ ## Vulnerability Details **File Location**: `scripts/clawhub_scan_install.sh:92`; `SKILL.md:31-33` **Vulnerability Type**: Unpinned third-party dependency execution **Risk Level**: Medium ### Vulnerable Code From `scripts/clawhub_scan_install.sh:90-92`: ```bash # NOTE: --workdir controls where clawhub writes its metadata; --dir is where skills land. # We keep everything inside the staging dir. ( cd "$STAGE_DIR" && npx -y clawhub --workdir "$STAGE_DIR" --dir skills "${INSTALL_ARGS[@]}" ) ``` From `SKILL.md:31-33`: ```bash git clone https://github.com/cisco-ai-defense/skill-scanner cd skill-scanner CC=gcc uv sync --all-extras ``` ### Technical Analysis The installation workflow invokes `npx -y clawhub` without an exact package version or integrity constraint. Depending on the local package state and npm resolution behavior, `npx` may retrieve and execute the currently published package from the registry. The documented scanner setup similarly clones the current default branch of the remote repository rather than an audited commit or signed release. It then resolves and installs the repository's dependencies with `uv sync --all-extras`. These operations make the effective code executed by the workflow mutable after this Skill has been reviewed. A compromised upstream repository, compromised package publisher, malicious dependency update, or account takeover could cause different code to execute on later installations. This concern applies to the tooling itself, which runs before or as part of the security gate. Staging the downloaded Skill does not sandbox the `npx` process; the package executes with the invoking user's normal permissions. ### Attack Path 1. An upstream repository, npm package, dependency, or publisher account is compromised, or an unsafe update is released. 2. A user follows the documented setup procedure or runs `clawhub_scan_install.sh`. 3. `git clone` retrieves the current upstream branch, or `npx -y clawhub` resolves th ...[truncated 841 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin `clawhub` to an explicitly reviewed version, for example: ```bash npx -y clawhub@<audited-version> \ --workdir "$STAGE_DIR" --dir skills "${INSTALL_ARGS[@]}" ``` 2. Commit an npm lockfile where practical and enforce package integrity values. 3. Pin the scanner repository to an audited immutable commit or verified signed release: ```bash git clone https://github.com/cisco-ai-defense/skill-scanner cd skill-scanner git checkout --detach <audited-commit-sha> ``` 4. Verify release signatures or published checksums before installation. 5. Use the scanner's committed lockfile with frozen dependency resolution, rather than allowing dependency versions to drift. 6. Document a controlled dependency-update process that includes source review, checksum updates, and regression testing. 7. Consider installing trusted tooling in an isolated environment with limited filesystem, credential, and network access. 8. Avoid relying on mutable branch names or unqualified package names in security-sensitive setup instructions. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (11)

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
A second description-behavior mismatch similarly indicates the skill markets itself as enforcing pre-install scanning and auto-quarantine while apparently lacking those guarantees. For a supply-chain security skill, misleading claims are especially risky because operators may depend on it as a preventive control when it is only advisory or partial.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
A second description-behavior mismatch similarly indicates the skill markets itself as enforcing pre-install scanning and auto-quarantine while apparently lacking those guarantees. For a supply-chain security skill, misleading claims are especially risky because operators may depend on it as a preventive control when it is only advisory or partial.

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill declares shell-capable binaries and operational shell workflows but does not declare any tool scope or permission boundaries. In an agent skill ecosystem, missing explicit permissions weakens reviewability and may allow the skill to execute broader command behavior than users expect.

Session Persistence

Medium
Category
Rogue Agent
Content
Install the units (templates are in `references/`):
```bash
mkdir -p ~/.config/systemd/user
cp -a "$HOME/.openclaw/skills/skill-scanner-guard/references/openclaw-skill-scan."* ~/.config/systemd/user/

systemctl --user daemon-reload
Confidence
84% confidence
Finding
Creating user systemd configuration and installing unit templates into ~/.config/systemd/user is persistence setup. In a security-sensitive skill, this is contextually understandable, but it still modifies autostart behavior and expands the attack surface if those files are tampered with later.

Session Persistence

Medium
Category
Rogue Agent
Content
cp -a "$HOME/.openclaw/skills/skill-scanner-guard/references/openclaw-skill-scan."* ~/.config/systemd/user/

systemctl --user daemon-reload
systemctl --user enable --now openclaw-skill-scan.path
```

Behavior:
Confidence
86% confidence
Finding
Enabling a user systemd unit establishes persistence so the scanning service runs automatically on future changes and across sessions. Even though the purpose is defensive, persistence mechanisms are sensitive because they create continuously executing behavior and could be abused if the referenced service scripts or unit files are modified.

File System Enumeration

Medium
Category
Data Exfiltration
Content
```bash
systemctl --user status openclaw-skill-scan.path
journalctl --user -u openclaw-skill-scan.service -n 100 --no-pager
ls -la ~/.openclaw/skills-quarantine
```

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

Missing User Warnings

Medium
Confidence
89% confidence
Finding
This shell script performs a safety-critical file operation by moving skill directories into a quarantine location when scan results are high or critical. Although it emits stderr messages at runtime, there is no confirmation prompt and the header comments do not warn that the script will automatically relocate user files, which can affect user data and skill availability.

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.

Session Persistence

Medium
Category
Rogue Agent
Content
STATE_DIR="${OPENCLAW_STATE_DIR:-$HOME/.openclaw}"
WORKSPACE_DIR="${OPENCLAW_WORKSPACE_DIR:-$STATE_DIR/workspace}"
STAGE_ROOT="$WORKSPACE_DIR/.skill_stage"
mkdir -p "$STAGE_ROOT"
STAGE_DIR="$(mktemp -d -p "$STAGE_ROOT" "clawhub-${SLUG}-XXXXXXXX")"

cleanup() {
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.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding
The script executes `npx -y clawhub` without pinning a specific package version or integrity source. That makes installation behavior depend on the latest package resolution at runtime, which creates a supply-chain risk: a compromised or malicious upstream package version could be fetched and executed during skill installation.

Intent-Code Divergence

Low
Confidence
83% confidence
Finding
The help text says `--force` will install even if issues are found, implying a direct override path. In practice, the script first declares the scan `BLOCKED`, prints remediation steps, and only then performs the forced install at L170-L179. This is a documentation-to-behavior mismatch in the script's own intent description, though the eventual effect is still an override install.

Static analysis

No suspicious patterns detected.