乐于分享
好东西不私藏

AI 时代的github上,你连 README 都不能相信

AI 时代的github上,你连 README 都不能相信

一条 npx 命令引发的越界问题

案例:为什么我的每一个agent工具里都被安装了这个skill

最近一个朋友跟我讲了一个很典型的 Harness Engineering 的问题:

"他使用npx skill add命令从github上安装了一个 skill 之后,发现这个 skill 不只出现在当前使用的 Agent 工具里,还出现在了机器上的其他 Agent 工具里。本来以为只是给 Codex 装一个 skill,结果 Claude Code、Cursor 或其他支持 skill 的工具目录里,也出现了这个skill。"

我听到之后第一反应就是: "这个 skill 是不是藏了恶意的脚本,用户下载之后就开始自动传播?”

抱着这个想法我去github上看了一下这个代码库. 哟嚯,这个skill有 5.6K 的star, 700+的fork. 看完之后我发现真正的问题不在 skill 文件本身,而在代码库 README 里推荐的一条安装命令。

这条命令是这样的,为了不给任何人打广告,我就不贴原文了:

npx -y skills add xxx/xxx -g --all

当我自己看到这条命令时,我第一反应也是:安装这个项目的全部 skill。但实际上当我把这个代码库丢给我的codex,和它描述了我朋友的问题,要求codex追查问题的时候,我发现我对这个命令的理解错了:

我们来看这条命令里的三个参数:

-y
-g
--all

-y 的意思是跳过确认。

-g 的意思是全局安装。

--all 在这里的意思不是“安装这个项目里的全部内容”这么简单。它在 skills 这个安装器里的真实含义是:把这个 skill 安装到它支持的全部 Agent 工具目录里。

也就是说,用户以为自己在做的是:

给当前 Agent 安装一个 skill

实际发生的是:

把这个仓库里的 skill,全局安装到本机上多个 Agent 工具目录里,并跳过确认

这也不是传统意义上的病毒。代码里也没有看到它偷偷下载后门,也没有看到它去读取 token、注册启动项、复制剪贴板内容。

而真正的问题是: 这个代码库的 README 里的安装说明本身越界了。

README 把一个影响范围很大的命令,包装成了普通安装命令。用户没有被告知这条命令会影响哪些工具,也没有机会在安装前确认写入路径。这本身在软件工程领域就是一个极其严重的问题

问题的根源是skills add这条命令

如果我们把 npx -y skills add xxx/xxx -g --all 这条命令拆开:

npx 的作用是运行一个 npm 包里的命令。比如:

npx skills add xxx/xxx

意思是临时运行名为 skills add 的 npm 命令,让它去安装某个 skill 仓库。

在这个案例里,skills 不是被安装的那个 skill,而是一个第三方安装器。被安装的内容是后面的 xxx/xxx 仓库。

所以这里有两层东西:

skills CLI:负责安装
xxx/xxx skill 仓库:被安装的内容

真正执行写入目录、选择 Agent、处理 --all 参数的,是 skills 这个 CLI。

这个 CLI 本身支持很多 Agent 工具,比如 Claude Code、Codex、Cursor、Gemini CLI、Windsurf 等。它内部有一张表,记录每个 Agent 的 skill 目录在哪里。

例如:

Claude Code -> ~/.claude/skills
Codex       -> ~/.codex/skills
Cursor      -> ~/.cursor/skills

当命令里写了 --all,它就不是只选择当前正在使用的 Agent,而是选择它支持的全部 Agent 类型。

这就是很多人容易误解的地方。

--all 的真实含义

普通用户看到 --all,很容易理解成“安装全部 skill”。

但在这条命令里,--all 的真实效果更接近:

安装全部 skill 到全部 Agent,并跳过确认

它等价于:

--skill '*'
--agent '*'
-y

这三个东西合在一起,风险就变大了。

--skill '*' 表示安装仓库里的全部 skill。

--agent '*' 表示目标是安装器支持的全部 Agent。

