SkillSpector 完整教學 — AI Agent Skill 安全掃描器
§1 專案定位
1.1 解決什麼問題
AI agent skill(如 Claude Code skill、Codex CLI skill、Gemini CLI skill)在安裝時幾乎沒有審查機制。根據 NVIDIA 引用的研究 “Agent Skills in the Wild”(Liu et al., 2026),在 42,447 個 skill 樣本中:
- 26.1% 含有至少一個漏洞 (vulnerability)
- 5.2% 呈現明顯惡意意圖 (malicious intent)
- 含可執行腳本的 skill,漏洞機率高出 2.12 倍
SkillSpector 的核心使命:在安裝前回答「這個 skill 安全嗎?」
1.2 誰該用
| 對象 | 使用情境 |
|---|---|
| AI agent 使用者 | 安裝第三方 skill 前快速掃描 |
| Skill 開發者 | 發佈前自我檢查,確保通過安全基準 |
| 安全團隊 | CI/CD 整合(SARIF 輸出),自動化 skill 審核 |
| 研究人員 | 大規模 skill 安全分析、漏洞模式研究 |
1.3 競品比較
目前 AI agent skill 安全掃描是一個新興領域,SkillSpector 是第一個專門針對此需求的開源工具。傳統的 SAST 工具(如 Semgrep、Bandit)可偵測通用程式碼漏洞,但無法處理 skill 特有的威脅向量:prompt injection (提示注入)、MCP tool poisoning (MCP 工具投毒)、memory poisoning (記憶體投毒) 等。
§2 安裝指南
2.1 環境需求
- Python:3.12 或 3.13(嚴格限制
>=3.12,<3.14) - Git:掃描 GitHub repo 時需要
- uv(推薦)或 pip:套件管理
- 網路存取:OSV.dev CVE 查詢需要(離線有 fallback)
2.2 從原始碼安裝
1# 1. Clone
2git clone https://github.com/NVIDIA/skillspector.git
3cd skillspector
4
5# 2. 建立虛擬環境
6uv venv .venv && source .venv/bin/activate
7# 或:python3 -m venv .venv && source .venv/bin/activate
8
9# 3. 安裝(正式使用)
10make install
11
12# 4. 驗證
13skillspector --version
14# 預期輸出:SkillSpector v2.1.3
2.3 開發者安裝
1make install-dev # 含 pytest, ruff, mypy, build 等
2make test # 跑全部測試(unit + integration)
3make lint # 跑 ruff linter
2.4 LLM 設定
SkillSpector 的 Stage 2 語義分析需要 LLM。三家 provider 擇一設定:
1# 方法 A:OpenAI(或 OpenAI-compatible endpoint)
2export SKILLSPECTOR_PROVIDER=openai
3export OPENAI_API_KEY=sk-...
4
5# 方法 B:Anthropic
6export SKILLSPECTOR_PROVIDER=anthropic
7export ANTHROPIC_API_KEY=sk-ant-...
8
9# 方法 C:NVIDIA Build(預設 provider)
10export SKILLSPECTOR_PROVIDER=nv_build
11export NVIDIA_INFERENCE_KEY=nvapi-...
12
13# 方法 D:本地 Ollama
14export SKILLSPECTOR_PROVIDER=openai
15export OPENAI_API_KEY=ollama
16export OPENAI_BASE_URL=http://localhost:11434/v1
17export SKILLSPECTOR_MODEL=llama3.1:8b
不設定 LLM 也可以使用,加 --no-llm 僅跑靜態分析。
§3 核心架構解析
3.1 LangGraph 工作流
SkillSpector 建構在 LangGraph StateGraph 之上,不是傳統的線性 pipeline。整個掃描流程是一張有向無環圖 (DAG):
graph TD
START([START]) --> resolve_input
resolve_input --> build_context
build_context --> analyzer_1[static_patterns_prompt_injection]
build_context --> analyzer_2[static_patterns_data_exfiltration]
build_context --> analyzer_3[static_patterns_privilege_escalation]
build_context --> analyzer_4[static_patterns_supply_chain]
build_context --> analyzer_5[behavioral_ast]
build_context --> analyzer_6[behavioral_taint_tracking]
build_context --> analyzer_7[mcp_least_privilege]
build_context --> analyzer_8[mcp_tool_poisoning]
build_context --> analyzer_9[semantic_security_discovery]
build_context --> analyzer_10[semantic_developer_intent]
build_context --> analyzer_dots[... 共 20 個 analyzer]
analyzer_1 --> meta_analyzer
analyzer_2 --> meta_analyzer
analyzer_3 --> meta_analyzer
analyzer_4 --> meta_analyzer
analyzer_5 --> meta_analyzer
analyzer_6 --> meta_analyzer
analyzer_7 --> meta_analyzer
analyzer_8 --> meta_analyzer
analyzer_9 --> meta_analyzer
analyzer_10 --> meta_analyzer
analyzer_dots --> meta_analyzer
meta_analyzer --> report
report --> END([END])
關鍵設計:20 個 analyzer node 從 build_context 後並行扇出 (fan-out),全部匯入 meta_analyzer 做 LLM 過濾。graph state 中的 findings 欄位使用 Annotated[list[Finding], operator.add] reducer,讓各 node 的結果自動合併。
3.2 五個核心 Node
| Node | 職責 |
|---|---|
resolve_input | 解析輸入(Git URL / HTTP URL / zip / 單檔 / 目錄)→ 統一為本地目錄 |
build_context | 走訪目錄、分類檔案、讀取內容、建立 file_cache / ast_cache / manifest |
| 20 Analyzer Nodes | 並行執行 — 靜態 regex + AST 分析 + YARA + taint tracking + MCP 審查 + LLM 語義分析 |
meta_analyzer | Stage 2 — 用 LLM 過濾誤報、富化解釋、調整信心度 (confidence);用 Pydantic structured output |
report | 計算風險分數 + 生成 SARIF 2.1.0 + 輸出 terminal/JSON/Markdown/SARIF 報告 |
3.3 Analyzer 分類
| 類型 | 數量 | 是否需要 LLM | 代表 |
|---|---|---|---|
| Static Pattern | 11 | 否 | prompt_injection, data_exfiltration, supply_chain |
| Behavioral (AST) | 1 | 否 | exec/eval/subprocess 偵測 |
| Behavioral (Taint) | 1 | 否 | 資料流追蹤(source → sink) |
| YARA | 1 | 否 | malware / webshell / cryptominer / hacktools |
| MCP | 3 | 部分(TP4 需要) | least_privilege, tool_poisoning, rug_pull |
| Semantic (LLM) | 3 | 是 | security_discovery, developer_intent, quality_policy |
3.4 Graph State 設計
1class SkillspectorState(TypedDict, total=False):
2 input_path: str | None # 使用者輸入
3 skill_path: str | None # 解析後的本地路徑
4 file_cache: dict[str, str] # 檔名 → 內容
5 ast_cache: dict[str, str] # 檔名 → AST dump
6 findings: Annotated[list[Finding], operator.add] # 各 analyzer append
7 filtered_findings: list[Finding] # meta_analyzer 過濾後
8 use_llm: bool # 是否啟用 Stage 2
9 risk_score: int # 0-100
10 report_body: str # 最終報告
§4 Helper Scripts 詳細用法
4.1 CLI 指令
1# 基本掃描 — 目錄
2skillspector scan ./my-skill/
3
4# 基本掃描 — 單一 SKILL.md
5skillspector scan ./SKILL.md
6
7# 掃描 GitHub repo
8skillspector scan https://github.com/user/my-skill
9
10# 掃描 zip 檔
11skillspector scan ./my-skill.zip
4.2 輸出格式
1# Terminal(預設,Rich 排版)
2skillspector scan ./my-skill/
3
4# JSON(機器可讀)
5skillspector scan ./my-skill/ --format json --output report.json
6
7# Markdown(文件化)
8skillspector scan ./my-skill/ --format markdown --output report.md
9
10# SARIF(CI/CD 整合)
11skillspector scan ./my-skill/ --format sarif --output report.sarif
4.3 LLM 控制
1# 跳過 LLM(僅靜態分析,速度快)
2skillspector scan ./my-skill/ --no-llm
3
4# 指定 provider 的模型
5export SKILLSPECTOR_MODEL=gpt-5.2
6skillspector scan ./my-skill/
7
8# Verbose 模式(DEBUG 級 log)
9skillspector scan ./my-skill/ -V
4.4 Makefile 指令
| 指令 | 說明 |
|---|---|
make install | 安裝正式版(uv 優先) |
make install-dev | 安裝開發版(含 pytest, ruff, mypy) |
make test | 跑 unit + integration 測試 |
make test-unit | 僅 unit 測試(無 LLM 呼叫) |
make test-integration | 僅 integration 測試(可能呼叫 LLM) |
make test-cov | 測試 + 覆蓋率報告 |
make lint | ruff check |
make format | ruff format |
make langgraph-dev | 啟動 LangGraph dev server(開啟 Studio UI) |
make clean | 清除 build artifacts |
4.5 Python API
1from skillspector import graph
2
3result = graph.invoke({
4 "input_path": "/path/to/skill",
5 "output_format": "json",
6 "use_llm": True,
7})
8
9print(f"Risk Score: {result['risk_score']}/100")
10print(f"Severity: {result['risk_severity']}")
11for finding in result["filtered_findings"]:
12 print(f"[{finding['severity']}] {finding['rule_id']}: {finding['message']}")
§5 應用場景
5.1 場景 A:安裝前快速檢查
1# 看到一個有趣的 Claude Code skill,先掃再裝
2skillspector scan https://github.com/someone/cool-skill --no-llm
3# 30 秒內得到靜態分析結果
5.2 場景 B:CI/CD 整合
1# GitHub Actions 範例
2- name: Scan skill security
3 run: |
4 skillspector scan ./skill/ --format sarif --output results.sarif
5- name: Upload SARIF
6 uses: github/codeql-action/upload-sarif@v3
7 with:
8 sarif_file: results.sarif
5.3 場景 C:Skill 開發者自我審查
1# 發佈前掃描,確保無高風險問題
2export SKILLSPECTOR_PROVIDER=openai
3export OPENAI_API_KEY=sk-...
4skillspector scan ./my-new-skill/
5# 目標:Score < 20,Severity = LOW
5.4 場景 D:大規模研究
1import json
2from pathlib import Path
3from skillspector import graph
4
5results = []
6for skill_dir in Path("skills-dataset").iterdir():
7 if skill_dir.is_dir():
8 r = graph.invoke({
9 "input_path": str(skill_dir),
10 "output_format": "json",
11 "use_llm": False,
12 })
13 results.append({
14 "skill": skill_dir.name,
15 "score": r["risk_score"],
16 "findings": len(r.get("filtered_findings", [])),
17 })
18
19Path("scan_results.json").write_text(json.dumps(results, indent=2))
§6 資安掃描報告
6.1 掃描範圍
對 SkillSpector 自身原始碼(src/skillspector/)進行資安掃描,檢查是否存在危險模式。
6.2 發現
| 項目 | 嚴重度 | 說明 |
|---|---|---|
subprocess.run() in input_handler.py:130 | 🟢 低 | 用於 git clone --depth 1,已設定 shell=False、timeout=60、capture_output=True,是安全的用法 |
httpx.Client.get() in input_handler.py:156 | 🟢 低 | 用於下載使用者指定的 URL,有 timeout=30 和 follow_redirects=True;但未限制回應大小 |
zipfile.extractall() in input_handler.py:181 | 🟡 中 | zip 解壓未檢查 zip bomb 或路徑穿越 (path traversal);Issue #21 已追蹤此問題 |
| API key 環境變數讀取 | 🟢 低 | os.environ.get("OPENAI_API_KEY") 等,正常的 credential 讀取模式,未寫入 log 或外傳 |
| LLM 呼叫(OpenAI / Anthropic SDK) | 🟢 低 | 透過官方 SDK 呼叫,token budget 有上限控制 |
YARA 規則檔 (yara_rules/*.yar) | 🟢 低 | 純比對規則,不執行任何動態操作 |
build_context 全檔讀入記憶體 | 🟡 中 | file_cache 將所有掃描檔案讀入記憶體,大型 skill 可能造成 OOM;Issue #5 / #21 相關 |
6.3 結論
整體評級:🟢 低風險
SkillSpector 自身的程式碼品質良好。主要的兩個 🟡 中風險項目(zip 解壓、記憶體使用)皆為已知問題且有 Issue 追蹤。無發現惡意行為、資料外洩或硬編碼 credential。subprocess 使用方式符合安全最佳實踐(shell=False)。
§7 FAQ
Q1:不設定 LLM 可以用嗎?
可以。加 --no-llm 即僅跑靜態分析(Stage 1),速度更快但精度較低(可能有較多 false positive)。
Q2:支援哪些輸入格式?
- 本地目錄
- 單一
.md或.py檔案 - GitHub / Git repo URL
- HTTP URL(直接下載)
.zip壓縮檔
Q3:SARIF 輸出可以接到哪些 CI/CD?
SARIF 2.1.0 是 OASIS 標準,可直接上傳到 GitHub Code Scanning (CodeQL)、Azure DevOps、SonarQube 等。
Q4:為什麼需要 Python 3.12+?
SkillSpector 使用 StrEnum(3.11+)和 type annotation 語法(如 int | None)等新特性。pyproject.toml 明確要求 >=3.12,<3.14。
Q5:可以用本地 LLM(Ollama)嗎?
可以。設定 OPENAI_BASE_URL=http://localhost:11434/v1 加上 SKILLSPECTOR_MODEL=llama3.1:8b 即可。
Q6:掃描結果 score 代表什麼?
| 分數 | 嚴重度 | 建議 |
|---|---|---|
| 0-20 | LOW | SAFE — 可安裝 |
| 21-50 | MEDIUM | CAUTION — 建議人工審查 |
| 51-80 | HIGH | DO NOT INSTALL |
| 81-100 | CRITICAL | DO NOT INSTALL |
Q7:Issue #31 提到 phantomstars,repo 的星星是假的嗎?
Issue #31 指出該 repo 可能存在 fake engagement。使用者應獨立評估工具品質,不應僅依賴 star count。
§8 進階技巧
8.1 自訂 YARA 規則
SkillSpector 支援載入額外的 YARA 規則目錄:
1skillspector scan ./my-skill/ --yara-rules-dir ./my-custom-rules/
規則檔放在目錄下,副檔名為 .yar 或 .yara,SkillSpector 會自動載入並與內建規則合併。
8.2 LangGraph Studio 視覺化
1make langgraph-dev
2# 在瀏覽器開啟 LangGraph Studio
3# 可視覺化看到整個 DAG、即時觀察 state 流動
8.3 覆寫模型
1# 使用指定模型而非 provider 預設
2export SKILLSPECTOR_MODEL=gpt-5.2
3skillspector scan ./my-skill/
各 provider 的預設模型:
| Provider | 預設模型 |
|---|---|
openai | gpt-5.4 |
anthropic | claude-opus-4-6 |
nv_build | deepseek-ai/deepseek-v4-flash |
8.4 自訂 model registry
1export SKILLSPECTOR_MODEL_REGISTRY=./my-registry.yaml
YAML 格式參考 src/skillspector/providers/openai/model_registry.yaml。
8.5 Debug 模式
1# CLI verbose
2skillspector scan ./my-skill/ -V
3
4# 環境變數
5export SKILLSPECTOR_LOG_LEVEL=DEBUG
6skillspector scan ./my-skill/
§9 整合進其他工作流
9.1 整合進 AIKT gh-tutorial-qd
在 AIKT 的 gh-tutorial-qd 工作流中,可以在 Step 3(資安掃描)階段使用 SkillSpector 取代手動 grep:
1# 對 clone 下來的 repo 跑 SkillSpector
2skillspector scan /tmp/cloned-repo/ --no-llm --format json --output /tmp/scan.json
9.2 作為 pre-commit hook
1# .pre-commit-config.yaml
2repos:
3 - repo: local
4 hooks:
5 - id: skillspector
6 name: SkillSpector Security Check
7 entry: skillspector scan . --no-llm --format json
8 language: system
9 always_run: true
10 pass_filenames: false
9.3 搭配 paper-qa-lite
掃描結果可以作為 paper-qa-lite 的輸入,協助分析 skill 安全研究論文中的具體案例:
1skillspector scan ./case-study-skill/ --format markdown --output /tmp/scan-report.md
2# 然後用 pq: 對掃描報告提問
§10 重點摘要 Checklist
- 環境:Python 3.12+、uv(或 pip)、Git
- 安裝:
git clone→uv venv→make install - 驗證:
skillspector --version→ v2.1.3 - LLM 設定:選擇 provider(openai / anthropic / nv_build)+ 設定 API key
- 基本掃描:
skillspector scan <target>— 支援目錄、檔案、URL、zip - 輸出格式:terminal / json / markdown / sarif
- 僅靜態:
--no-llm跳過 LLM 分析 - 風險判讀:0-20 SAFE / 21-50 CAUTION / 51+ DO NOT INSTALL
- 64 個偵測模式:涵蓋 16 類別(prompt injection 到 MCP tool poisoning)
- CI/CD:SARIF 輸出可直接整合 GitHub Code Scanning
- Python API:
from skillspector import graph; graph.invoke({...}) - LangGraph Studio:
make langgraph-dev視覺化觀察工作流
§11 進一步閱讀
官方文件
- README — 完整使用說明
- DEVELOPMENT.md — 開發者指南
- LLM_ANALYZER_BASE_GUIDE.md — 如何擴充 LLM analyzer
- EVAL_DATASETS.md — 評估資料集
- MCP Least Privilege — B.3.1 規範
- MCP Tool Poisoning — B.3.2 規範
相關研究
- Liu et al. (2026). “Agent Skills in the Wild: An Empirical Study of Security Vulnerabilities at Scale” — 42,447 skill 大規模安全分析
- OWASP LLM Top 10 — LLM 應用安全威脅排名
- SARIF 2.1.0 OASIS Standard — 靜態分析結果交換格式
Comments