Skip to content
AI Ferryman Alex
Go back

你装技能之前真读过它的指令文件吗?31,132 个技能里 26.1% 带着漏洞

你上次装新技能的时候,是把它的指令文件从头读了一遍,还是只看了市场页面上的介绍就直接装了?我的做法一直是前面那一种。不管这个技能的介绍写得多简单,我都要先把指令文件打开读完,然后才决定要不要继续往下走。

我这么做,是因为技能装上以后并不是待在一个跟我无关的地方运行。它接下来会按照指令文件里的内容去读我机器上的文件,并且还会调用我平常就在用的那些工具,所以一个陌生人写进指令文件里的要求,最后是用我的权限在我的环境里执行。正是因为这样,我才不肯只看介绍页和下载量就把一个技能装进来。

我真正担心的场面是这样的:我为了省下读文件的几分钟,把一个会收集环境变量(也就是机器上存着 API 密钥这类登录凭据的系统变量)的技能装进每天都在用的工作环境里,然后它趁我不在屏幕前把 API 密钥发了出去。等我察觉的时候,往往已经是某个账号出现异常调用了,而它到底读过哪些文件又发出去多少,我事后很难查全。

我做全栈开发已经 24 年多了,过去曾经带过一个 400 人的技术团队,现在仍然是几个大型开源项目的核心维护者。看了这么多年别人写的代码,我对写得含糊的指令反而更警惕。技能装上以后,照着指令文件做事的是 agent,用的又是装技能那个人的权限。正因为这样,指令一旦写得含糊,agent 到底会按哪种理解去执行,就没有人能提前替我确定。真按错的理解执行了,后果还是要由装它的人来承担。

指令文件读完以后,我会把这个技能带的可执行脚本单独打开,一个一个看过去。因为指令文件主要是在告诉 agent 应该做哪些事,而可执行脚本是真的会在我的机器上运行的代码,所以这两样东西的风险并不一样。只要某个脚本里有一段代码我看不明白它为什么要存在,我就会停在那里先把这一段弄清楚,而不是先装上再等出问题以后回头找原因。

我把这套顺序看得这么紧,也跟一项大规模研究的结果有关。这项研究在 2025 年十二月先从 skills.rest 和 skillsmp.com 这两个市场爬取了 42,447 个技能,然后研究者对这批技能做了去重,又过滤掉了一批质量不够的,最后留下 31,132 个唯一的技能。后面我提到的每一个比率,分母用的都是这 31,132 个技能。

从 42,447 个减到 31,132 个,中间一共去掉了 11,315 个。但是这 11,315 个里面,只有一步有精确数字。这一步过滤掉的,是那些已经被删除、打开时只会返回 404 的仓库,这一类仓库一共被这一步移走了 7,353 个。至于剩下的大约 3,962 个分别是在哪一步被去掉的,论文没有逐项给出数字,所以我引用这项研究的时候,也不会替它把剩下的部分拆出一个看起来很细的说法。

做这项研究的工具叫 SkillScan,它是一个研究框架。它先做静态扫描,也就是只读技能的文件和代码,并不运行被扫的这个技能,从读到的内容里找出问题模式,然后再用 LLM-Guard 做一层标记。LLM-Guard 是一套给大模型内容做安全扫描的现成工具。

被静态扫描和 LLM-Guard 这两步标记出来的技能,就是候选技能,随后会交给一个大模型做分类确认,只有分类确认下来的才计入统计。大模型做分类确认时,用的是 SkillScan 的分类法,一共 14 种模式,归在 4 个类别下面。SkillScan 是研究用的框架,SkillSpector 是 NVIDIA 后来发布的产品,两者不是同一个东西。

SkillScan 最后确认的结果是,在 31,132 个技能里有 8,126 个至少命中了 14 种模式里的任意一种,占 26.1%。不过这个口径放得很宽,因为故意写的恶意代码被计入了,作者疏忽写出的不安全代码也被计入了。另外还有一些写法,它们本身没有伤人的意图,但是模式很危险,这类写法同样被计入了。在这几类里面,数量占多数的是作者疏忽写出不安全代码的那一类。

还有一个经常和 26.1% 一起被引用的数字是 5.2%,它对应 1,619 个技能。但是这个数字不能理解成研究者逐个判定了这 1,619 个技能的作者怀有恶意。研究者在分析开始之前就先按模式定死了严重程度,其中 14 种模式里面有 8 种被预先定为高等级。一个技能最后的等级,取的是它命中的模式里最高的那一级。所以 5.2% 说的只是这 1,619 个技能含有至少一个高等级模式。

论文自己也对这个数字作了提醒。研究者把风险最高的 87 个技能拿出来人工复查了一遍,结果只有 23 个能看出明确的恶意迹象。剩下的那些技能同样危险,但是光看它们的内容,分不清作者到底是故意这样写的,还是写的时候疏忽了。正是因为人工复查分不清剩下的技能是作者故意写的,还是写的时候疏忽了,所以我在引用 5.2% 的时候,只会把它说成一个按模式推算出来的代理指标,而不会把它说成已经证实了意图的比例。

还有一个数字直接关系到我为什么要把可执行脚本单独拿出来看。研究发现,带可执行脚本的技能出现漏洞的可能性,是不带脚本的纯指令型技能的 2.12 倍。我对这个差距的理解是这样的。指令写得再有问题,它也要先经过 agent 的理解,然后才会变成动作。脚本不一样,它只要一运行,读哪些内容和往哪里发送就都由代码直接决定,中间没有人能再替我拦一道。

