SecurityOpen SourceFreeActiveMachine-verified· intermediate · ~15 min setup

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.

by Shilpa Mitra· verified today· v1.0.0

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@20

Side 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. 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. 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 today
  • gate-okcontainstimeout 30s · max $0

    Expected: gate OK: blocked the CRITICAL skill (severity 9.1), passed the clean scan

  • clean-exitexit_codetimeout 30s · max $0

    Expected: 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).