你只想把一段文字整理成摘要和三个小标题。下载来的技能也这样介绍自己,但往下看几行,它开始要求忽略原有指令、读取本机密钥,还要瞒着用户操作。
前面的功能介绍没有变,后面的权限要求却已经偏离了任务。装一个新技能前,比“它能做什么”更值得多问一句的是:为了做这件事,它到底要碰什么?
这里说的技能(skill),是给 AI 助手的操作说明,有时还附带脚本。NVIDIA 的 SkillSpector 是安装前的检查工具:它读取技能说明与附带文件,给出发现、位置和处理建议;官方还提供目录集合扫描、可选大模型分析及多种报告格式。本篇实跑两种用途:准备装一个技能时,找到超出任务的要求;整理一组自己的技能时,确认有没有漏扫。它出报告,是否修改、如何修改仍由人决定,不会替你自动修复。
先说明:这是 RepoGo 制作的原创练习。我们专门写了三份纯文本样例,只让扫描器读取;没有安装这些技能,没有读取真实密钥,也没有执行样例中的上传要求。下面的 81 分来自这份练习,不是一宗真实入侵事件。
原创关系图。样例里的要求没有执行,箭头表达文字要求之间的关系。
分数先提醒你停一下,行号才告诉你去看哪里
SkillSpector 会检查技能文件,输出发现列表、位置、解释和建议。本期关闭了可选的大模型分析,采用静态检查:按规则读文件,不运行被检查技能的指令。
2026 年 10 月 31 日的两组实跑,macOS 和 Linux 得到了相同结果:
正常版与修正版的文件内容完全相同,保留前者是为了作对照。这不是“工具在真实攻击中拦截成功”,也不是五种漏洞的检出率测试。
81 是工具本版的风险分,不是“81% 的恶意概率”。上表数值来自已保存的原始 JSON 报告。
越权版只有第 7—9 行被定位,却产生了 5 条发现,原因很具体:第 7 行的覆盖指令同时命中两类规则;第 8 行写了两个敏感路径,各产生一条发现;第 9 行的免审批要求再产生一条。
如果只截一张“CRITICAL / 81”的图,这个练习很容易变成吓人的分数展示。真正有用的,是拿着报告去看原文:一个整理段落的任务,为什么需要读取登录凭据?这项额外要求是否来自你本人、是否必要、是否经过授权?在这个原创样例里,任务与要求明显不相称。
公开练习先跑通,别拿待装技能直接试执行
准备 Git、Python 3 和 uv;uv 用来建立扫描器的固定依赖环境。安装后重新打开终端,检查 git --version、python3 --version、uv --version。扫描器本期使用 Python 3.12,入口会通过 uv 准备它。
在没有同名目录的新位置执行:
git clone https://gitee.com/lushengjie/repogo-skillspector.git
cd repogo-skillspector
git checkout --detach 74be2a092b8709ad4998df012ac24561ef6242eb
sh start.sh
这份公开仓库是 RepoGo 的原创中文入口和练习,不是上游代码镜像。启动时会从 NVIDIA 官方仓库下载固定提交 efb4e8c19a20eb468f797ecb0d685ecb5c887960,安装依赖,再逐组扫描。版本为 2.12.0,用于复现本篇,不能理解为永远最新。
实测边界先放在这里:macOS Apple Silicon 的依赖安装和练习扫描分别通过,空目录 start 从下载到结束的整条链路尚未独立验收;Linux x86_64 在 shenji 的 Slurm CPU 作业内完成冻结安装和三组扫描,但源码由本机同步,未验证计算节点冷下载。Windows ARM64、x64 都未实测,不能用启动脚本存在代替兼容性结论。
本练习不需要 GPU 或模型 API key。首次下载需要网络;--no-llm 只关闭模型分析,不等于工具的一切功能都断网——依赖检查可能查询 OSV 漏洞数据库。本轮只有本地 Markdown,没有依赖清单。
结束时应看到:
benign: exit=0, issues=0, score=0
risky: exit=1, issues=5, score=81
repaired: exit=0, issues=0, score=0
DEMO_COMPLETE:三组结果已核对,见 output/comparison.json
没有 DEMO_COMPLETE,或出现“未完成”,就先看 output/*.log 和仓库里的 FAQ.md。不要因为目录里已有一份旧报告,就认定本轮成功。重跑会覆盖同名报告,需要留档先复制 output/。
把报告的第 7 行,接回文件的第 7 行
打开 output/risky.json,找到 issues。每一项的 location.file 是文件,location.start_line 是起始行,category 是发现类型;explanation 和 remediation 分别解释原因与处理建议。
不想在长 JSON 里找位置,可以在练习目录里运行下面这段报告读取命令。它只读取已经生成的 JSON,不再扫描,也不运行样例:
python3 - <<'PY'
import json
from pathlib import Path
report = json.loads(Path('output/risky.json').read_text())
for issue in report['issues']:
where = issue['location']
print(where['file'], where['start_line'], issue['category'])
PY
对应输出为两条第 7 行、两条第 8 行和一条第 9 行。回到 fixtures/risky/SKILL.md,带着行号阅读上下文。第 7 行的 Prompt Injection,是试图让助手丢掉原本约束的指令;YARA Match 是另一类模式匹配发现。同一段话可以同时命中两类规则,发现数不会自动等于独立问题数。
源码局部为本期原创文件原文重排。图中不是终端或扫描器界面;没有实际执行任何越权要求。
再看 fixtures/repaired/SKILL.md:它只允许使用当前对话里的段落,不读本地文件、不运行命令,并要求在外部变更前询问用户。这份文件恢复为正常版的相同内容;复扫回到 0 条,说明本组规则不再命中这些文字,仍不能给整个技能发一张“安全证书”。
自己有一组技能时,零发现也可能只是没扫完
第二种用途面对的是技能维护者:准备把会议纪要、表格说明等多个自写技能交给别人使用,你关心的不只是“有没有发现”,还要确认这批文件是否都检查到了。
11 月 2 日,我们在同一固定版本的 macOS 环境中新建了两个纯文本教学技能:meeting 只整理用户粘贴的会议记录,table 只解释用户粘贴的表头。它们没有脚本、依赖清单、外链或私人材料。这里演示的是集合扫描的覆盖检查,没有执行会议整理或表格生成任务。
下面的 Python 命令在练习仓库中新建独立目录;如目录已存在会停止,避免覆盖旧内容:
python3 - <<'PY'
from pathlib import Path
root = Path('collection-demo')
if root.exists():
raise SystemExit('collection-demo 已存在,请换一个空目录名称')
for name, title, task in [
('meeting', '会议纪要整理', '将用户粘贴的会议记录整理为议题、决定和待办。仅使用本次对话文本,不读本地文件、不执行脚本。'),
('table', '表格列说明', '根据用户粘贴的表头与虚构样例,写出每列的中文含义。只处理用户提供的内容,不访问外部资源。'),
]:
folder = root / name
folder.mkdir(parents=True)
(folder / 'SKILL.md').write_text(
f'---\nname: repogo-{name}\ndescription: {title}\n---\n\n# {title}\n\n{task}\n',
encoding='utf-8')
PY
准备好前面的扫描器后,先故意把本次集合扫描的技能上限设为 1:
.runtime/upstream/.venv/bin/skillspector scan collection-demo --recursive --max-skills 1 --no-llm --format json --output output/collection-partial.json --fail-on-findings --fail-on-incomplete
--recursive 在这里把直接子目录里的 SKILL.md 分别当作一个技能;--max-skills 限制本次最多处理多少个。报告是零发现,命令却返回 1,因为两个技能只扫了一个。把上限改为 2,再保存另一份报告:
.runtime/upstream/.venv/bin/skillspector scan collection-demo --recursive --max-skills 2 --no-llm --format json --output output/collection-complete.json --fail-on-findings --fail-on-incomplete
这两份真实结果说明,“没发现”与“扫完了”是两件事。交付前可以把“不完整就停止”作为检查条件,避免一个零分掩盖了另一份还没看过的文件。100% 只表示本次配置下这两份文件的覆盖,不是覆盖了全部安全风险;提高数量上限也不能保证任意大集合都会完整完成,其他资源上限仍然有效。本新增场景仅在 macOS 验证,Linux 和 Windows 没有补跑。
换成自己的技能时,先把边界留住
将待检查技能放在独立目录,先不加入 AI 助手的自动加载目录,也不运行其中脚本。读清来源和内容后,用已经建好的扫描器检查本地路径,例如 macOS / Linux:
.runtime/upstream/.venv/bin/skillspector scan "/绝对路径/待检查技能" --no-llm --format json --output output/my-skill.json --fail-on-findings --fail-on-incomplete
这是替换路径用的操作示例,本篇没有检查你的文件。先确认目标不含不能交给第三方服务的私人材料,并根据实际启用的分析器核对联网行为。
Windows 的说明入口是 py -3 run.py start,扫描器路径是 .runtime\upstream\.venv\Scripts\skillspector.exe;这一平台仍未实测,需要单独核对原生依赖,不能直接照抄本篇的 Mac 结论。
命令中的两个 --fail-… 选项要求:存在发现,或分析未完整完成,就返回失败状态。因此退出码 1 不一定是程序崩溃。本版扫描的 1 可以来自发现、阈值或不完整分析,执行错误通常为 2;要一起检查 execution_successful、analysis_completeness.is_complete 和日志。完整性字段说明本次请求的检查是否完成,不证明所有风险都已覆盖。
还有两种常见误读需要避开。危险语句出现在安全教程的引用里,也可能需要结合语境复核,这是误报的可能性,本期没有专门测量误报率。反过来,没有命中规则,也不证明不存在隐蔽逻辑或运行时问题,本期没有测量漏报率。不要只为把分数变成零而删除正常配置、屏蔽规则或忽略报告。
是否安装,最后仍要回到用途、来源、必要权限和可承受的影响。扫描器的价值,是让你更快找到该看的位置,而不是替你省掉这次判断。
上游:NVIDIA / SkillSpector,Apache-2.0。公开练习:RepoGo Gitee。RepoGo 补充了中文入口、原创三组对照、报告读法和真实排坑记录,没有汉化扫描器,也不代表 NVIDIA 的安全认证。完整交付记录整理在 RepoGo 知识星球;本篇的公开练习和操作步骤可以独立使用。
本文由 AI 辅助编写,配图为原创说明及真实报告数值重排。所有样例仅作为惰性文本扫描,未执行其指令;图文不构成全面安全审计。
本文由 AI图鉴自动抓取并翻译,版权归原作者所有;如需查看原文请点下方链接。