装别人的 skill 之前先扫一遍:NVIDIA 把 71 种投毒模式做成扫描器,3 万个技能里 26% 有问题

本页目录 9 节
先说一个现在很常见、但很少有人停下来想的动作。
你在终端里敲一行命令,装上一个别人写的 skill——它可能是一段提示词、一个 SKILL.md、几个 Python 脚本,外加一份 requirements.txt。装完之后,你的 AI 助手会用这个 skill 去读文件、发请求、跑命令。
换句话说:你把一段陌生人的提示词,连着几个陌生人的脚本,一起接进了自己有权限的终端。
浏览器的扩展商店至少还有审核和沙箱。技能包生态现在基本是「谁都可以发、装了就生效」。这篇要说的 SkillSpector,就是 NVIDIA 开源出来、专门在这个环节上补一道检查的工具:装之前,先静态扫一遍。
一、它是什么:一个装之前用的扫描器
一句话概括:输入一个技能包(目录、单个 SKILL.md、Git 仓库或 zip),输出一份风险报告和一个 0—100 的风险分。
| 项目 | 情况 |
|---|---|
| 开源方 | NVIDIA,Apache License 2.0 |
| 形态 | 命令行工具(skillspector scan),也可挂成 MCP 服务器 |
| 支持输入 | 本地目录 / 单个 SKILL.md / Git 仓库 URL / zip 包 |
| 检测面 | 17 个类别、71 种漏洞模式 |
| 分析方式 | 正则 + Python AST + YARA 静态分析;可选 LLM 二次复核(可关) |
| 输出格式 | 终端彩色报告 / JSON / Markdown / SARIF 2.1.0 |
| 覆盖生态 | Claude Code、Codex CLI、MCP 服务器、Gemini CLI、OpenCode、Pi 扩展 |
| 定位 | NVIDIA Verified Skills 流水线的一环:发布前扫描、评估、签名 |
| 费用 | 免费,无账号、无付费墙;纯静态模式不需要任何密钥 |
先把最容易误会的一点说清楚:它不执行被扫描的代码。整套分析是静态的——读文本、解析语法树、匹配 YARA 规则,可选再加一层大模型判断。它不会跑那个 skill,也不会隔离你的机器。这一点既是它的优点(安全、快),也是它最大的局限(后面第八节展开)。
二、26.1% 这个数字是怎么来的
README 引用了一份 2026 年的研究(Liu et al.),里面几个数字值得抄下来,因为它们直接解释了这类工具为什么必须存在:
- 数据集共采集 42,447 个技能,其中 31,132 个被实际分析;
- 26.1% 的技能至少存在一个漏洞;
- 5.2% 显示出「可能的恶意意图」;
- 含可执行脚本的技能,存在漏洞的概率是普通技能的 2.12 倍。
这四个数字里,最有信息量的是最后一条。它说明风险不是均匀分布的——凡是带你跑脚本的 skill,风险直接翻倍。而现实是,功能越强的 skill 越需要脚本:读文件、调接口、跑构建,全靠脚本。所以「挑好评多的装」这条经验在这里基本失效,好评多往往意味着它做的事多,也就是脚本多。
5.2% 这个比例也要正确理解:三万多个技能里一千多个「疑似恶意」,听起来吓人,但「疑似」是扫描器的判定,不是法院的判决。误报率官方没有公布,所以正确的用法是「把它当成筛子,不是当成判决书」——它筛出可疑的,你自己去看那段被标红的代码。
三、装:一条命令,三种备选
最省事的方式是用 uv(如果没装,先 pip install uv 或按官网方式装):
uv tool install git+https://github.com/NVIDIA/skillspector.git
以后升级:
uv tool update skillspector
如果你想让它同时能当 MCP 服务器用(第七节会用到),装带扩展的那份:
uv tool install 'skillspector[mcp] @ git+https://github.com/NVIDIA/skillspector.git'
不想在本机装 Python 环境,就用 Docker——注意它挂载的是当前目录,扫描结果写到 /scan 里:
docker build -t skillspector .
docker run --rm -v "$PWD:/scan" skillspector scan ./my-skill/ --no-llm
想读源码或者要改规则,就克隆下来跑 make install(生产)或 make install-dev(带开发依赖)。Docker 镜像基于 python:3.12-slim-bookworm。
四、扫:五种输入,四种输出
最常用的四条命令:
skillspector scan ./my-skill/ # 扫一个技能目录
skillspector scan ./SKILL.md # 扫单个技能文件
skillspector scan https://github.com/user/my-skill # 扫远程仓库
skillspector scan ./my-skill.zip # 扫压缩包
加上 --no-llm 就只做静态分析——更快、不联网、不外发任何内容,缺点是判断全靠规则,误报会多一些。第一次用建议先跑一遍 --no-llm 看有哪些命中,再决定要不要开 LLM 复核。
批量扫一个技能库:
skillspector scan ./my-skills/ --recursive --max-skills 100 --no-llm --format json
注意 --recursive 默认只聚合 32 个技能,超过要用 --max-skills 抬上限。仓库里还有 contrib/batch_scan 这个批量脚本,能开 20 个并发、直接吐 JSON,而且支持中文、日文、韩文检测——对中文技能包更友好。
还有一个很实用的功能:基线抑制误报。
skillspector baseline ./my-skill/ -o .skillspector-baseline.yaml
skillspector scan ./my-skill/ --baseline .skillspector-baseline.yaml
先跑一次生成基线,之后只报「新出现的问题」。这一步是把扫描器真正接进日常流程的关键:一个技能包本来就有 8 条低危告警,你不可能每次更新都重看一遍;有了基线,你能立刻看出这次提交是不是多了一条高危。
输出方面,--format json 给机器读,--format markdown 贴文档,--format sarif 喂给 GitHub Code Scanning 一类的 CI 工具。SARIF 这条路是把安全扫描变成「自动门禁」的前提。
五、它到底在查什么:17 类 71 种
这一节是全篇最该仔细看的部分,因为它直接告诉你「一个 skill 是怎么害人的」。挑重点列:
| 类别 | 模式数 | 在查什么 |
|---|---|---|
| 提示注入 | 6 | 指令覆盖、隐藏指令、数据外传命令、行为操纵、有害内容、用空白字符藏字 |
| 反拒绝(Anti-Refusal) | 3 | 压制模型的拒绝、压制免责声明、把安全策略整体失效(越狱) |
| 数据外泄 | 4 | 向外部传输、收割环境变量、枚举文件系统、泄漏上下文 |
| 提权 | 3 | 过度权限、sudo/root 执行、读取凭据 |
| 供应链 | 10+ | 未固定版本依赖、curl | bash、混淆代码、实时查 OSV.dev 的已知 CVE、废弃依赖、域名占用、夹带字节码、隐藏可执行体、依赖源重定向 |
| 过度代理 | 5 | 无限制工具访问、自主决策、范围蔓延、无界资源访问、私自切换外部模型 |
| 系统提示泄漏 | 3 | 直接泄漏、间接套取、借工具外传 |
| 记忆投毒 | 3 | 往持久上下文里注入、塞满上下文窗口、篡改记忆 |
| 工具滥用 | 3 | shell=True、--force 这类参数滥用、链式滥用、不安全默认值 |
| 流氓代理 | 2 | 运行时自我修改、用 cron 或启动脚本做持久化 |
| 触发器滥用 | 3 | 触发范围过宽、影子命令、关键词钓鱼 |
| 行为 AST | 9 | exec()、eval()、动态导入、subprocess、os.system、compile()、动态 getattr()、危险执行链 |
| 污点追踪 | 5 | 从读到发的完整链路:凭据外泄链、文件读到网络发出、外部输入到代码执行 |
| YARA 签名 | 4 | 恶意软件、Webshell、挖矿程序、黑客工具/漏洞利用 |
| MCP 最小权限 | 4 | 能力少申报、通配符权限、缺权限声明、权限过度申报 |
| MCP 工具投毒 | 4 | 元数据里藏指令、Unicode 欺骗、参数描述注入、描述与实际行为不符 |
这张表里有三处值得单独点出来。
第一,「记忆投毒」是被严重低估的一类。大部分人对 skill 的担心停在「它会不会偷我的 key」。但一个 skill 如果能往助手的持久上下文里写东西,它就不需要偷任何东西——它可以让你的助手从明天开始,每次都多带一句你没要求过的话。这种攻击没有日志、没有报错,只在某天你发现模型的判断方式变了。
第二,「反拒绝」这一类说明攻击面已经变了。以前装个插件,风险是「它想干坏事」;现在多了一层「它想让模型放弃拒绝」。一个 skill 只要能让模型把「这我不能做」改成「好的」,后面的事就不需要它自己动手了。
第三,供应链那一类里有一条是「实时的」。它会在扫描时去 api.osv.dev 查依赖的已知漏洞,不需要 Key,离线时退回内置的静态列表。这是这份工具里少数「不是靠规则猜、而是查事实」的部分,可信度最高。
六、评分与门禁:0—100 怎么算,超过 50 就该停手
分数是加权累加的: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 分,两条就直接进「别装」区间;而一条 CRITICAL 加脚本的 1.3 倍,单条就能到 65 分。换句话说,这分数对「严重项」非常敏感,对「一堆低危」反而不敏感(要 11 条 LOW 才到 55)。用的时候看的应该是「有没有 CRITICAL/HIGH」,而不是总分。
接进 CI 靠的是退出码,这个契约写得很清楚:
0:扫描完成,且总分 ≤ 50;1:扫描完成但总分 > 50,或触发了--fail-on-findings/--fail-on-incomplete/--min-coverage;2:出错(输入无效、源不可读、内部失败)。
配上 SARIF 输出,就能在 PR 里直接看到「这个 skill 新增了一条数据外泄」的行内注释。对一个团队来说,这一步比装十个扫描器都值——因为它把「人记得去检查」换成了「不通过就合不进去」。
七、当关卡用:挂成 MCP,让助手自己先扫
它还能起成 MCP 服务器,对外暴露一个工具 scan_skill(target, use_llm, output_format):
skillspector mcp
# 或走 HTTP:
skillspector mcp --transport http --host 127.0.0.1 --port 8000
注册到 Claude Code:
claude mcp add skillspector -- skillspector mcp
这样做的意义在于,扫描可以发生在「装」这个动作内部:助手在装一个 skill 之前,先调一次扫描,看到结果再决定。这比「人先跑一遍命令、再回头装」靠谱得多,因为人总会忘。
⚠️ HTTP 模式没有认证,官方只允许绑 127.0.0.1 / ::1,本地路径和 file:// URL 会被自动拒绝。不要为了「让局域网里的另一台机器也能调」把它绑到 0.0.0.0 —— 那等于把一个能读你文件系统的接口公开出去。
八、边界:它不是杀毒软件,更不是沙箱
这一节请连着上一节一起读。官方在文档里把局限写得很直白,逐条列出来:
- 纯静态,不做动态执行。看代码、看文本,不跑它。所以「运行之后才发作」的行为,它看不见。
- 它不是沙箱,不隔离宿主。它只是在安装前把风险标出来,你装了之后它不会替你挡住任何东西。这是最容易产生的误会:扫完显示 SAFE,不等于这个 skill 安全,只等于「在它的规则里没查出问题」。
- 非英文内容可能漏检。规则和 LLM 复核对英文最敏感,中文技能包里的隐晦指令有可能被放过。
- 不分析图片里的文字,也不分析编译或加密后的内容。把指令塞进一张 PNG,或者塞进一个
.pyc,它就看不到了。 - LLM 分析会把文件内容发给你配的 provider。默认 provider 是 NVIDIA 的
nv_build(默认模型z-ai/glm-5.3);要全程本地,用--no-llm,或者配ollama(默认llama3.1:8b)。如果你要扫的东西本身涉密,千万别默认开 LLM。 - 就算关掉 LLM,它仍会连
api.osv.dev查依赖漏洞(只发依赖名和版本)。完全离线的环境要知道这一条。 - Windows 上文件输出功能不可用,因为它依赖 POSIX 的 no-follow 目录操作。这也是本文只标 macOS 和 Linux 的原因——不替它在 Windows 上做「大概能跑」的推断。
- 资源有硬上限:单次摄入 100MiB、zip 解压后最多 10,000 个成员、单文件分析上限 1MB、整次扫描默认 1080 秒超时。超过就直接失败,不是慢慢扫。
还有一个埋得比较深的细节:codex_cli 这个 provider 被官方禁用了,理由是它的只读沙箱允许读取宿主文件——也就是说,把一个能读宿主文件的执行环境,当成「分析器」来用,本身就违反了这个工具的前提。这条禁用理由,其实比任何功能说明都更能说明设计者的立场。
九、怎么用才算用对了
三步就够,不用搞复杂:
第一步,装之前扫一次,只看有没有 CRITICAL 和 HIGH。总分 30 分和 45 分之间的区别,对决策没有意义;有没有一条「数据外泄」才有意义。
第二步,把常装的几个 skill 建一份基线,扔进 CI 或 pre-commit。你要防的不是「今天这个 skill 有问题」,而是「上周还好好的 skill,这周更新里多了一行 curl | bash」——技能包会更新,而更新通常没人看。
第三步,把高危项对应的那段代码自己读一遍。扫描器标出「第 47 行有 os.system」,你得知道它拼的是什么字符串。这一条没法外包给任何工具,也恰恰是这份工具存在的目的:它不是替你判断,是把「该看哪里」指出来。
最后回到开头那个动作。装一个 skill,本质上是在自己的权限范围里执行陌生人的意图。这件事不会因为有扫描器就变安全,但会因为它变得可检查——在这之前,你唯一的依据是 star 数和别人的推荐;在这之后,你至少能看见那 71 种模式里命中了哪几条。
站上写过 claude-mem 那套跨会话记忆,讲的是让助手记住更多东西。这一篇讲的是相反的方向:它记住的东西、它被允许做的事,都来自你装进去的那些包。包不干净,记得越多越麻烦。
↓ 获取资源
点击按钮直接前往资源页面。