你钉住的插件,其实从来没钉住|开发者机会观察

作者:程序员白大力 · 2026-09-29 01:06

封面

这是《开发者机会观察》第7期。这周的主线不在模型有多聪明,而在“信任”这一层被人从底下掏空了。9月17日 air.security 披露 Plugin4Shell:四家主流编码 agent 都把插件钉在某个 commit 上,却从不验证落地的是不是那个 commit,仓库主人一条同名分支就把你钉死的东西换掉;9月18日 Hacktron 又演示把一段藏在 README 里的话喂给 Codex,从一个“本该锁了网络”的沙箱里把密钥带出来。前后这一周,Claude in Chrome GA、Projects 重做的余波还没散。厂商忙着补模型,被反复抽打的却是分发层和上下文层——插件市场、仓库内容、子代理配置,这些以前没人专门盯的地方。下面五个。

一、你挂了一堆插件,没人帮你对账它们落地在哪

一句话是什么:一个本地小工具,把你通过各家市场装的插件列一张清单,记录每个插件实际解析到哪个 commit,下次跑的时候对比,告诉你“它自己动了”。

为什么是机会:9月17日 air.security 的 Plugin4Shell 把根因说得很直白——四家都是 clone 完、checkout 完,从不 git rev-parse HEAD 对一下是不是钉住的那个。攻击者把一个分支名取成那串 40 位哈希、设成默认分支,git 在“同名 ref 和对象 id”之间会优先选 ref,于是钉住的是请求、不是代码;加上插件后台自动更新是默认开的,零点击就换。补丁进度又不齐:Claude 在 2.1.179、Codex 在 0.146.0 修了,Copilot 至今没补丁,Gemini CLI 干脆弃修、让你迁去 Antigravity。也就是说你根本不知道自己装的那套在哪一档。

现有方案不足:air 自己给的修复就一行 test "$(git rev-parse HEAD)" = "<pin>" || abort,那是厂商要在 checkout 后做的事。已有的 contextlock 是给文件内容做封印的,parallax 是 mutation 前后的协议门,都不解决“我到底装了哪些、各自落地在哪、有没有偷偷换”。市场方看不到客户端 checkout 的结果,个人更没人帮你对账。

个人开发者怎么切:MVP 就是个只读 CLI——读你配置里挂的 marketplace 和已装插件目录,对每个跑一遍 git rev-parse HEAD,存一份快照;再跑一次就 diff,标红“这个插件这次解析到的 commit 跟上次不一样”,并提醒“你挂的这个市场后端(Bitbucket 或自建 git)允许用 40 位哈希当分支名”。不执行插件、不改代码,只读。门槛得认:厂商自己在修,窗口在收窄;只对真用多市场或自建市场的人有用;而且你证明不了“它是被攻击换的”还是正常版本升级,工具只报差异。

参考线索:air.security 9月17日 Plugin4Shell 原文;The Hacker News 9月18日报道;对照 mindmodelai/contextlock、parallax-claudecode(都不是干这个的)。

二、README 里藏的话,agent 当成命令照做

一句话是什么:你准备让 agent 去碰一个没读过的仓库之前,先把它 README、AGENTS.md、显眼注释里那些“对 agent 下命令”的句子挑出来,要么挡住、要么包一层“以下不可信、别照做”的标签再交给它。

为什么是机会:9月18日 top10.dev 讲 Hacktron 怎么用一段藏在 README 里的间接提示注入,配上 Codex 自己的 shell 工具,从一个“本该锁死网络”的沙箱里把密钥带出来。它没破模型,破的是“仓库里的文字等于上下文”这条信任假设。上一期我们查的是会自动执行的钩子(postinstall、git config),这一期是另一层——它根本不自动跑,是 agent 自己读了、自己照做。

现有方案不足:各家现在的沙箱(allowedDomains 那套)管的是 shell 能连哪些地址、能写哪些路径,管不了“agent 读到一句话后愿不愿意照做”。HackYourAgent 那类红队 skill 是让你跑对抗测试的,不是你 clone 之前先过一遍的消毒器。安全研究员写得热闹,普通人手里没有“进仓库前先把毒文字挑出来”这一步。

个人开发者怎么切:MVP 先做轻的——读 README/AGENTS.md/入口注释,用规则加一个小分类器,把“运行这个脚本”“curl 这个地址”“把你的 token 设成 X”“忽略之前的指令”这类对 agent 发号施令的句子标出来,包进围栏标签再交给 agent。本地、不联网、不跑仓库里任何东西。门槛得认:正文里本来就写着“运行 npm install”,必然误报;对藏在图片、隐写或 unicode 里的攻击,静态扫描基本看不见;它是减面,不是兜火。

参考线索:top10.dev 9月18日 Hacktron 那篇;vexp.dev 的 README 投毒拆解;往期第6期“陌生仓库自动执行钩子预检”管执行层,这一期补内容层。

三、一个小需求,被它写成了一整套架构

一句话是什么:agent 干完活你跑一下,它把这次 diff 算成一张“膨胀账”——新建了几个文件、加了几个类/接口/工厂、净增行数跟实际改动行数的比,告诉你“这次是不是又过度设计了”。

为什么是机会:Karpathy 那篇被转烂的 CLAUDE.md 总结里专门点了这条——agent 喜欢把一百行能说清的事写成一千行,堆一堆永远不会被用到的抽象,还不清死代码。8月有人吐槽“让它改个老 HTML 的 sitemap,结果它顺手换了配色、重排了文案,还把原文件唯一的备份删了”。社区给的答案几乎全是写规则、写提示词去“劝”它少写,没人拿尺子量。

