Vet a skill before quay add
quay add fetches Markdown that your agent will execute with implicit trust.
quay verifies provenance and integrity — that the file you got is the file the
remote has. It does not read the skill and judge whether the instructions inside
it are hostile. Nothing in quay does.
SkillSpector (NVIDIA, Apache-2.0) does that part: 68 patterns across 17 categories — prompt injection, data exfiltration, privilege escalation, supply chain, excessive agency, MCP tool poisoning, plus AST-level dangerous-code detection and taint tracking.
The two tools are not integrated and do not need to be. Run the scan, then add.
Scan before you add
# Scan the source repo without downloading it yourself
skillspector scan https://github.com/someone/their-skill --no-llm
# Happy with it?
quay add their-skill
Exit codes: 0 = risk score ≤ 50, 1 = over threshold, 2 = scan error. The
threshold is hard-coded in SkillSpector; there is no flag to move it.
--no-llm runs static analysis only. Without it, skill content is sent to an
LLM provider for semantic evaluation — worth it for a manual review of something
you distrust, wrong for anything automatic.
Audit what you already installed
# Everything in canonical, one summary table
skillspector scan .agents/skills/ --recursive --no-llm
Findings you have triaged and accepted go in a baseline so re-scans surface only what is new:
skillspector baseline .agents/skills/ -o .skillspector-baseline.yaml
skillspector scan .agents/skills/ --recursive --no-llm --baseline .skillspector-baseline.yaml
Commit the baseline.
Gate it in CI
If you want this on every PR, four things are worth knowing before you write the workflow — each one cost us a red run:
--recursivewith--format sarifwrites concatenated text, not merged SARIF. Scan each skill directory separately.- Uploading a directory of per-skill SARIF files is rejected: code scanning
refuses multiple runs sharing a category. Fold them into a single run (dedupe
tool.driver.rulesbyid) and upload one file. - Findings carry uris relative to the scanned dir (a bare
SKILL.md), so rewrite them to repo-root-relative or every annotation lands on a path that doesn't exist. - Exit code 1 means "over threshold"; anything else means the scan didn't happen. Treat them differently — an unscanned skill is not a safe skill, and collapsing both into one branch is how a crashed scanner produces a green check.
Pin the install to a commit. SkillSpector publishes no tagged releases and moves
fast; an unpinned git+https:// install means your CI gate changes without you.
Let the agent do it
Both tools ship MCP servers — quay mcp and skillspector mcp. An agent with
both configured can scan and then install in one flow, gating the install on the
result, with no wiring between the projects:
{
"mcpServers": {
"quay": { "command": "quay", "args": ["mcp"] },
"skillspector": { "command": "skillspector", "args": ["mcp"] }
}
}
Requires the MCP extra: uv tool install 'skillspector[mcp] @ git+https://github.com/NVIDIA/skillspector.git'.
Why this isn't built into quay
A pre-install gate inside quay add would mean a Python runtime in a Rust
tool's install path, and a hard dependency on a CLI contract that has no
released version yet. Scanning stays a separate step you compose, by choice.