Skills skill-vettr
Static analysis security scanner for third-party OpenClaw skills. Detects eval/spawn risks, malicious dependencies, typosquatting, and prompt injection patterns before installation. Use when vetting skills from ClawHub or untrusted sources.
git clone https://github.com/openclaw/skills
T=$(mktemp -d) && git clone --depth=1 https://github.com/openclaw/skills "$T" && mkdir -p ~/.openclaw/skills && cp -r "$T/skills/britrik/skill-vettr" ~/.openclaw/skills/openclaw-skills-skill-vettr && rm -rf "$T"
skills/britrik/skill-vettr/skill.mdskill-vettr v2.0.3
Security scanner for third-party OpenClaw skills. Analyses source code, dependencies, and metadata before installation using tree-sitter AST parsing and regex pattern matching.
Installation
npm install
This installs all Node.js dependencies, including tree-sitter
.wasm grammar files required at runtime for AST-based analysis. The .wasm files are located in node_modules and must be present for the skill to function.
⚠️ Install safety:
runs dependency lifecycle scripts, which can execute arbitrary code. For stronger isolation, runnpm install— but note that tree-sitter native/WASM artifacts may not build, breaking AST analysis. Prefer installing inside a container or VM when possible.npm ci --ignore-scripts
External Binaries
The
vet-url and vet-clawhub commands invoke external binaries via execSafe (which uses execFile — no shell is spawned). Only the following commands are permitted:
| Binary | Used By | Purpose |
|---|---|---|
| | Clone URLs (with hooks disabled) |
| | Download archive URLs |
| | Extract downloaded archives |
| | Fetch skills from ClawHub registry |
The
/skill:vet command (local path vetting) requires only node and no external binaries.
Commands
— Vet a local skill directory/skill:vet --path <directory>
— Download and vet from URL/skill:vet-url --url <https://...>
— Fetch and vet from ClawHub/skill:vet-clawhub --skill <slug>
Detection Categories
| Category | Method | Examples |
|---|---|---|
| Code execution | AST | eval(), new Function(), vm.runInThisContext() |
| Shell injection | AST | exec(), execSync(), spawn("bash"), child_process imports |
| Dynamic require | AST | require(variable), require(templateString) |
| Prototype pollution | AST | proto assignment |
| Prompt injection | Regex | Instruction override patterns, control tokens (in string literals) |
| Homoglyph attacks | Regex | Cyrillic/Greek lookalike characters in identifiers |
| Encoded names | Regex | Unicode/hex-escaped "eval", "exec" |
| Credential paths | Regex | Cloud and SSH credential directory references, system credential store access |
| Network calls | AST | fetch() with literal URLs (checked against allowlist) |
| Malicious deps | Config | Known bad packages, lifecycle scripts, git/http deps |
| Typosquatting | Levenshtein | Skill names within edit distance 2 of targets |
| Dangerous permissions | Config | shell:exec, credentials:read in SKILL.md |
Limitations
⚠️ This is a heuristic scanner with inherent limitations. It cannot guarantee safety.
- Static analysis only — Cannot detect runtime behaviour (e.g., code that fetches malware after install)
- Evasion possible — Sophisticated obfuscation or multi-stage string construction can evade detection
- JS/TS only — Binary payloads, images, and non-text files are skipped
- Limited network detection — Only detects
with literal URL strings; misses axios, http module, dynamic URLsfetch() - No sandboxing — Does not execute or isolate target code
- Comment scanning — Prompt injection detection scans string literals, not comments
- Filesystem scope —
downloads and extracts remote archives into a temp directory;vet-url
accepts paths undervet
,os.tmpdir()
, and~/.openclaw
by default. Set~/Downloads
in config to also permitallowCwd: true
(see Configuration below)process.cwd() - External binary trust —
andvet-url
invokevet-clawhub
,git
,curl
, andtar
viaclawhub
. These binaries must be trusted and present onexecFilePATH
For high-security environments, combine with sandboxing, network isolation, and manual source review. Run inside a disposable container when vetting untrusted URLs.
Configuration
allowCwd
allowCwdBy default,
process.cwd() is not included in the set of allowed vetting roots. The default allowed roots are:
os.tmpdir()~/.openclaw~/Downloads
To allow vetting paths under the current working directory, set
allowCwd: true in your vetting config:
{ "allowCwd": true }
⚠️ Security implication: Enabling
means the scanner will accept any path under the directory you launched it from. If you run fromallowCwdor/, this effectively grants access to your entire filesystem. Only enable this when running from a scoped project directory or inside a container.$HOME
.vettrignore
.vettrignorePlace a
.vettrignore file in the root of the skill directory being scanned to exclude files or directories from analysis. This is useful for excluding test fixtures that contain deliberate malicious patterns.
Format
- One glob pattern per line
- Lines starting with
are comments# - Empty lines are ignored
- Patterns ending with
match entire directories/
matches any sequence of non-separator characters*
matches any sequence including path separators (recursive)**
matches a single non-separator character?
Example
# Exclude test fixtures containing deliberate prompt injection vectors test/fixtures/ # Exclude generated files dist/ *.min.js
If the
.vettrignore file is unreadable or contains invalid UTF-8, the engine logs an INFO-level warning and proceeds with a full scan.