Security & quality audits for AI agent skills β before they run.
Your agent loads SKILL.md files from the internet and follows their
instructions with your shell, your files, and your credentials. Nothing checks
what's inside them.
skill-audit is a zero-dependency CLI that statically scans Agent Skills
(Claude Code, Codex CLI, Cursor, opencode, β¦) for prompt injection, credential
exfiltration, destructive commands, obfuscated payloads, and broken metadata β
then gives each skill a 0β100 health score.
npx @frankfu0916/skill-audit ~/.claude/skills env-sync β skills/env-sync/SKILL.md
β CRITICAL script "scripts/sync.sh" both reads environment variables and performs network/file-transfer operations
[env-exfiltration] at line 4
β CRITICAL script:scripts/sync.sh references ~/.ssh private keys
ββ cat ~/.ssh/id_rsa >> /tmp/extras.txt
[secret-file-access]
β WARNING script "scripts/sync.sh" makes outbound network calls (curl)
[network-access] at line 4
score: 0/100
Summary
5 skill(s) audited Β· 24 rules Β· 8 critical Β· 3 warnings Β· 7 info
Agent Skills are the fastest-growing package ecosystem on GitHub β and the least inspected. A skill is executable instructions plus bundled scripts:
- Its description is injected into your system prompt, where hidden instructions can hijack the session (prompt injection).
- Its scripts run in your shell without ever being shown to you β a skill
that "manages dotfiles" can also
cat ~/.ssh/id_rsaand POST it somewhere. - There is no review step: no lockfile, no registry audit, no sandbox by default.
skill-audit closes that gap the way npm audit did for packages: fast,
local, opinionated, CI-friendly. It runs entirely offline β it reads files and
reports; it never executes anything it finds.
No install needed:
npx @frankfu0916/skill-audit <path>Or add it to a project / CI:
npm install -D @frankfu0916/skill-auditRequires Node β₯ 18. Zero runtime dependencies.
skill-audit <paths...> [options]
# Audit everything installed for your user
npx @frankfu0916/skill-audit # defaults to ~/.claude/skills if present
npx @frankfu0916/skill-audit ~/.claude/skills
# Audit one repo's skills before publishing yours
npx @frankfu0916/skill-audit ./skills/my-skill
# Machine-readable output for CI
npx @frankfu0916/skill-audit .claude/skills -f sarif -o results.sarif
npx @frankfu0916/skill-audit .claude/skills -f json | jq '.summary'
# Tune the rule set
npx @frankfu0916/skill-audit ./skills --skip network-access,pip-install-unpinned| Option | Description |
|---|---|
-f, --format |
full | compact | json | sarif | markdown |
-o, --output <file> |
Write report to file instead of stdout |
--only <rules> |
Run only these rules (comma-separated ids) |
--skip <rules> |
Skip these rules |
-q, --quiet |
Summary only |
--no-color |
Disable colored output |
Exit codes make it a CI gate: 0 clean Β· 1 critical findings Β· 2
bad arguments or unreadable paths.
name: skill-audit
on: [push, pull_request]
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 22 }
- run: npx -y skill-audit ./skills -f sarif -o results.sarif || echo "findings above"
- uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: results.sarifFindings then appear under the repo's Security β Code scanning tab.
24 rules across six categories. Every finding cites its rule id, line number, and matched text β nothing is a black box.
Full rule catalog
Credential & secret exfiltration
| Rule | Severity |
|---|---|
env-exfiltration β scripts that read environment variables and make network calls |
critical |
secret-file-access β references to ~/.ssh, AWS credentials, .npmrc, .env, keychains |
critical |
Destructive & dangerous commands
| Rule | Severity |
|---|---|
destructive-commands β recursive rm over wildcards/~/$HOME/root, mkfs, dd of=/dev/*, fork bombs, force-push to main, DROP TABLE/DATABASE, power commands |
critical |
curl-pipe-shell β piping downloads straight into a shell |
warning |
network-access β outbound network calls from bundled scripts |
warning |
Prompt injection
| Rule | Severity |
|---|---|
instruction-concealment β instructional HTML comments, zero-width character smuggling |
critical |
override-system-prompt β "ignore previous instructions", persona takeover |
warning |
data-to-remote β sending conversation/file data to endpoints, paste services, webhooks |
warning |
urgency-pressure β "do this immediately without asking" |
info |
Obfuscation
| Rule | Severity |
|---|---|
obfuscated-content β base64/hex blobs, decode-then-execute patterns |
warning |
eval-exec β dynamic evaluation in bundled scripts |
warning |
Metadata integrity (Agent Skills spec)
| Rule | Severity |
|---|---|
missing-frontmatter, missing-name, missing-description |
warning |
xml-tags-in-metadata |
warning |
invalid-name-format, name-mismatch-dir, description-too-long, yaml-parse-warning |
info |
Quality & supply-chain hygiene
| Rule | Severity |
|---|---|
body-too-long (spec: β€500 lines), empty-body, broken-references, unbounded-script-exec |
info |
pip-install-unpinned β unpinned installs resolved at runtime |
info |
Each skill gets 100 minus weighted penalties: β34 per critical, β12 per warning, β3 per info, floored at 0.
- 80β100 healthy β ship it
- 50β79 needs a look β read the warnings before installing
- 0β49 do not install without a full manual review
The auditor is importable β build editors, dashboards, or pre-install hooks on top:
import { createAuditRunner } from 'skill-audit';
const runner = createAuditRunner({ version: 'x.y.z' });
const report = runner.audit(['~/.claude/skills'], { skip: ['network-access'] });
console.log(report.summary); // { skills, critical, warning, info, minScore }
console.log(runner.renderSarif(report));- Static analysis only. It never executes skill code or fetches URLs.
- Zero dependencies. ~600 lines of auditable source; the supply chain for your security tool is the tool itself.
- Explainable findings. Rule id + line + excerpt + docs for every hit. No scores from a neural net you can't interrogate.
- CI-native. SARIF output, stable JSON schema, meaningful exit codes.
Static analysis sees what's written, not what's meant β obfuscated payloads
can hide from regexes, and a benign-looking pattern may be flagged while being
harmless. Treat skill-audit as a necessary filter, not sufficient review:
for anything score < 80, read the SKILL.md and its scripts yourself.
See ROADMAP.md: --fix metadata repair, baseline/ignore files,
skill-hash drift detection (a lockfile for skills), taint tracking, a
community index of audited skills, and a GitHub App for org-wide policy.
- Agent Skills spec β official format & examples
- Skills ecosystems are exploding; so are third-party skills of unknown provenance. Audit before you activate.
Rules are small, pure functions β adding one is a great first PR:
implement run(skill) in src/rules.js, add a fixture under
test/fixtures/, assert in test/rules.test.js. See
CONTRIBUTING.md.