Security scanner for AI agent skills. Detect vulnerabilities, malicious patterns, and security risks.
Security scanner for AI agent skills. Detect vulnerabilities, malicious patterns, and security risks.
Security scanner for AI agent skills. Detect vulnerabilities, malicious patterns, and security risks before installing agent skills.
AI agent skills (used by Claude Code, Codex CLI, Gemini CLI, etc.) execute with implicit trust and minimal vetting. Research shows that 26.1% of skills contain vulnerabilities and 5.2% show likely malicious intent.
SkillSpector helps you answer: "Is this skill safe to install?"
SkillSpector is part of the NVIDIA Verified Skills pipeline, which scans, evaluates, and signs agent skills before publication. Skills that pass are published to the NVIDIA skills catalog.
Open-source software notice: This project will download and install additional third-party open source software projects. Review the license terms of these open source projects before use.
Create and activate a virtual environment first (all make targets assume the venv is active). Use uv or pip; the Makefile uses uv if available, otherwise pip.
Quick install with uv (CLI-only):
uv tool install git+https://github.com/NVIDIA/skillspector.git
# Update later: uv tool update skillspector
If you plan to run skillspector mcp, install the MCP extra at install time:
uv tool install 'skillspector[mcp] @ git+https://github.com/NVIDIA/skillspector.git'
From source:
# Clone the repository
git clone https://github.com/NVIDIA/skillspector.git
cd skillspector
# Create and activate virtual environment
uv venv .venv && source .venv/bin/activate
# or: python3 -m venv .venv && source .venv/bin/activate
# Install for production use
make install
# Or install with development dependencies
make install-dev
Run SkillSpector without installing Python by building it locally from the included Dockerfile. The image is based on the Docker Official Python 3.12-slim-bookworm image.
Build the image:
make docker-build
# or: docker build -t skillspector .
Scan a local directory by mounting your current directory into /scan, the container's working directory:
docker run --rm -v "$PWD:/scan" skillspector scan ./my-skill/ --no-llm
Scan with LLM analysis by passing credentials with a local .env file:
cat > .env <<'EOF'
SKILLSPECTOR_PROVIDER=anthropic
ANTHROPIC_API_KEY=sk-ant-...
EOF
docker run --rm \
-v "$PWD:/scan" \
--env-file .env \
skillspector scan ./my-skill/
Or pass credentials directly from your shell environment:
docker run --rm \
-v "$PWD:/scan" \
-e SKILLSPECTOR_PROVIDER=anthropic \
-e ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY" \
skillspector scan ./my-skill/
Write a report to the host filesystem by writing to the mounted directory:
docker run --rm \
-v "$PWD:/scan" \
skillspector scan ./my-skill/ --no-llm --format json --output report.json
Optional alias for repeated static scans:
alias skillspector-docker='docker run --rm -v "$PWD:/scan" skillspector'
skillspector-docker scan ./my-skill/ --no-llm
# Scan a local skill directory
skillspector scan ./my-skill/
# Scan a single SKILL.md file
skillspector scan ./SKILL.md
# Scan a Git repository
skillspector scan https://github.com/user/my-skill
# Scan a zip file
skillspector scan ./my-skill.zip
SkillSpector enforces two independent caps on remote and archive inputs to bound the impact of oversized downloads and zip bombs:
INGEST_MAX_BYTES (100 MiB) — applied to streamed URL downloads, total uncompressed size of zip archives, and post-clone disk usage of Git repos.INGEST_MAX_ZIP_MEMBERS (10,000) — caps the number of entries in a single zip.Note that the per-file 1 MB analysis cap (MAX_FILE_BYTES) is a separate, downstream limit: it bounds what individual analyzers will read out of an already-ingested directory. The ingest caps above bound how much content can land on disk in the first place. A breach of either ingest cap fails closed with an IngestLimitExceededError.
# Terminal output (default) - pretty formatted
skillspector scan ./my-skill/
# JSON output - machine readable
skillspector scan ./my-skill/ --format json --output report.json
# Markdown output - for documentation
skillspector scan ./my-skill/ --format markdown --output report.md
# SARIF output - for CI/CD integration and IDE tooling
skillspector scan ./my-skill/ --format sarif --output report.sarif
Scan entire directories of skills in parallel from contrib/batch_scan/:
python -m contrib.batch_scan.batch_scan ./my-skills/ --no-llm
python -m contrib.batch_scan.batch_scan ./my-skills/ --workers 20 -f json -o report.json
python -m contrib.batch_scan.batch_scan ./tests/fixtures/ -f terminal --workers 20
Supports multilingual detection (zh/ja/ko) and terminal/JSON/Markdown output.
For LLM scans with higher concurrency, configure multiple API keys following
.env.example — the pool improves throughput
and resilience, provided the keys don't share an account-level rate limit.
See the contrib guide for details.
Note on LLM support: The default configuration targets DeepSeek as the cheapest public option. DeepSeek-Chat is expected to sunset, and the contributor does not have hardware to test against local models. The batch scanner was originally tested with OpenAI-compatible endpoints — DeepSeek's lack of structured-output support required manual JSON-parsing patches. If you can contribute a more universal backend (Ollama, vLLM, or a different provider), PRs are very welcome.
Suppress known/accepted findings so the risk score reflects only un-triaged issues and re-scans surface only new findings. See the suppression guide for the full reference.
# Accept all current findings into a baseline (run once), then commit it.
skillspector baseline ./my-skill/ -o .skillspector-baseline.yaml
# Scan against the baseline — only NEW findings are reported and scored.
skillspector scan ./my-skill/ --baseline .skillspector-baseline.yaml
# Review what was suppressed (still excluded from the score).
skillspector scan ./my-skill/ --baseline .skillspector-baseline.yaml --show-suppressed
A baseline can also use drift-tolerant glob rules (by rule id, file path, or
message) — see .skillspector-baseline.example.yaml.
Exact fingerprint baselines are evidence-bound: changing the scanned source or
SkillSpector version keeps the finding active until it is reviewed again.
When a selected baseline or baseline output is stored inside the skill
directory, SkillSpector excludes that exact file from content analysis so its
suppression text cannot create findings or enter regenerated fingerprints;
sibling files remain in normal scan scope.
For the best results, configure an OpenAI-compatible LLM endpoint for
semantic analysis. Pick a provider with SKILLSPECTOR_PROVIDER; hosted providers ship bundled default models, while CLI providers fall back to the local runtime's default model unless SKILLSPECTOR_MODEL is set. SkillSpector also works against
local OpenAI-compatible servers (Ollama, vLLM, llama.cpp) and managed
inference gateways.
SKILLSPECTOR_PROVIDER)
Credential env var
Endpoint
Default model
openai
OPENAI_API_KEY (+ optional OPENAI_BASE_URL)
api.openai.com (or any OpenAI-compatible URL)
gpt-5.4
anthropic
ANTHROPIC_API_KEY
api.anthropic.com
claude-opus-4-6
anthropic_proxy
ANTHROPIC_PROXY_API_KEY + ANTHROPIC_PROXY_ENDPOINT_URL
Any Vertex-style raw-predict proxy
claude-sonnet-4-6
bedrock
AWS_PROFILE (optional) + AWS_REGION — SigV4 via boto3
AWS Bedrock Runtime
us.anthropic.claude-sonnet-4-6-20250915-v1:0
nv_build
NVIDIA_INFERENCE_KEY
build.nvidia.com
deepseek-ai/deepseek-v4-flash
claude_cli
(none — uses local CLI auth)
local claude binary
local Claude runtime fallback, or SKILLSPECTOR_MODEL
codex_cli
(none — uses local CLI auth)
local codex binary
local Codex runtime fallback, or SKILLSPECTOR_MODEL
…
Run SkillSpector as a Model Context Protocol server so any MCP-capable agent (Claude Code, Codex CLI, Gemini CLI) or remote runtime can call scanning as a tool and gate skill/MCP installs on the result — turning SkillSpector into a runtime guardrail instead of an out-of-band audit step.
skillspector mcp requires skillspector[mcp].
# Install, or reinstall if you already used the CLI-only path
uv tool install --force 'skillspector[mcp] @ git+https://github.com/NVIDIA/skillspector.git'
# FastMCP stdio transport for local CLI agents
skillspector mcp
# streamable HTTP/SSE transport for remote / A2A callers
skillspector mcp --transport http --host 127.0.0.1 --port 8000
The stdio transport is the current FastMCP path for local CLI agents, and the initialize hang reported in issue #199 still applies there.
The server exposes a single tool:
scan_skill(target, use_llm=true, output_format="json") — scans a Git
URL, file URL, .zip, .md file, or directory and returns a structured
verdict: risk_score (0-100), severity, recommendation,
safe_to_install, and findings. It also reports llm_used / scan_mode
so a low score from a static-only scan is never mistaken for a clean full
scan.Register it with Claude Code via:
claude mcp add skillspector -- skillspector mcp
Security — HTTP transport trust model
The HTTP transport ships without authentication. Any caller that can reach the port can invoke
scan_skill. Over stdio or127.0.0.1this is the same trust boundary as the CLI. If you bind to a routable interface:
- Sit the server behind an authenticating reverse proxy (e.g. nginx + mTLS) before exposing it externally.