Tools
Secure Plugin Installer
Audit and gate third-party Claude Code plugins / OpenClaw skills before enabling them: capability enumeration, categorised pattern scanning, commit pinning, hash-chained trust ledger, per-MCP-server approval.
Install
pip install skillspector`
README
# Secure Plugin Installer
Cross-platform skill for auditing and gating third-party packages —
**Claude Code plugins** (sourced from GitHub or any git-clonable URL) and
**OpenClaw / ClawHub skills** (typically installed as plain directories
under `/opt/<env>/workspace/skills/`).
This document is the **comprehensive reference** for humans. The
companion [`SKILL.md`](SKILL.md) is a compact agent-facing trigger that
describes the workflow at a high level; agents (Claude Code, OpenClaw,
etc.) read it to decide when and how to invoke the installer. If
something is brief in SKILL.md, the long-form explanation lives here.
---
## Contents
1. [What this is](#what-this-is)
2. [When this is invoked](#when-this-is-invoked)
3. [Quickstart (end-user examples)](#quickstart-end-user-examples)
4. [What "install" means in each profile](#what-install-means-in-each-profile)
5. [The 6-step workflow](#the-6-step-workflow)
6. [Trust ledger](#trust-ledger)
7. [Threat model — what this catches and doesn't](#threat-model)
8. [Architecture](#architecture)
9. [Required dependencies](#required-dependencies)
10. [Install destinations and workspace layout](#install-destinations-and-workspace-layout)
11. [Backup, rollback, version comparison, and collision policy](#backup-rollback-and-collision-policy)
12. [Operational notes](#operational-notes)
13. [Known limitations and open work](#known-limitations-and-open-work)
---
## What this is
A guarded install pipeline for third-party packages whose code will run
inside your agent's privileges (Claude Code or OpenClaw). Five layers,
each independently useful:
| Layer | What it does | Stops |
|---|---|---|
| **Hardened clone** | `git -c core.symlinks=false clone --depth=1 --no-tags --no-hardlinks` | Filesystem-traversal attacks via malicious symlinks; pollution of source repos via hardlinks |
| **Capability enumeration** | Parses declared hooks / MCP servers / postinstall scripts / permissions / build steps | Surfaces every auto-executing or privilege-granting declaration |
| **Categorised pattern scan** | 7 risk classes × ~40 detectors, severity-aware, location-demoted (docs/tests are MEDIUM→LOW) | Surfaces command-exec, network, encoded-payload, destructive, persistence, exfil, credential-access tells |
| **Trust ledger** | Append-only, SHA-256 hash-chained log of inspections and approvals; pins commit SHAs and marketplace sources | Tamper-detected if an entry is edited; SHA drift forces re-inspection; marketplace-source drift invalidates approvals |
| **Typed-confirmation install gate** | Demands the user type the exact slug back, plus a separate typed confirmation per declared MCP server | Rubber-stamp / accidental approvals |
There's also a **PreToolUse hook** on the claude-code profile that
intercepts `Edit`/`Write` of `settings.json` and blocks additions to
`enabledPlugins` whose slug isn't APPROVED in the trust ledger. The
OpenClaw analog isn't built yet (see [Known limitations](#known-limitations-and-open-work)).
## When this is invoked
Trigger this skill **whenever a user asks to install, audit, or
"security review" a third-party plugin or skill** — Claude Code or
OpenClaw. Skip only for packages you've already approved at the current
SHA / content hash (the trust ledger remembers).
If you ask an agent to install a ClawHub skill on a system where this
is registered, this gated workflow is the default path. If you want to
bypass it for a specific case, say so explicitly.
## Quickstart (end-user examples)
> All examples assume the `secure-plugin-installer` skill lives in your
> environment's skills directory. On Claude Code that's
> `~/.claude/skills/secure-plugin-installer/`; on OpenClaw it's
> `/opt/<env>/workspace/skills/secure-plugin-installer/`.
### Inspect a Claude Code plugin from GitHub
```
python3 scripts/safe_inspect.py everything-claude-code@everything-claude-code
```
(Or use the `.sh` wrapper: `bash scripts/safe_inspect.sh everything-claude-code@everything-claude-code`.)
### Inspect a locally-installed OpenClaw skill (no git history)
```
bash scripts/safe_inspect.sh --local /opt/openclaw-workspace/skills/superpowers --marketplace my-marketplace
```
Falls back to a SHA-256 content hash when no git history is present.
Writes the report to `<workspace>/plugin-inspect/<plugin>/REPORT.md`,
**not** into the source directory.
### Inspect again later (same SHA / same content)
```
bash scripts/safe_inspect.sh everything-claude-code@everything-claude-code
```
Short-circuits with:
```
Prior trust: APPROVED at 2026-05-14T18:13:34Z by alice (same SHA).
*** Already trusted at this SHA — inspection skipped. ***
```
Pass `--force` to re-scan anyway.
### Inspect after an upstream commit (SHA drift)
Same command. Output shows:
```
Prior trust: SHA DIFFERS (4423f10cfb9e -> 364245445f1f). Prior approval (if any) is INVALID.
--- Diff vs trusted SHA (--stat) ---
README.md | 2 ++
1 file changed, 2 insertions(+)
Pattern scan will be scoped to changed files. Pass --force for a full re-scan.
```
### Approve + install (claude-code profile)
Interactive:
```
python3 scripts/install.py everything-claude-code@everything-claude-code
```
Non-interactive (for automation):
```
python3 scripts/install.py everything-claude-code@everything-claude-code \
--confirm everything-claude-code@everything-claude-code \
--confirm-mcp <server1> --confirm-mcp <server2> \
--approver alice
```
### Roll back
```
python3 scripts/rollback.py everything-claude-code@everything-claude-code
```
Surgically removes the slug from `enabledPlugins` and also removes the
marketplace entry from `extraKnownMarketplaces` if no other plugin
references it. Idempotent. Use `--dry-run` to preview.
### Verify trust-ledger integrity
```
python3 scripts/trust_verify.py
```
Exit 0 if the SHA-256 hash chain is intact; non-zero with the broken
entry index otherwise.
### Inspect every skill in an environment
```
for d in /opt/openclaw-workspace/skills/*/; do
bash scripts/safe_inspect.sh --force --local "$d" --marketplace my-marketplace 2>&1 |
grep -E "^Recommendation:"
done
```
Per-skill recommendation, suitable for compliance-style audits.
## What "install" means in each profile
This is one of the bigger conceptual cliffs to be aware of — the two
runtime profiles have different installation models, and the installer
**only fully implements the claude-code model right now**.
### Claude Code profile
- Plugins are **referenced** in `~/.claude/settings.json` under
`enabledPlugins` (a dict of slug → bool) and `extraKnownMarketplaces`
(a dict of marketplace-name → source descriptor).
- The plugin **source files** live elsewhere — fetched from the
marketplace's git source at runtime by Claude Code itself.
- "Install" = add to `enabledPlugins` (+ register marketplace if not
already registered). That's what `install.py` does.
- "Uninstall" = remove from `enabledPlugins` (+ remove orphaned
marketplace). That's what `rollback.py` does.
- The inspector clones the source to a workspace location for review
but **does not copy it anywhere "installed"** — Claude Code does that
on its own.
### OpenClaw profile
- Skills are **directories** under `/opt/<env>/workspace/skills/`.
- They are auto-loaded by openclaw at session start; there's no
separate "enabled / disabled" gate analogous to `enabledPlugins`.
- The canonical config at `/opt/openclaw-config/openclaw.json` has
`skills` and `plugins` top-level keys, but their schema doesn't match
Claude Code's `enabledPlugins`/`extraKnownMarketplaces`.
- **`install.py` does not currently work as designed on this profile.**
It looks for `enabledPlugins`/`extraKnownMarketplaces` keys that
aren't there and fails the marketplace-not-registered precondition.
See [Known limitations](#known-limitations-and-open-work).
- What still works on OpenClaw:
- **Inspection** (`safe_inspect.py`) — fully functional. Reads,
enumerates capabilities, scans patterns, records in trust ledger.
- **Trust ledger** — written and verified normally. Approvals can be
recorded directly with `trust.py approve`.
- **Reporting** — REPORT.md generates correctly.
### OpenClaw install flow
`install.py` is profile-aware (since v1.1.0). On OpenClaw it skips the
settings mutation, confirms the skill is present on disk, and records the
approval in the trust ledger:
1. `safe_inspect.sh --local /opt/<env>/workspace/skills/<name>` — inspect
2. Review the REPORT.md
3. `python3 scripts/install.py <name>@<env> --confirm <name>@<env> --approver <your-name>`
— typed-confirmation gate, records approval (override the skills dir with
`--skills-dir` if needed). Recording approval directly with
`python3 scripts/trust.py approve <name>@<env> <your-name>` remains a valid
shortcut.
4. The skill is file-system-installed; no settings mutation needed.
5. Restart the env's container (if the skill wasn't there at session start).
## The 6-step workflow
These map directly onto `SKILL.md`'s numbered steps; this section
explains the rationale.
1. **Research.** Identify the package and where it lives. Surface
provenance signals up front (stars, age, owner type) so the user
isn't approving blindly.
2. **Inspect.** Clone (or read in-place via `--local`), enumerate
declared capabilities, run categorised pattern scan, fetch GitHub
provenance. Write REPORT.md. Record an **inspection** entry in the
trust ledger for the plugin and each declared MCP server.
3. **Install gate.** Present REPORT.md to the user. The
**Recommendation** section distills the findings:
- `MINIMAL RISK SURFACE` — no declared capabilities, no pattern findings
- `REVIEW RECOMMENDED` — MEDIUM-only findings (pattern scan or the
optional SkillSpector scanner) or normal capabilities
- `REQUIRES HUMAN REVIEW` — HIGH pattern findings OR any HIGH
SkillSpector finding OR auto-executing capabilities (hook, MCP
server, postinstall) OR broad permission rules (Bash(*), etc.). Pe
... (truncated)
tools
Comments
Sign in to leave a comment