问问助手

依赖被投毒,先查谁有按回车的权限

2026-10-07 Aryee 1

先把你大概率会听到的一句话放在这儿:"我们没被入侵。"

这句话今年听来要格外小心。它通常只覆盖你的服务器、你的账号、你的网络边界,而不覆盖你的团队每天往自己机器上装的那些东西——那些东西由外面的人发布、由你的机器自动执行、还常常拿着你最好的一批钥匙。过去一年最疼的一批事故,不是谁打穿了谁的防火墙,是有人把一段代码放进了你自己要装、并且自己给了权限的那个包里。

老板侧要做的判断只有一个:这件事的钱该花在哪一格,以及那一格现在由谁负责。 这篇就答这个。

一、先把"投毒"这两个字拆开:它不发生在你想的那个地方

漏洞被利用是"别人进了你的房子"。投毒不是。投毒是"你请进来的东西,自己在你房子里配了一把钥匙"。三条链要分开看:

  • 写代码那一环:人从公网取一个现成的包来用。今天几乎所有的业务系统都是这样堆起来的,一个中等规模的项目里,自己写的代码往往只占很小一部分,其余是第三方与间接依赖。
  • 构建那一环:一台机器(或者云上的一次流水线任务)把依赖装齐、打成制品。出事的多半是这一环,因为这一环同时具备三样别人没有的东西:它自动执行第三方代码、它持有发布与部署的凭据、它产出的东西会被送到更多机器上。
  • 发出去那一环:制品到了客户机器上。如果你的交付是"把跑起来的东西交给对方、对方机器上不留源码",那这串依赖是跟着你的制品一起走出去的。

这三条链上,你的防火墙、你的入侵检测、你的等保测评,覆盖得最好的是第三条,覆盖得最差的是第二条。而 2026 年这一年,攻击者明确把枪口对准了第二条——多家安全厂商在年度回顾里给的判断都是这一句:攻击目的从"找软件漏洞"转向"夺开发者的权限",路径主要落在四个维度:AI 编程辅助工具、招聘流程钓鱼、开源依赖本身、持续集成与交付流水线。

二、把市场这一年摆出来(带日期,也带口径)

下面这些是公开情报与媒体回顾里的内容,日期和规模照原样抄,具体数字以各家公告为准。方向我是信的,但你要拿去立项时,别把某一颗数当成依据——这是我在这个站上反复讲的那条口径:厂商情报的颗粒度不是审计口径。

  • 2025 年秋季,一批每周下载量以十亿次计的核心包被植入恶意代码。一家中文安全媒体的年度回顾点到了十几个包名,其中包含那种"每个前端项目都间接装了一次"的基础工具包。这类包的可怕之处不在流量,在于没人会觉得装它需要理由。
  • 2025 年 12 月,同一生态的第二波攻击里出现了会自我复制的蠕虫:它感染开发环境后窃取认证凭据,再自动向这位开发者有权限的其他包二次传播。损害的速度不再取决于攻击者有多勤快,而取决于受害名单里谁的权限最大。
  • 2026 年 3 月下旬,一款被广泛使用的开源漏洞扫描工具自身遭入侵;紧接着,一款把大模型接进业务系统的中间库也被攻破。分析把两起指向同一攻击组织——挑扫描工具和目标库,意思是它要的是流水线的入口,不是你的业务代码。
  • 2026 年 4 月,针对开源项目的恶意合并请求数量突破 500 个,呈机械式批量投递、目标是捞开发者认证信息。同月,一款几乎人人都在用的网页请求库的开发账号被侵害,业界那句评价很直白:这种量级的单个包失陷,足以让全球一大片网页瘫痪。 也是在这个月,出现了伪装成某知名密码管理器官方命令行工具的单包投毒,以及针对某大型企业软件生态的四个包(周下载量约 57 万)。
  • 2026 年 6 月 1 日,一家做企业开源发行版的厂商,它自己的包命名空间下 32 个包被投毒,周下载量约 8 万。这一条值得单独记住:"官方命名空间"不是护身符,它只是让审核人少看一眼。
  • 2026 年 7 月底,一家云厂商的威胁情报把包括上面那个请求库在内的四起攻击,关联到同一个国家级黑客组织。
  • 2026 年 8 月 4 日,微软威胁情报披露了一场代号 ChainDrop 的大规模投毒:超过 400 个包在一夜之间被注入恶意代码,横跨多个互不相干的发布者,其中包含几款缓存类的高下载量组件。载体是一个恶意提交,被直接推进了其中一款包的发布线;负载是会自我传播的窃密蠕虫的轻量变种,打包方式换了、混淆很重,在安装阶段自动执行,不需要任何人与任何确认。
  • 同一个月被反复拿来比较的另一起:一百四十多个包在九十分钟内全部沦陷。

