SkillSpector: fail your CI build on a risky agent skill
Scan every skill you did not write with SkillSpector and gate CI on the result, so a malicious or vulnerable SKILL.md fails the build instead of running with your agent's permissions at runtime.
Run this workflow
CI-verified, 2/2 fixtures passing.
Build this with your agent
One copy-paste hands Claude Code, Codex, or Cursor the full recipe, steps included, nothing to fetch.
Intended Use
Anyone installing agent skills or MCP servers they did not author. CI validates the SARIF severity gate against fixtures: a CRITICAL finding (level error / security-severity 9.1) is blocked and a clean scan passes, exactly the logic you put after `skillspector scan --format sarif`. The real scan (install via uv, static analysis plus the optional LLM pass) is fenced.
Not for
- Treating a clean scan as a safety certificate, it is static analysis: strongest on code, weaker on non-English content, images, or behavior that only shows up at runtime
- Replacing least privilege, a skill still inherits your agent's file access and credentials, so scan AND scope it
The Stack
Tested Against
NVIDIA/SkillSpector (SARIF 2.1.0, 2026-06)node@20Side effects & data flow
- Network
- none, local only
- Writes
- ./risky.sarif, ./clean.sarif
- Credentials
- none required
Prerequisites
- uv (to actually install and run skillspector: uv tool install git+https://github.com/NVIDIA/skillspector.git)
Steps
- 1
Write the CI gate and prove it on a risky and a clean SARIF
SkillSpector emits SARIF 2.1.0 (skillspector scan ./skill --format sarif > out.sarif). The CI gate reads that SARIF and fails the build on any finding at level error or security-severity >= 7.0. CI here proves the gate blocks a CRITICAL skill and passes a clean one; the scan that produces the SARIF needs the tool installed and is fenced.
cat > risky.sarif <<'JSON' { "version": "2.1.0", "runs": [ { "tool": { "driver": { "name": "SkillSpector", "informationUri": "https://github.com/NVIDIA/SkillSpector" } }, "results": [ { "ruleId": "data-exfiltration", "level": "error", "properties": { "security-severity": "9.1" }, "message": { "text": "Skill posts file contents to an external host" } } ] } ] } JSON cat > clean.sarif <<'JSON' { "version": "2.1.0", "runs": [ { "tool": { "driver": { "name": "SkillSpector" } }, "results": [] } ] } JSON node -e ' const fs = require("fs"); function gate(path) { const doc = JSON.parse(fs.readFileSync(path, "utf8")); const runs = doc.runs || []; let worst = 0, blocked = false; for (const run of runs) { for (const r of (run.results || [])) { const sev = parseFloat((r.properties || {})["security-severity"] || "0") || 0; if (sev > worst) worst = sev; if (r.level === "error" || sev >= 7.0) blocked = true; } } return { blocked: blocked, worst: worst }; } function bad(m) { console.error("BAD: " + m); process.exit(1); } const risky = gate("risky.sarif"); const clean = gate("clean.sarif"); if (!risky.blocked) bad("gate let a CRITICAL skill through"); if (clean.blocked) bad("gate failed a clean scan"); console.log("gate OK: blocked the CRITICAL skill (severity " + risky.worst.toFixed(1) + "), passed the clean scan"); ' - 2
Run the real scan in CI (the model step, not checked by CI here)
Install the scanner (uv tool install git+https://github.com/NVIDIA/skillspector.git), then in your workflow run `skillspector scan ./path --format sarif > skillspector.sarif` on a directory, file, repo URL, or zip, and pipe it into the gate above. The static analysis plus optional LLM pass is fenced; only the gate logic is asserted here.
Eval, 2 fixtures
Last passed: verified todaygate-okcontainstimeout 30s · max $0Expected:
gate OK: blocked the CRITICAL skill (severity 9.1), passed the clean scanclean-exitexit_codetimeout 30s · max $0Expected:
0
Results
A 2026 study scanned 42,447 agent skills and found 26.1% had at least one vulnerability and 5.2% likely malicious intent, with executable-script skills 2.12x more likely to be vulnerable. SkillSpector emits SARIF 2.1.0 with a 0-100 risk score, so you can wire it into CI and fail on HIGH/CRITICAL. A clean scan lowers risk, it does not certify safety, so still prefer least privilege and read what you install.
Did this work for you?
Our CI checks the setup runs. You tell us if the whole thing worked. Tell us straight.
Related workflows
Liked this workflow?
Get new verified workflows in WebAfterAI, three issues a week (Tue, Thu, Sat).