-y 表示不要再问用户,直接执行。

再加上 -g,就变成全局安装。

所以这条命令完整展开以后,不是一个小范围安装命令,而是一个全局、多工具、无确认的批量写入命令。

这就是为什么用户会觉得“它怎么跑到我其他 Agent 工具里去了”。

不是因为 skill 自己会传播,而是因为安装命令要求安装器这样做。

工程边界在哪里被打破了

这个案例最严重的地方,它打破了工程边界。

用户的边界是:

我正在当前 Agent 里安装一个工具。

命令实际执行的边界是:

我正在改写本机上多个 Agent 的全局配置。

这两个边界完全不是一回事。

当前 Agent,是一个很小的范围。本机所有 Agent,是一个很大的范围。

当前项目,是一个更小的范围。全局目录,是一个长期生效的范围。

README 里的安装命令,把这些范围全部混在一起了。

如果这个问题发生在我以前工作的公司,如果是 QA 发现这个问题,毫无疑问是 P0 的 BUG. 如果被客户发现这个问题, 连 RD 带经理一起处理,全团队还要开复盘. 简直要被永远钉在耻辱柱上。

在 Agent 工具里,这个问题的风险性更大。因为 skill 不是普通库文件。普通库文件一般只有在代码显式调用时才会执行。skill 更像是一层给 Agent 看的行为指令。它会影响 Agent 如何理解任务、如何触发流程、如何写文件、如何调用工具。把一个 skill 写进多个 Agent,相当于同时改变多个 Agent 的工作环境。如果用户在安装之前就被告知这件事,并且明确同意安装,那没有问题。但问题是用户不知道啊,我翻遍整个 README 也没看到这个代码仓库的作者对这条安装命令有任何安全提示. 我十分怀疑这个readme也是用 AI 写的,作者根本就不看.

我们深入的问一句: 这是恶意的吗?

从目前我们看到的证据,不能直接说这是恶意传播。

因为真正的安装行为来自第三方 skills CLI。--all 是这个 CLI 公开支持的功能。被安装的 skill 仓库并没有自己写一段脚本去扫描所有 Agent 目录,然后偷偷复制自己。但不能因为不是恶意,就说问题不严重。

软件工程里有绝大多数事故,并不是开发者有主动"作恶"的意图. 而是质量的 BUG. 今天这个问题的性质更接近:

文档诱导型越界 bug

也就是说,代码功能本身是公开的,但 README 推荐的使用方式会把用户带到一个远超预期的作用域里。
这应该按严重问题处理。我甚至认为,在 Agent 工具生态里,这类问题可以按 P0 级别看待。它改的不是一个项目目录,而是用户本机多个 Agent 的全局行为环境。它还通过 -y 跳过确认,让用户没有机会在执行前看到影响范围。

两个库分别负什么责任

这里有两个责任主体。

第一个是 skills CLI。

skills CLI 是一个第三方 npm 安装工具,包名叫 skills(你没看错,这个 CLI 的名字就叫skills). 代码仓库在github的 https://github.com/vercel-labs/skills。从仓库归属看,它由 Vercel Labs 维护. skills CLI 是一个 Agent skill 的安装和管理工具。它的具体功能包括:

  • • 从 GitHub 仓库、npm 包或本地目录里寻找 SKILL.md 文件。
  • • 读取 skill 的名称、描述和目录结构。
  • • 按用户指定的目标,把 skill 安装到不同 Agent 工具的 skill 目录里。
  • • 支持 Claude Code、Codex、Cursor、Gemini CLI、Windsurf 等多个 Agent。
  • • 提供安装、删除、列出、搜索、更新、初始化等命令。

它定义了 --all 的含义,也维护了 Agent 支持表。它知道哪些 Agent 会被写入,知道每个目录在哪里。作为安装器,它应该对高影响操作有更强的提示。

比如:

你即将安装到 50 多个 Agent 目标。
你即将写入以下全局目录。
这不是只安装到当前 Agent。
是否继续?

更好的做法是,--all 不应该默认跳过这些提示。即使用户传了 -y,涉及全局、多 Agent 的写入,也应该有特殊保护。

第二个是 使用这条命令: npx -y skills add xxx/xxx -g --all 的skill仓库作者。

他在自己的 README 里推荐了:

npx -y skills add xxx/xxx -g --all

这就是他要负的责任,而且我得说这种行为非常的不负责:README 面向的是用户。用户不会先去读第三方 CLI 的源码,也不会知道 --all 在这个上下文里到底是什么意思。代码库的作者要为自己写的每一个字负责, 但是他把这条命令放在“通用安装方式”下面,普通用户就会认为这是安全、推荐、默认的安装方式。

更合理的写法应该是:

npx skills add xxx/xxx --list

先列出可安装内容。

如果用户只用 Codex,就写:

npx skills add xxx/xxx -a codex

如果用户只用 Claude Code,就写:

npx skills add xxx/xxx -a claude-code

是否全局安装,应该单独说明。是否安装全部 skill,也应该单独说明。是否跳过确认,更不应该作为默认推荐。

我们应该怎么防

这个CASE给我的最大提醒是:

不要盲目相信github上的star, fork. 也不要相信把代码上传到github上的人就对自己的代码完全了解.

尤其是看到下面这些组合时,必须停下来:

npx
curl
wget
-g
--global
-y
--yes
--force
--all
*

这些词单独出现不一定危险,但如果组合在一起,就说明这条命令可能会拉取外部代码、跳过确认、全局安装、批量写入。

这时候应该先做静态调查。

比如:

这个命令背后运行的是哪个包?
这个包是谁维护的?
--all 到底是什么意思?
-g 会写到哪里?
-y 跳过了哪些确认?
会不会影响多个 Agent?
有没有回滚方式?

如果查不清楚,就不要执行。

对 Agent 来说,这应该变成 harness 规则,而不是靠人记住。

只要命令同时命中:

外部执行入口
全局安装
跳过确认
全量目标
Agent 配置目录

就应该默认拦截,先审计,再决定是否执行。

最后

这个案例暴露出来的问题很扎心:在 AI Agent 时代,不能把信任交给除了规则和铁律以外的任何形式

以前我们看一个github上的代码库,如果有 4 位数的star, 700+的fork,我们默认是"有这么多的程序员认可", 也只有从事软件研发的人员才会去安装,fork开源代码库. 到了 AI 时代,agent的coding能力极大的扩展了github的受众群体,我们现在只能认为"有这么多 AI 的使用者对这个代码库感兴趣".

过去我们读 README,会默认它是项目作者认真写下来的说明。这个默认信任在今天已经不可靠了。现在大量 README、安装说明、配置教程,可能都是 AI 生成的。AI 生成内容最大的问题,不是它一定会胡说,而是它经常把“看起来合理”的东西写得很顺滑。命令格式对了,语气也像官方文档,但里面的边界、权限和后果,可能根本没有被认真审查过。

唯一稳妥的做法,是保护好自己的电脑和服务器。这就意味着每一个 AI Agent 的用户必须要建立起自己的harness。它应该在命令执行前拦住高风险组合,比如今天我们看到的:

npx / curl / wget
-g / --global
-y / --yes / --force
--all / *
~/.claude / ~/.codex / ~/.cursor / ~/.agents

只要命中这些组合,就先停下来,静态审计,再决定能不能执行。
这次事故的教训很朴素:

1.不要相信一条看起来正常的安装命令。

2.不要把 README 当成权威。

3.不要指望写 README 的人,或者生成 README 的 AI,替你保护你的机器。

4.真正可靠的做法,是在自己的 Agent 前面加门禁。先保护执行环境,再谈自动化效率。

关注我的公众号, 我会定期分享harness engineering, 软件工程,本体论建模,AI 应用开发的内容