还有一条市场侧的信号,它说明这一格正在从"技术自觉"变成"审计项":一家专做流水线与制品安全的厂商在 2026 年 7 月的年中更新里写,他们的买方构成从初创与中型科技公司,转成了上市企业、大型 AI 公司和受监管行业(金融服务、资本市场、抵押贷款与金融科技、媒体与游戏、国防科技、医疗、企业软件),并且很多老客户在第一次续约之前就加购了覆盖面。翻译成你听得懂的话:审计方已经开始问这一格了,而它过去不在任何一张检查表上。

三、为什么能"一夜四百个包":三格机制,一格都比一格便宜

看懂这三格,你就知道钱该往哪儿放。

第一格:装包的那一刻,代码是自动执行的。 依赖包里可以带一段"装完我之后先跑一下我"的脚本,这是包管理器的正常功能,用来编译原生模块、准备缓存。它的问题是默认允许:没有人看过那段脚本,也没有人需要在场。你不需要被骗点击任何东西——这正是今年那一系列事件里最反直觉的一句:攻击者不需要攻破你的防火墙,他只需要骗过你的一次安装。

第二格:它先搜刮凭据,再用你的身份发新包。 公开分析里对这种蠕虫的动作顺序描述得很清楚:第一步翻遍这台机器上的包管理器配置、环境变量、密钥文件;第二步用拿到的身份去访问代码托管、云、密钥库;第三步枚举你名下的所有仓库和包,读取流水线里的密值;第四步把收集到的东西加密回传;第五步——也是让它能"一夜四百"的那一步——用你的账号发布新的恶意包。所以这件事的规模从来不是"一台机器",而是"这台机器上那个人有权限的所有东西"。

第三格:批准人从"你"变成了"流程里的一个默认值"。 今年秋天出现了两起被完整复现的攻击形态:一个看起来人畜无害的开源仓库,靠写自述文件里的说明、写配置文件里的工具授权,让编程助手以它主人的权限把恶意流程跑起来。国内安全媒体那两篇复现的标题起得很准——「从说明文件到远程执行」「回车即沦陷」。这件事的本质不是模型变坏了,而是你把自己没有对任何人开放过的那一套权限,交给了一条自动执行的路径,而这条路径会照抄你塞给它的任何一句话。

四、这笔钱花在哪一格:四档,各自挡住什么、挡不住什么

这四档不是"要不要做",而是"你先把钱放在哪一条链上"。它们的价格、负责人、能否退回,全都不同。

档一:只让机器从你指定的仓库取包(私仓代理)

做法是一句话:机器不允许直连公网包源,所有依赖经过你自己的中转仓库取。它挡住的很具体:陌生包直接进机器、装错名字的山寨包、以及事后追认——因为中转仓库会留下"什么时候、哪个项目、取了哪个版本"的账。

它挡不住什么要说清楚:挡不住已经被投毒的正式版本。那一版在源头本来就是"正牌作者发出来的正牌版本号",你的中转仓库会老老实实替你把毒也缓存一遍。所以这一格的价值不在拦截,在于你有一份可以回答"哪天开始有的"的账。

代价:最便宜的一档,通常一到两天做完,之后几乎不占人力。对你交付客户的场景还有一层附带好处——客户环境断网也能装出同一棵树。

档二:锁定版本,并且用只读方式扫一遍

两件事。第一件是把依赖树锁死:今天装出来的东西和昨天装出来的必须逐字一致,任何新增依赖都要显式承认。第二件是扫描,但扫描必须只读——不能为了查一个可疑包就把它装起来跑一遍,那正好是它想让你做的事。今年这批事件之后,业内开始出现明确只读的扫描器:只读磁盘上的锁定文件、包的元数据与配置清单,绝不执行安装脚本,覆盖面从几种主流语言生态一直扩到工具授权配置与智能体的技能锁文件,并且带一份公开的历史事件目录做精确匹配。

它挡住什么:发现。它挡不住什么:挡不住"装的那一刻已经执行了"这一格——扫描器读的是磁盘上的清单,它判的是形迹,不是行为。代价:便宜,但要人看。没人看的扫描等于没有扫描,这一句要写在分工上,而不是写在制度里。

档三:构建那一台机器不再长期持有发布钥匙

年度回顾里给出的三条护栏,最硬的就是这一条:把流水线里的长效凭据换成短效的——每次任务临时申请、按角色收窄、用完即失效。同时把"能发布包"的权限从"能构建包"的权限里拆出去:构建机可以装任何东西,但它拿不到往外面发布的身份。

