Agent Skills 生态正在爆发,但信任模型非常原始:装一个技能,等于让它带着你的 Agent 权限跑一段你没逐行读过的指令。NVIDIA 官方 README 引用的研究给出了量级——26.1% 的技能存在漏洞,5.2% 有明显恶意意图。NVIDIA 开源的 SkillSpector(Apache-2.0)就是回答「这个技能能不能装」这件事的专用扫描器:覆盖 68 类漏洞模式(提示注入、数据外泄、权限提升、供应链、工具投毒、记忆投毒等 17 个类别),静态分析本地完成、不执行技能代码,可选叠加 LLM 语义分析比对「描述与行为是否一致」,输出 0-100 风险分与 SARIF 报告直接接 CI。本篇从安装到进 CI 门禁完整走一遍。
先理解:技能的信任问题与扫描器的两段式设计
技能文件的本质是「给模型的指令 + 可选的可执行脚本」,Claude Code、Codex CLI、Gemini CLI 等主流运行时都默认信任已安装的技能。风险藏在几个地方:HTML 注释或零宽字符里藏的隐藏指令(人眼读 Markdown 根本看不到)、描述里说只读但代码里带外发请求的「描述-行为不一致」、声明权限过宽、依赖里有已知 CVE。SkillSpector 的两段式设计对应这两类问题:静态分析快速且确定,负责可疑字符串、危险 API、依赖风险、权限声明不匹配;LLM 语义分析(可选)把技能声称要做的事和代码实际做的事做意图比对,专抓隐藏指令与描述欺骗。静态扫描完全本地、不执行任何技能代码;CVE 查询走 OSV.dev 实时接口、无需 Key、断网自动回退。理解了这个分层,你就知道什么时候只跑静态、什么时候值得开语义。
扫描器不是银弹,阳性率比你想象的高。有第三方分析引述 OpenClaw ClawScan 流水线在 67,453 个公开技能版本上的实测:SkillSpector 标记了其中 48.7% 为阳性,远高于 VirusTotal 的 7.75%——它按「模式命中」计分,宁可错报不可漏报。正确用法是把扫描结果当人工复核的排序依据与发布门禁之一,而不是当判决书。
Step 1:三路安装,选最适合你环境的那条
# 路线一:uv 快速安装(Python 3.12+)
uv tool install git+https://github.com/NVIDIA/skillspector.git
# 后续更新
uv tool update skillspector
# 路线二:源码安装(要改代码或跟进 main 分支时)
git clone https://github.com/NVIDIA/skillspector.git
cd skillspector
uv venv .venv
source .venv/bin/activate # Windows: .venv/Scripts/activate
make install
# 路线三:Docker(本机没有 Python 环境时)
git clone https://github.com/NVIDIA/skillspector.git
cd skillspector
docker build -t skillspector .
uv 路线最省事:装完直接得到全局 skillspector 命令,uv tool update 跟进新版本。源码路线适合要读分析器实现或跑测试集的人,官方 Makefile 在没有 uv 时自动回退 pip。Docker 路线的价值在于环境隔离:扫描器跑在容器里,把当前目录挂载到 /scan 即可扫描,宿主机连 Python 都不用装,CI 里也最好走这条路保证环境一致。注意如果要后面把 SkillSpector 当 MCP server 用(Step 6),uv 安装命令要换成带 mcp extra 的写法,装的时候一步到位。
Step 2:跑扫描,四种输入一个命令
# 扫描本地技能目录
skillspector scan ./my-skill/
# 扫描单个 SKILL.md
skillspector scan ./SKILL.md
# 直接扫一个 Git 仓库(装前审查第三方技能最快路径)
skillspector scan https://github.com/user/my-skill
# 扫描 zip 包(市场下载的技能包)
skillspector scan ./my-skill.zip
# 静态-only 快扫(不调 LLM,最快最省)
skillspector scan ./my-skill/ --no-llm
# Docker 等价写法
docker run --rm -v "$PWD:/scan" skillspector scan ./my-skill/ --no-llm
四种输入覆盖了技能进入你机器的所有路径:本机目录、单个 SKILL.md、Git 仓库地址(装第三方技能前先扫 repo 是标准动作)、zip 包。单次扫描限制 100MiB、zip 内 10,000 个文件,正常技能远达不到。建议把 --no-llm 作为默认:静态分析毫秒级返回、结果确定、不花钱,绝大多数明显问题(隐藏字符串、危险 API、CVE 依赖)它都能抓到;只有当静态结果存疑、或技能来源不完全可信需要意图级审查时,再开 LLM 语义档做深度比对。
Step 3:读懂报告——风险分、严重度与处置建议
# 报告核心字段(JSON 输出同源):
# risk_score 0-100 风险分
# severity LOW / MEDIUM / HIGH / CRITICAL
# recommendation SAFE / CAUTION / DO NOT INSTALL
# safe_to_install 布尔值
# findings[] 逐条发现(规则、位置、证据)
# 计分规则(官方文档):
# CRITICAL 发现 +50 分
# HIGH 发现 +25 分
# MEDIUM 发现 +10 分
# LOW 发现 +5 分
# 技能捆绑可执行脚本时,总分乘 1.3
# 分数段处置(官方口径):
# 0-20 LOW SAFE 可安装
# 21-50 MEDIUM CAUTION 复核后决定
# 51-80 HIGH DO NOT INSTALL 不装
# 81-100 CRITICAL DO NOT INSTALL 不装
计分逻辑值得花一分钟理解,因为它决定了你该怎么读报告。单条发现的权重差距很大:一条 CRITICAL 直接 +50,意味着一个就够把技能打进「不要安装」区间;而 LOW 级发现攒六条才抵一条 HIGH。可执行脚本 ×1.3 的乘数来自官方引用的数据——带脚本技能的漏洞概率是纯文本技能的约 2.12 倍,扫描器故意不让它们同台竞争。处置动作跟着发现类型走(官方 triage 表):隐藏指令或工具投毒——删除隐藏内容再说;声明权限不足——收窄行为或更新权限声明;已知漏洞依赖——升级或锁修复版本;描述与行为不一致——改描述或改代码。目标是「声明、权限、代码、风险文档四者互相印证」,不是刷一个干净的分数。
Step 4:LLM 语义分析与隐私边界
# 开启语义分析:选 provider 并给 Key
export SKILLSPECTOR_PROVIDER=openai
export OPENAI_API_KEY="sk-..."
skillspector scan ./my-skill/
# Anthropic 路线
export SKILLSPECTOR_PROVIDER=anthropic
export ANTHROPIC_API_KEY="sk-ant-..."
# 本地 Ollama(零 API 成本,数据不出机)
export SKILLSPECTOR_PROVIDER=openai
export OPENAI_API_KEY="ollama"
export OPENAI_BASE_URL="http://localhost:11434/v1"
export SKILLSPECTOR_MODEL="llama3.1:8b"
# provider 不可用时自动回退为纯静态结果
语义分析的 provider 支持面很宽:openai、anthropic、bedrock、NVIDIA 自家推理服务,乃至 claude_cli 与 codex_cli,选一个你已有账户的即可;本地 Ollama 路线用 OpenAI 兼容接口指到 localhost:11434,零成本且数据完全不出本机。这里有一条必须划清的隐私红线:语义分析会把技能文件内容发送给你配置的外部 provider——审查来路不明的第三方技能没问题(它本来就要进你机器),但公司内部技能或含敏感材料的技能一律 --no-llm,或者走本地 Ollama。provider 配错或服务不可用时扫描不会失败,而是静默回退纯静态结果——看到报告里语义段缺失时先查 provider 配置,别误以为技能没问题。
第三方分析指出实现与宣称的差距。有代码分析称在 v2.1.3 版本中,污点追踪、MCP 专项分析器与语义分析节点尚未完全实现,官方宣传的 68 模式覆盖矩阵是「设计目标」而非当前全量。动手前以官方仓库最新版本的 README 与 release notes 为准,关键决策不要只依赖单一来源。
Step 5:基线降噪,让重扫只报新问题
# 把当前发现固化为基线(跑一次,然后提交进仓库)
skillspector baseline ./my-skill/ -o .skillspector-baseline.yaml
# 带基线重扫:只报告与计分「新」发现
skillspector scan ./my-skill/ --baseline .skillspector-baseline.yaml
# 复查被压制的内容(仍不计分,但可见)
skillspector scan ./my-skill/ --baseline .skillspector-baseline.yaml --show-suppressed
# 基线文件支持按规则 ID / 文件路径 / 消息的
# glob 规则(参考 .skillspector-baseline.example.yaml)
基线机制解决的是扫描器落地的经典矛盾:历史遗留的低危发现会让每次重扫都报同样的噪音,久而久之人就开始忽略报告。官方做法是把已接受的发现写进 .skillspector-baseline.yaml 提交入库,之后的扫描只对新增发现计分与告警——风险分从此反映的是「未处置的增量」而不是「全部历史」,新增风险一眼可见。被压制的发现并没有消失,--show-suppressed 随时可查。工程纪律上建议:基线文件与技能代码同仓库同评审,谁接受一个发现、理由是什么,就留在基线文件的 diff 里,审计链自然形成。
Step 6:接进 CI 门禁与让 Agent 自审
# CI 门禁的 exit code 语义(官方):
# 0 = 风险分不超过 50(LOW / MEDIUM),通过
# 1 = 超过 50(HIGH / CRITICAL),失败
# 2 = 扫描本身出错
# 阈值 50 即官方默认门禁线,不需要自定义
# SARIF 输出,直接进 GitHub Security 页
skillspector scan ./skills --no-llm --format sarif --output skillspector.sarif
# GitHub Actions 门禁骨架(OWASP 集成指南版本)
# on: pull_request, paths: ['skills/**']
# - uses: actions/setup-python@v5 (python 3.12)
# - run: pip install git+https://github.com/NVIDIA/SkillSpector
# - run: skillspector scan ./skills --no-llm --format sarif --output skillspector.sarif
# - uses: github/codeql-action/upload-sarif@v3
# with: { sarif_file: skillspector.sarif }
# MCP server 模式:装 mcp extra 后启动
uv tool install 'skillspector[mcp] @ git+https://github.com/NVIDIA/skillspector.git'
skillspector mcp
# HTTP 模式:skillspector mcp --transport http --host 127.0.0.1 --port 8000
CI 集成的关键是 exit code 语义已经内置:0-50 通过、超 50 失败,你不需要自己写阈值判断,把 scan 命令塞进 workflow 这一步本身就把门禁立起来了。SARIF 报告上传到 GitHub Code Scanning 后,每条发现在 Security 页有独立条目、可指派可跟踪,评审者在 PR diff 里直接看到风险标注。更进一步的是 MCP server 模式:装上 mcp extra 后把 SkillSpector 变成一个 MCP 工具,Claude Code 这类客户端就能在会话里调用 scan_skill(target, use_llm, output_format) 自己审查要装的技能——把「装前扫一遍」从人的纪律变成 Agent 的默认流程,这是扫描器最有趣的打开方式。
门禁阈值可以严但不建议松。50 分是官方默认线(对应到 HIGH 起判),低于 50 放行的 MEDIUM 发现也要进人工清单;把阈值调到 80 以上换「绿」等于关掉门禁——48.7% 的阳性率说明这工具的噪音本就需要基线机制消化,而不是靠放宽阈值。
预期效果与自检清单
全部做完后,你应该达到:skillspector scan ./某技能/ --no-llm 能在几秒内给出含风险分的报告;你能说清一条 CRITICAL 与一条 MEDIUM 分别加多少分、可执行脚本为什么乘 1.3;内部技能扫描全部走静态或本地模型、无文件外发;仓库里有已提交的基线文件且重扫只报增量;GitHub Actions 对 skills 目录的 PR 自动跑扫描并在超阈值时拒绝合并;MCP 模式下 Agent 能在会话里对候选技能发起扫描并给出装/不装建议。技能生态的信任问题不会很快有银弹,但「装前扫描 + 基线降噪 + CI 门禁」这套组合,已经能把随机踩雷变成有记录、有阈值、有审计的工程流程。