现有方案不足:drift-analyzer 那类是找“能通过所有测试但结构在烂”的侵蚀;pr-to-spec 是拿改动跟你写的 spec 对偏差;它们要么吃模型、要么要你先写规格。没有人用纯算术告诉你最朴素的一件事:你要的是个小改动,它是不是又凭空多造了一层没人调用的新结构。Ponytail 那类是事前用提示词压着,这是事后量一量。

个人开发者怎么切:MVP 完全不用模型——git status 加 git diff 这次工作区,数新增文件数、新增的 class/interface/enum/factory 声明数、added 跟 changed 的行数比,再列一遍“这次新增的函数,仓库里没有别处调用”。输出一张人话表:“要改 30 行,净增 180 行、新建 4 个文件、2 层抽象没人用”。门槛得认:多写不等于错,有些需求就是需要抽象;它只负责把账摊开,判不判是你自己的事;阈值是拍脑袋定的,别假装它有科学依据。

参考线索:miraflow 转的 Karpathy CLAUDE.md 三条观察;explainx 8月 Opus 5 过度工程那篇 Reddit 反应;对照 drift-analyzer、pr-to-spec(它俩纠错或对规格,不量膨胀)。

四、你装的子代理和技能,模型压根不会选它

一句话是什么:你在 ~/.claude/agents/ 或 skills 目录里攒了一堆子代理和技能,这个小工具扫一遍它们的 description 行,告诉你哪个“模型根本不会路由到”。

为什么是机会:9月6日 dev.to 有人实测,子代理比 skill 失败率高 2.8 倍,而排第一的原因特别蠢——你写了个子代理,description 那行是空的或只有一个词。模型启动时只看得到每个技能约 100 token 的名字和描述,匹配不上就干脆不路由,自己把活干了,还报告“完成了”。这类失败是沉默的:不报错、文件也正常,你第二天才发现压根没人用它。

现有方案不足:skillproof 这类是把你的技能放到干净机器上真跑一遍来验,是付费服务;满网的“skill not firing”博客给的都是手写排查清单。没有一个本地、离线、纯静态的小工具,读一遍你自己的 frontmatter 就打分。claude plugin eval 是给真写插件的人跑 with/without 对拍的,重,不适合日常扫配置。

个人开发者怎么切:MVP 就是个 linter——解析 ~/.claude/agents/*.md 和 skills/*/SKILL.md 的 frontmatter,输出每个的 description 长度、跟同级兄弟的关键词重叠度、有没有“何时用”这半句。红的标“这行描述模型大概率不会路由到”。纯静态、不调模型、不装东西。门槛得认:描述写得好不等于真能触发,最终还得手动跑一次验证;这是给“自己写或攒了一堆子代理”的人用的,普通用户一个子代理都没有。

参考线索:dev.to 9月6日“subagents fail 2.8x more often than skills”;mcp.directory 那条“模型只看约 100 token 描述”;对照 skillproof.dev(真跑测试的付费服务)。

五、agent 一个 rm,把你唯一的备份删了

一句话是什么:给 agent 挂一个 PreToolUse 钩子,在它真去 rm、覆盖文件、往非 git 目录写之前,先把原文件悄悄复制到本地一个 .agent-trash/ 里,出了事能一键拿回。

为什么是机会:上面那条 sitemap 吐槽里最疼的一句是“它把原文件唯一的备份也删了”。agent 干起活来不管 git:一个 rm -rf、一次覆盖、写到一个没纳管的配置目录,等你想退已经没了。内置撤销只在同一个会话里、只对它自己的 Edit 工具有效,一旦它用 Bash 跑命令、一旦你关了会话,就没了。

现有方案不足:git 能兜住仓库里的改动,但 agent 经常在仓库外动手,或者在你 commit 之前就动了;Claude Code 的 undo 不跨会话、不覆盖 Bash 的 rm。往期我们聊过的“越界文件事后审计”是事后看它越界了没,不是给它留一条退路。缺的就是这么一个最朴素的安全网。

个人开发者怎么切:MVP 是一个 PreToolUse hook——匹配 Bash 里的 rm/mv/重定向覆盖、Write/Edit 命中已存在文件时,先把目标按“时间戳加文件路径”拷一份到 .agent-trash/,再放它继续干;提供一个 restore 命令按时间戳找回。本地、零依赖、一个 shell 脚本的事。门槛得认:会占磁盘,得自己定个保留期;它救不了内存里的改动和已经 push 的提交;而且跟 git 功能部分重叠,真正的空白只有“非 git 目录加跨会话”这一段。

参考线索:explainx 8月那条“删了唯一备份”;Claude Code hooks 文档的 PreToolUse;往期第4期“越界文件事后审计”是事后看,这一期是事前留退路。


把这五件摆回这周的大新闻里看,位移很清楚:9月17、18 号那两天被安全圈炸出来的,不是模型变笨了,也不是提示词不够好,而是“分发层”和“上下文层”这两块以前没人当回事的地方——插件市场钉的 commit 不验、README 里的话被当指令、子代理配置沉默失效、干多干少没人量、删了东西没退路。厂商的补丁是反应式的:Claude 和 Codex 堵了 Plugin4Shell,Copilot 还没堵,Gemini CLI 直接弃修。也就是说信任这一层永远在修一个洞、漏下一个洞的节奏里。

跟前几期一个调子:被资本和媒体盯着的角落,窗口一周就关;剩下空着的,是这种说不上多性感、但每天都有人踩的脏活——对账、兜底、留退路。个人开发者挤进去的位置,大概还是这些。

本文由 AI 辅助生成并经人工审核发布,内容仅供参考。