为什么这一格是唯一改变"中招之后能走多远"的:第一格与第二格决定的是会不会进来,第三格决定的是进来了能不能借你的身份出去。上面那起"一夜四百"的战役,传播动力完全来自被窃取的那几把长期有效的钥匙。

代价:这是四档里唯一"动过就回不去"的一档。它要改流水线定义、要通知所有还在拿旧密钥跑的脚本、要处理那些"从 2019 年活到今天、没人知道谁在用"的定时任务。工期不在技术上,在问人上。建议先只做构建机这一块,别一次全公司铺开。

档四:谁能发版,以及名字归谁

这一档不是软件成本,是组织成本,但它管住的是最前面那格机制的入口:

  • 发版是双人动作:任何一个包的新版本推出去之前,有第二个人看过这一版多了什么。
  • 包名要先把坑占住:投毒常用的一招是注册一个和你要用的包差一个字母的名字。这类事在采购单上看不见,出了事才知道。
  • 离职与外包账号的回收要能证明:那起蠕虫的第二步就是"枚举你名下所有仓库"。如果前任的账号还能动,你的"名下"比你想的大。

五、发现时效才是那笔账:中招的判据不是"有没有收到告警"

把老板真正该问的那一句写出来:从那枚提交进发布线,到你停手,用了多久。

这个数才决定损失范围。以九十分钟沦陷一百四十多个包那种速度,一晚上才反应的团队和一周后才发现的团队,赔的完全不是一回事。所以我的建议是把这一格做成可查的东西,而不是做成一句口号:

  1. 有一份"我们用了哪些外部组件"的清单,并且它每天自己更新。清单不在,一切都谈不上——你连"该查哪几个包名"都答不出来。
  2. 知道哪台机器上有钥匙。构建机、发布机、跑定时任务的机器,各持有哪一类凭据,这份表比安全制度有用得多。
  3. 有一个能在两小时内说"停"的动作:中转仓库一键切断某个版本、流水线一键停用某类任务。没有这个动作,发现得再早也只能看着。

三个可以分开批的小决定,不用一次做完:先只把构建机的凭据换短效;先只把"发布"和"构建"这两个权限拆开;先只审依赖里新增的执行脚本。这三个都不需要买工具,都能单独验收。

六、两种最贵的形态,都和钱没关系

第一种:所有钥匙在同一台机器上。 一台既装依赖、又跑流水线、又持有发布身份、又连着密钥库的机器。它平时最好用,出事时最贵——上面那起战役要的就是这一台。拆它的动作不难,难在没人敢动,因为没人说得清上面还挂着什么。

第二种:只有搭流水线那个人知道钥匙在哪儿。 这个形态我在别的篇里写过,它在这里同样成立,而且更严重:如果只有一个人清楚哪台机器上装了哪一串依赖、哪把密钥还能用,那么请假两周的那个人,就是你整条发布链的单点。判据不需要猜:随便挑一个工作日,让第二个人独立发一次版,并且能列出"谁能往生产里放东西"这份名单。 列不出来,就是这一种。

七、你把系统交给客户的时候,这串依赖是跟你一起走出去的

这一节写给做交付的人。客户要的是"能跑起来的东西",客户机上不留源码——这没有问题,但依赖树是跟着制品走出去的。也就是说:

  • 你装的每一个第三方组件,都进了客户的环境,也进了客户的安全审计范围。
  • 客户出事时,第一个被问的是你,因为清单上的发布者是你,不是那个上游作者。
  • 合同里那句"不含第三方组件引发的安全责任",值多少钱取决于你能不能拿出上面档二里那份"哪天开始有的"的账。拿不出来,这句话就是一张纸。

反过来说,这一格做完之后是可以当卖点讲的:"我们的交付物带完整的组件清单,任何一个版本被追认为有问题,我们两小时内能告诉你在哪几台机器上跑着。" 这是能对甲方安全部门讲、且讲得出证据的一句话。

八、最后一句

不要把它当成"要不要再买一个安全工具"的问题。这一年公开出来的事件里,中招的东西没有一样是买工具买回来的:它们是一枚被推进发布线的提交、一个装完自动执行的脚本、一把长期有效的钥匙、一份没人看的清单。

你真正要管的是"谁有按回车的权限"这件事——包括你自己都不知道给了谁的那几份。

你手上那套系统,卡在哪一步?

留个手机号和方便的时间,我打过来先听你说现状与约束,再给可执行的判断:这套系统是该继续修、该动哪里,还是干脆重做一版设计更省。

约一次沟通不接纯 UI 外包,只做系统层面的问题。