NVIDIA 的 SkillSpector 在仓库的说明文件 README 里放了一份示例报告,这份报告能说明脚本这一关为什么不能省。报告里的技能叫 suspicious-skill,它带了一个放在 scripts/sync.py 的脚本。这份示例报告给这个技能打了 78 分,等级是 HIGH,给出的结论就是不要装。这份报告是 README 里放出来的示例,不是我自己遇到的真实技能。

这份示例报告在这个脚本里列出了两条高等级的发现。第一条发现是,这个脚本会遍历 os.environ,把机器上的环境变量收集起来,而环境变量里面放着 API 密钥这类机密。

第二条发现是,这个脚本会用 requests.post 把它收集到的内容发到一个外部服务器上去。这两条发现要放在一起看,因为单独的收集动作还可以有别的解释,但是收集完了又往外部服务器发送,合起来就是把凭据从我的机器上往外送。

我自己在安装之前用的工具就是 SkillSpector,它是 NVIDIA 发布的产品,仓库地址是 https://github.com/NVIDIA/SkillSpector 。

那 31,132 个技能是研究框架 SkillScan 扫出来的,而 SkillSpector 只是在它的 README 里引用了这项研究的比率。所以「SkillSpector 扫了 31,132 个技能」这个说法是错的,对的说法是扫这些技能的是 SkillScan,SkillSpector 没有扫过它们,只是在 README 里引用了这项研究的比率。

SkillSpector 的分析分成两段来做。第一段是静态分析,做法和前面 SkillScan 的静态扫描相同,也是读技能里的代码和文字,去匹配已知的问题模式。第二段是可以选择开启的大模型语义评估,也就是让一个大模型来读这些文件的内容,判断某段写法放在它所在的上下文里到底是什么意思。因为扫描这个动作本身不会执行可疑代码,所以我才敢在安装之前先拿它扫一遍陌生技能。

我是去看了 SkillSpector 的计分代码,才弄清楚 SkillSpector 是怎么计分的。每一条发现先按严重程度拿到一个基础分。CRITICAL 的基础分是 50 分,HIGH 的基础分是 25 分。MEDIUM 的基础分是 10 分,LOW 的基础分是 5 分。拿到基础分以后,还要再乘上这条发现的可信度。

可信度是扫描器为每一条发现单独给出的数值,取值在 0 到 1 之间,如果一条发现的可信度小于或等于 0,那么这条发现就不计分。如果同一条规则在一个技能里第二次出现,那么第二次只按一半计算,第三次出现只按四分之一计算,再往后出现就不计分了。

计分里有一处细节容易被讲错:1.3 倍这个乘数不是乘在总分上的。发现位于可执行脚本文件里时,乘 1.3 倍的只有这一条发现的得分,出现在指令文件里的发现不乘这个倍数。另外有少数发现本身就带有 51 分的下限,就是说只要命中这类发现,分数至少从 51 分起算。所有发现加完以后,SkillSpector 把总分封顶在 100 分。只要总分到了 51 分,SkillSpector 给出的结论就是不要装。

分数落在 21 分到 50 分之间的时候,结论是谨慎处理。我遇到这种结果,会回到报告里把每一条发现对应的文件重新看一遍,然后再判断这些问题到底是作者疏忽,还是我不能接受的行为。如果我看完还是判断不了的话,那么我就按不要装来处理。不装一个技能,我损失的只是一个方便。但是如果我装错了一个技能,那么我后面要处理的就是它可能已经读过和发出去的那些东西,这个麻烦要大得多。

就算扫完一个问题都没有报,我也不会直接认定这个技能就没有问题。因为 SkillSpector 只做静态分析,所以那些要等到运行时才会出现的行为,它是看不到的。用非英文写的内容,它可能会漏掉。藏在图片里的文字它分析不了,加密过或者编译过的内容它也分析不了。它在自己的说明里也写了,它不会把我执意要装的技能隔离开来单独运行,所以它本身不是沙箱,装完以后的隔离还得我自己另外去做。

我现在的顺序一直没有变过。我拿到一个新技能,会先把它的指令文件从头读到尾,因为我要先弄清楚这个技能打算让 agent 做哪些事情,又打算让它读哪些文件。读的时候,如果指令文件要求读取的文件跟这个技能宣称的功能没有关系,我就会在这一步停下来。如果指令文件要求把内容发到我不认识的外部地址去,我同样会停下来,不再往下看。

指令文件这一关过了以后,我再逐个打开这个新技能带的可执行脚本看,因为前面研究里 2.12 倍的那个差距已经说明,脚本是最容易出问题的地方,而且示例报告里那两条高等级发现也都是出在脚本文件里。脚本都看完以后,我最后才用 SkillSpector 扫一遍,而只要它给出的分数到了 51 分以上的不要装区间,我就直接停手,不会因为这个技能用起来很方便就给它破一次例。

这类装之前先把风险看清楚再决定装不装的文章,我还会接着写。觉得有用的话,欢迎订阅这个博客,或者先收藏起来。我会持续分享 AI、安全与开源这几块里我自己实际查过和用过的东西,后面再有新的技能工具出现,我也会先自己动手跑一遍,然后再把结果写出来告诉你。

来源:数字出自 Liu et al. 2026 论文《Agent Skills in the Wild: An Empirical Study of Security Vulnerabilities at Scale》,由 NVIDIA SkillSpector 仓库在 README 研究背景部分引用,仓库链接见正文。