
SkillSpector
エージェント用スキルを導入前に読み、自分のマシンとデータに対して何ができてしまうかを報告する検査ツール
SkillSpectorとは
スキルやMCPサーバーの導入は、ライブラリの追加よりブラウザ拡張の導入に近い行為です。届くのは指示とスクリプトであり、エージェントは自分の認証情報とファイルが手の届く範囲にある状態でそれに従いますが、事前に中身を読む人はほとんどいません。SkillSpectorはそれを読みます。リポジトリや書庫、ディレクトリを対象に、プロンプトインジェクション、データが本来と違う先へ送られる動き、権限の昇格、細工されたツール説明、供給網の危険といった観点の検出パターンで走査し、危険度と推奨対応を添えた指摘を返します。NVIDIAは、調査したスキルの26.1%に脆弱性、5.2%に悪意の疑いがあったとする研究を引いています。パターンによる走査が示すのは証明ではなく疑いなので、指摘を人が確認し、許容したものを記録していく運用が前提になります。
SkillSpectorで何ができますか?
- 導入してよいかという1点に答える — リポジトリ、URL、書庫、ディレクトリのいずれかを指定すると、深刻度と100点満点の評点、推奨対応を添えた指摘が返ります。
- エージェント特有の失敗を探す — 検出パターンは、プロンプトインジェクション、データの持ち出し、過剰な権限、記憶の汚染、誤解を誘うツール説明などを対象にしています。一般的なコードの粗探しではありません。
- 依存先も確認する — スキルが取り込むものに既知の脆弱性がないかを公開データベースに照会します。ネットワークが無い場合は手元のデータで代替します。
- 時間をかけた二番目の判断を足す — 任意の段階として、内容をモデルに読ませて意味の面から判定できます。パターンでは表現できない意図をここで捉えます。
- 確認済みのものを許容として記録する — 問題ないと判断した指摘を基準として登録できるため、再走査では同じ一覧ではなく新しく出たものだけが表示されます。
- 自動処理から導入を止める — 報告はJSON、Markdown、SARIFで出力できるので、指摘があればビルドを失敗させ、他のセキュリティ検査と同じ場所に結果を集められます。
SkillSpectorを選ぶ前に
- パターンによる走査が示すのは証明ではなく疑いです。問題のないスキルにも指摘は出ます。許容したものを記録する機能があるのはそのためで、指摘ゼロも保証ではありません。
- 意図まで捉える意味解析の段階にはモデルが必要で、鍵と費用が伴います。高速な静的解析だけでも動きますが、見えるのはパターンで表現できる範囲に限られます。
よくある質問
SkillSpectorは商用利用できますか?
SkillSpectorはApache-2.0ライセンスで公開されています。OSI承認のオープンソースライセンスで、商用利用が認められています。
SkillSpectorはどの形で使えますか?
SkillSpectorはローカル実行・セルフホストの形で利用できます。
ドキュメント
NVIDIA/SkillSpector のREADMEより転載(Apache-2.0)。 原文を読む ↗
SkillSpector
Security scanner for AI agent skills. Detect vulnerabilities, malicious patterns, and security risks before installing agent skills.
Overview
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.
Documentation
- Scan agent skills before installation — Hosted guide: when to scan, how to read a report, and how to gate installs.
- Development guide — Architecture, package layout, and how to extend the analyzer pipeline.
- Analysis resource bounds — Fail-closed bundle, parser, nested-artifact, ledger, and finding ceilings.
- Pi extension — Install SkillSpector as a Pi tool for scanning skills from inside agent sessions.
Features
- Multi-format input: Scan Git repos, URLs, zip files, directories, or single files
- 71 vulnerability patterns across 17 categories: prompt injection, data exfiltration, privilege escalation, supply chain, excessive agency, output handling, system prompt leakage, memory poisoning, tool misuse, rogue agent, anti-refusal, trigger abuse, dangerous code (AST), taint tracking, YARA signatures, MCP least privilege, and MCP tool poisoning
- Two-stage analysis: Fast static analysis + optional LLM semantic evaluation
- Live vulnerability lookups: SC4 queries OSV.dev for real-time CVE data with automatic offline fallback
- Multiple output formats: Terminal, JSON, Markdown, and SARIF reports
- Risk scoring: 0-100 score with severity labels and clear recommendations
- Baseline / false-positive suppression: Accept known findings via a glob-rule or fingerprint baseline so re-scans surface only new issues (docs)
Quick Start
Installation
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
Docker (no Python required)
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
Basic Usage
# 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
Size limits
SkillSpector enforces two independent caps on remote and archive inputs to bound the impact of oversized downloads and zip bombs:
- Per-ingest cap:
INGEST_MAX_BYTES(100 MiB) — applied to streamed URL downloads, total uncompressed size of zip archives, and post-clone disk usage of Git repos. - Zip member cap:
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.
Output Formats
# 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
Batch Scanning
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.
Suppressing False Positives (baseline)
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.
LLM Analysis
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.
Provider (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 |
# Stock OpenAI
export SKILLSPECTOR_PROVIDER=openai
export OPENAI_API_KEY=sk-...
skillspector scan ./my-skill/
# Anthropic
export SKILLSPECTOR_PROVIDER=anthropic
export ANTHROPIC_API_KEY=sk-ant-...
skillspector scan ./my-skill/
# Anthropic via Vertex-style proxy (corporate gateways, GCP Vertex AI)
export SKILLSPECTOR_PROVIDER=anthropic_proxy
export ANTHROPIC_PROXY_ENDPOINT_URL=https://my-gateway.example.com/models/claude-sonnet-4-6:streamRawPredict
export ANTHROPIC_PROXY_API_KEY=your-bearer-token
export SKILLSPECTOR_MODEL=claude-sonnet-4-6
skillspector scan ./my-skill/
# AWS Bedrock (Claude via SigV4)
export SKILLSPECTOR_PROVIDER=bedrock
# Optional: select an AWS named profile. When unset, the standard
# boto3 credential chain (env vars, instance metadata, SSO, etc.) resolves.
# export AWS_PROFILE=my-profile
export AWS_REGION=us-west-2 # default if unset
# Default model: us.anthropic.claude-sonnet-4-6-20250915-v1:0
# Override with any Bedrock model ID, cross-region inference-profile
# ID, or your own application-inference-profile ARN:
# export SKILLSPECTOR_MODEL=us.anthropic.claude-opus-4-6-20250915-v1:0
skillspector scan ./my-skill/
# NVIDIA build.nvidia.com
export SKILLSPECTOR_PROVIDER=nv_build
export NVIDIA_INFERENCE_KEY=nvapi-...
skillspector scan ./my-skill/
# Local Claude CLI — no API key; uses your existing `claude auth login` session
# Requires: claude CLI installed and authenticated (claude auth login)
export SKILLSPECTOR_PROVIDER=claude_cli
# Uses the local Claude CLI runtime fallback unless SKILLSPECTOR_MODEL is set.
# export SKILLSPECTOR_MODEL=claude-sonnet-4-6
skillspector scan ./my-skill/
# Local Codex CLI — no API key; uses your existing `codex login` session
# Requires: codex CLI installed and authenticated
export SKILLSPECTOR_PROVIDER=codex_cli
skillspector scan ./my-skill/
# Local Ollama or any OpenAI-compatible endpoint
export SKILLSPECTOR_PROVIDER=openai
export OPENAI_API_KEY=ollama
export OPENAI_BASE_URL=http://localhost:11434/v1
export SKILLSPECTOR_MODEL=llama3.1:8b
skillspector scan ./my-skill/
# Override the provider's default model
export SKILLSPECTOR_MODEL=gpt-5.2
skillspector scan ./my-skill/
# Skip LLM analysis (faster, static analysis only)
skillspector scan ./my-skill/ --no-llm
MCP Server
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,.mdfile, or directory and returns a structured verdict:risk_score(0-100),severity,recommendation,safe_to_install, andfindings. It also reportsllm_used/scan_modeso 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.
- Local paths and
file://URLs are automatically rejected over HTTP to prevent unauthenticated callers from reading arbitrary host files. Only remote Git and.zipURLs are accepted.
Vulnerability Patterns
SkillSpector detects 71 vulnerability patterns across 17 categories:
Prompt Injection (6 patterns)
| ID | Pattern | Severity | Description |
|---|---|---|---|
| P1 | Instruction Override | HIGH | Commands to ignore safety constraints |
| P2 | Hidden Instructions | HIGH | Malicious directives in comments/invisible text |
| P3 | Exfiltration Commands | HIGH | Instructions to transmit context externally |
| P4 | Behavior Manipulation | MEDIUM | Subtle instructions altering agent decisions |
| P5 | Harmful Content | CRITICAL | Instructions that could cause physical harm |
| P9 | Whitespace Padding | MEDIUM | Large whitespace padding hiding instructions below/beside the visible area |
Anti-Refusal (3 patterns)
| ID | Pattern | Severity | Description |
|---|---|---|---|
| AR1 | Refusal Suppression | HIGH | Instructions to never refuse or always comply (e.g. “never refuse”, “always comply”) |
| AR2 | Disclaimer Suppression | HIGH | Instructions to omit warnings, disclaimers, or ethical commentary (e.g. “no disclaimers”, “do not moralize”) |
| AR3 | Safety Policy Nullification | HIGH | Jailbreak framing that nullifies guardrails (e.g. “you have no restrictions”, “ignore your guidelines”, “do anything now”) |
Data Exfiltration (4 patterns)
| ID | Pattern | Severity | Description |
|---|---|---|---|
| E1 | External Transmission | MEDIUM | Sending data to external URLs |
| E2 | Env Variable Harvesting | HIGH | Enumerating, copying, or searching environment data to collect secrets |
| E3 | File System Enumeration | MEDIUM | Scanning directories for sensitive files |
| E4 | Context Leakage | HIGH | Transmitting conversation context externally |
Privilege Escalation (3 patterns)
| ID | Pattern | Severity | Description |
|---|---|---|---|
| PE1 | Excessive Permissions | LOW | Requesting access beyond stated functionality |
| PE2 | Sudo/Root Execution | MEDIUM | Invoking elevated system privileges |
| PE3 | Credential Access | HIGH | Reading SSH keys, tokens, passwords |
Supply Chain (9+ patterns)
| ID | Pattern | Severity | Description |
|---|---|---|---|
| SC1 | Unpinned Dependencies | LOW | No version constraints on packages |
| SC2 | External Script Fetching | HIGH | curl | bash and remote code execution |
| SC3 | Obfuscated Code | HIGH | Base64/hex encoded execution |
| SC4 | Known Vulnerable Dependencies | HIGH | Dependencies with known CVEs (live OSV.dev lookup) |
| SC5 | Abandoned Dependencies | MEDIUM | Unmaintained packages without security updates |
| SC6 | Typosquatting | HIGH | Package names similar to popular packages |
| SC8 | Shipped Python Bytecode | HIGH | __pycache__ / .pyc present (discovery skips; malicious bytecode bypass) |
| SC9 | Concealed Executable Artifact | HIGH | Executable nested in a document container or hidden/disguised artifact |
Excessive Agency (5 patterns)
| ID | Pattern | Severity | Description |
|---|---|---|---|
| EA1 | Unrestricted Tool Access | HIGH | Unfettered tool access without constraints |
| EA2 | Autonomous Decision Making | HIGH | High-impact decisions without human-in-the-loop |
| EA3 | Scope Creep | MEDIUM | Capabilities extending beyond stated purpose |
| EA4 | Unbounded Resource Access | MEDIUM | No rate limits or quotas on resource consumption |
| EA5 | External Model or Provider Selection | MEDIUM/HIGH | Model/provider pins or coding-CLI shell-outs that can switch billing accounts |
Output Handling (3 patterns)
| ID | Pattern | Severity | Description |
|---|---|---|---|
| OH1 | Unvalidated Output Injection | HIGH | Model output used without sanitization |
| OH2 | Cross-Context Output | MEDIUM | Output flows across trust boundaries without validation |
| OH3 | Unbounded Output | MEDIUM | No limits on output size or generation rate |
System Prompt Leakage (3 patterns)
| ID | Pattern | Severity | Description |
|---|---|---|---|
| P6 | Direct Leakage | HIGH | Instructions that expose system prompts or internal rules |
| P7 | Indirect Extraction | MEDIUM | Extraction via rephrasing, translation, or side-channels |
| P8 | Tool-Based Exfiltration | HIGH | System prompts exfiltrated via file writes or network requests |
Memory Poisoning (3 patterns)
| ID | Pattern | Severity | Description |
|---|---|---|---|
| MP1 | Persistent Context Injection | HIGH | Content designed to persist across interactions |
| MP2 | Context Window Stuffing | MEDIUM | Filler content displacing safety constraints |
| MP3 | Memory Manipulation | HIGH | Tampering with agent memory or stored state |
Tool Misuse (3 patterns)
| ID | Pattern | Severity | Description |
|---|---|---|---|
| TM1 | Tool Parameter Abuse | HIGH | Crafted parameters for unintended behavior (shell=True, —force) |
| TM2 | Chaining Abuse | HIGH | Tool chains that bypass individual safety checks |
| TM3 | Unsafe Defaults | MEDIUM | Overly permissive defaults (disabled TLS, no auth) |
Rogue Agent (2 patterns)
| ID | Pattern | Severity | Description |
|---|---|---|---|
| RA1 | Self-Modification | CRITICAL | Modifying own code or configuration at runtime |
| RA2 | Session Persistence | HIGH | Unauthorized persistence via cron jobs or startup scripts |
Trigger Abuse (3 patterns)
| ID | Pattern | Severity | Description |
|---|---|---|---|
| TR1 | Overly Broad Trigger | MEDIUM | Trigger patterns matching common words |
| TR2 | Shadow Command Trigger | HIGH | Triggers that shadow built-in commands or other skills |
| TR3 | Keyword Baiting Trigger | MEDIUM | Generic triggers designed to maximize activation |
Behavioral AST (9 patterns)
| ID | Pattern | Severity | Description |
|---|---|---|---|
| AST1 | exec() Call | CRITICAL | Direct exec() enabling arbitrary code execution |
| AST2 | eval() Call | HIGH | Direct eval() evaluating arbitrary expressions |
| AST3 | Dynamic Import | HIGH | __import__() loading arbitrary modules at runtime |
| AST4 | subprocess Call | HIGH | External command execution via subprocess |
| AST5 | os.system / exec-family | HIGH | Shell commands via os module |
| AST6 | compile() Call | MEDIUM | Code object creation from strings |
| AST7 | Dynamic getattr() | MEDIUM | Arbitrary attribute access with non-literal names |
| AST8 | Dangerous Execution Chain | CRITICAL | exec/eval combined with dynamic source (network, encoded data) |
| AST9 | Reflective getattr() Sink | HIGH | Reflective exec via getattr(os,'system') / getattr(builtins,'exec') that evades AST1/AST5 |
Taint Tracking (5 patterns)
| ID | Pattern | Severity | Description |
|---|---|---|---|
| TT1 | Direct Taint Flow | HIGH | Data flows directly from a source to a sink without sanitization |
| TT2 | Variable-Mediated Taint Flow | MEDIUM | Data flows from source to sink through intermediate variables |
| TT3 | Credential Exfiltration Chain | CRITICAL | Credentials (env vars, secrets) flow to network output sinks |
| TT4 | File Read to Network Exfiltration | HIGH | File contents flow to network output sinks |
| TT5 | External Input to Code Execution | CRITICAL | Network or user input flows to exec/eval/subprocess sinks |
YARA Signatures (4 patterns)
| ID | Pattern | Severity | Description |
|---|---|---|---|
| YR1 | Malware Match | CRITICAL | YARA rule match for known malware signatures |
| YR2 | Webshell Match | CRITICAL | YARA rule match for webshell patterns |
| YR3 | Cryptominer Match | HIGH | YARA rule match for crypto mining indicators |
| YR4 | Hack Tool / Exploit Match | HIGH | YARA rule match for hack tools or exploit code |
MCP Least Privilege (4 patterns)
| ID | Pattern | Severity | Description |
|---|---|---|---|
| LP1 | Underdeclared Capability | HIGH | Code uses capabilities not listed in declared permissions |
| LP2 | Wildcard Permission | MEDIUM | Permission list contains wildcards (*, all, full, any) |
| LP3 | Missing Permission Declaration | MEDIUM | No permissions field but code has detectable capabilities |
| LP4 | Overdeclared Permission | LOW | Permission declared but no corresponding code capability found |
このREADMEは一部を省略しています。全文はGitHubにあります。 原文を読む ↗