-
-
一个Shai-Hulud,差点攻陷整个npm生态
-
发表于: 15小时前 226
-
毫不夸张地说,如果没有平台的介入,整个npm生态的依赖包都会被Shai-Hulud蠕虫感染。
从2025年9月至今,黑客组织TeamPCP利用Shai-Hulud,发动了3轮特大规模供应链投毒,数千个npm包被攻陷,其中不乏CrowdStrike、SAP、TanStack、AsyncAPI、Postman/PostHog这些知名公司和明星软件包。
Shai-Hulud(2025/09)
Sha1-Hulud / Shai-Hulud 2.0(2025/11)
Mini Shai-Hulud(2026/04-2026/05)
与常规供应链攻击攻陷单个热门依赖包不同,Shai-Hulud在攻陷零号感染者后,会自动感染受害者所属其他npm包,最快可在30分钟内感染超过600个版本,因此被认为是npm生态首个大规模自动化传播的供应链蠕虫。
更令人担忧的是,今年5月,TeamPCP公开了Shai-Hulud源码,这就意味着它正在成为一个去中心化的黑产工具,迭代速度、投毒规模将远超想象。
回顾Shai-Hulud所有关联的攻击,零号npm包的失陷过程,已经成为最关键的问题,对于防范供应链攻击至关重要。对此,微步情报局进行了全面分析。
本次完整分析报告(含完整攻击过程、代码分析、投毒恶意包)暂不开放线上获取,如有需求,请联系我们的工作人员。
初见:npm生态的首个供应链蠕虫
Shai-Hulud第一次在npm平台出现,是2025年9月14日17:55(UTC),医疗软件开发商RXNT旗下名为rxnt-authentication的npm包感染恶意代码。代码比较简单,主要是通过下载/运行TruffleHog扫描窃取凭据。
至于具体感染方式,目前尚不得而知。但由于其不通过GitHub CI/CD发布,所以只能是维护者techsupportrxnt的npm token泄漏导致。
微步情报局推测,TeamPCP一定是通过某种方式,如使用GitHub Pwn Requests攻击,窃取到了GitHub Actions runner中维护者的npm token,进而篡改、发布恶意版本。
由于Shai-Hulud会自动利用窃取到的npm token,篡改、发布受害者所属的其他npm包,因此本轮投毒很快形成了规模化扩散。
短短3天内多达500+npm包迅速失陷,传播速度之快前所未有。其中受影响比较严重的有:
lrxnt-authentication@0.0.3 (17:58:50)
ljson-rules-engine-simplified@0.2.1 (17:58:51)
lreact-jsonschema-form-conditionals@0.3.18 (17:58:52)
lencounter-playground@0.0.2 (17:58:52)
lrxnt-healthchecks-nestjs@1.0.2 (17:58:53)
lrxnt-kue@1.0.4 (17:58:54)
在npm平台的快速干预下,2025年9月18日,这轮投毒活动告一段落。然而危险的种子已经种下,npm token依然暴露在攻击者面前,这也为下一轮更大规模的投毒埋下了伏笔。
2.0:持续利用npm token暴露面
果不其然,两个月后的2025年11月24日凌晨(UTC),Shai-Hulud 2.0来了。
TeamPCP对蠕虫代码做了部分调整,包括新增了持久化手段以及破坏性的手段,在无法获取GitHub/npm token时,删除当前用户主目录中的数据。
@zapier、@asyncapi、@postman、@posthog等npm包接连出现恶意版本,共同成为了第二轮投毒的零号感染者。
在所有失陷分析报告中,PostHog提及了一个关键错误配置:pull_request_target。
维护者在使用Github流水线自动发布npm包时,会提前配置需要的npm token,因此存在一个长时间的暴露窗口。TeamPCP正是抓住了这个机制,利用pull_request_target的配置缺陷,在官方服务器运行攻击脚本,窃取了npm token。
结合失陷厂商的分析报告,微步情报局还原了零号感染者的失陷过程。
第一步:流水线审计
攻击者通过研究项目的GitHub Actions workflow,发现项目使用pull_request_target,并且会checkout提交PR的代码、执行仓库内脚本。
第二步:植入恶意载荷
攻击者fork项目,并在个人副本仓库中,修改将被官方工作流调用的脚本或测试文件,植入恶意载荷,它的作用是静默读取当前进程环境变量、内存空间以及外传凭证。
第三步:触发恶意代码
攻击者向目标项目提交Pull Request(PR),激活官方仓库的pull_request_target工作流,在缺乏安全隔离的情况下,触发了恶意代码,导致环境中默认全局共享的npm token失窃。
第四步,发布恶意版本
攻击者利用窃取到的npm token,发布恶意版本,随后产生链式污染。根据公开数据统计,Shai-Hulud 2.0制造了超过800个恶意软件版本。
这轮投毒过后,市场警觉了起来。
几乎所有失陷厂商都在分析报告中宣布,不再使用长期token发布npm包,转而让GitHub做担保申请npm平台一次性token,即OIDC(OpenID Connect),避免被攻击者轻易窃取。
截图:Postman分析报告
或许是OIDC技术起到了一定作用,或许是TeamPCP忙着去做别的事情,亦或其他原因,总之第二轮投毒过后,Shai-Hulud沉寂了一段时间。
在此期间,供应链投毒虽然依旧猛烈,但大规模的链式传播并不多。
3.0:针对OIDC技术的定向绕过
直到2026年4月,沉寂被打破了。TeamPCP在其最新代码仓库的描述中写着:A Mini Shai-Hulud has Appeared。
TeamPCP针对Mini Shai-Hulud做了很多的改良,包括内置硬编码去扫描凭证,使用AES+RSA混合加密回传信息,但更重要的是在投毒过程中,绕过了失陷厂商使用的OIDC技术。
本轮投毒明确的零号感染者有两个:
4月29日,SAP旗下@cap-js失陷,攻击者发布了4个恶意npm包;
5月11日,@TanStack也宣告失守,42个@tanstack/* npm包产生了84个恶意版本。
为了更好理解TeamPCP的绕过手法,先对使用OIDC发布npm包的流程做一个简单科普。
第一,项目发布信息构建。
维护者将代码合并至发布分支,触发GitHub Actions workflow对代码进行打包和安全测试。
第二,申请OIDC身份令牌。
随后,workflow会向GitHub官方申请OIDC ID Token,并将得到的包含数字签名的短期OIDC身份令牌,发送给npm平台。
第三,身份验证与发布授权。
npm会严格核验令牌签名的真实性,同时校验workflow文件、仓库、分支,确认与预设的可信发布者完全一致,才会开放临时发布权限,发布后即失效。
但就是这样一个看起来很安全的检验机制,还是被TeamPCP还是钻了空子。
SAP/@CAP-js失陷的原因是OIDC配置不当,没有严格指定发布分支。
TeamPCP窃取了一个SAP/@CAP-js的开发者账户,向非主要分支上传了恶意workflow,触发后发起OIDC令牌交换请求。
由于没有严格指定发布分支,因此身份验证被npm通过,攻击者拿到了短期有效的npm发布token,向@cap-js/cds-dbs包植入恶意代码。
@TanStack失陷的原因是GitHub Actions workflow缓存被投毒。
TanStack的OIDC配置做了严格发布分支约束,因此使用恶意workflow直接向npm发起身份认证,一定无法通过。然而GitHub Actions workflow为了节省性能消耗,维护了一套公共缓存,所有workflow都会加载。
TeamPCP正是利用这个机制,运行一个低权限的恶意workflow污染公共缓存,等合法workflow加载缓存时恶意代码触发,劫持合法workflow的发布权限完成投毒。
终章:源码开放,去中心化的开始
Mini Shai-Hulud的“高光时刻”是在5月19日。
当日凌晨1:56(UTC)开始,攻击者利用一个npm维护者账户,在22分钟之内发布了323个独立程序包的639个恶意版本,是迄今为止Shai-Hulud系列蠕虫传播最快的一次,其中@antv、echarts-for-react系列包失陷最为严重。
结合攻击手法以及恶意版本携带的载荷特征,有人仍将此次攻击归因于TeamPCP。但在微步情报局看来,这个说法并不一定成立。
因为就在攻陷TanStack之后,TeamPCP做了一个“违背祖宗”的决定:在GitHub上开放源码,甚至把源码拿去与BreachForums合作,组织供应链投毒竞赛。因此仅凭代码特征的归因分析,没办法100%确认就是TeamPCP干的。
对此,TeamPCP没有任何解释。或许如他们在兜售窃取的GitHub数据时说的那样:“看起来我们很快就要退休了。”
但有一点可以肯定,Shai-Hulud源码开放之后,一定会成为一个去中心化的黑产工具。4.0/5.0/6.0等等各种魔改版本,或许很快就会迭代出来。
至于迭代速度和攻击规模,会不会又是一个“银狐病毒”呢?
外传:TeamPCP提出防护建议
Shai-Hulud系列供应链蠕虫主要是针对npm包(也有少部分pypi依赖库),但供应链攻击活动远不止于此。
有趣的是,TeamPCP在2026年5月21日少有的接受了一次外部访谈,重点谈及了如何防范供应链攻击。结合此次访谈实录,微步情报局总结了五点防护建议。
第一,不要自动拉取最新的开源安装包,可以设置最小的时间间隔。这种策略不会完全阻止恶意包,但可以给安全厂商、社区研究人员和包仓库管理员留下发现、下架和发布IOC的时间,避开大量刚发布即投毒的攻击窗口。
第二,依赖和工具链应尽量固定到不可变标识,如hash、commit SHA或image digest。tag和版本号在某些场景下可能被攻击者篡改、重发或劫持,而hash几乎是唯一特征,对不上大概率有问题。
第三,发布凭据和自动化token必须限权。理想情况下,每个token只允许访问特定仓库、特定包、特定环境和特定操作,即使某个Runner、包安装脚本或开发者环境被攻破,攻击者拿到的凭据也难以横移,或者继续污染更多项目。
第四,排查、审计IDE中安装的扩展插件。这是TeamPCP特别提到的,OpenVSX、VSCode、或其他IDE插件能够接触源码、终端、Git 凭据、云 CLI 配置、SSH key、.env 文件和包管理器token,是最佳的攻击入口之一。
就在5月19日,TeamPCP通过投毒VSCode,攻陷了GitHub自身至少3800个代码仓库。
最后,集成外部情报和快速响应能力。无论是威胁情报公司、开源社区还是内部安全团队,越早发现恶意包并发布IOC、影响范围和修复步骤,就越有机会在恶意包广泛传播之前阻断风险。
目前看来,做到这五点建议已经刻不容缓了。
随着Shai-Hulud开源,没人知道Shai-Hulud4.0、5.0、6.0……N.0,都在哪里等着。
附录:IOC和投毒包
以下为Shai-Hulud关联的部分IOC和投毒包,完整内容可联系微步工作人员获取。
IOC
t.m-kosche.com
git-tanstack.com
checkmarx.cx
litellm.cloud
checkmarx.zone
tdtqy-oyaaa-aaaae-af2dq-cai.raw.icp0.io
投毒npm包
Full Package | Namespace | Name | Versions |
|---|---|---|---|
@antv/a8 | @antv | a8 | 0.1.1, 0.2.1 |
@antv/adjust | @antv | adjust | 0.3.5, 0.4.5 |
@antv/algorithm | @antv | algorithm | 0.2.26, 0.3.26 |
@cap-js/db-service<o:page> | @cap-js | db-service | 2.10.1 |
@cap-js/postgres | @cap-js | postgres | 2.2.2 |
@cap-js/sqlite | @cap-js | sqlite | 2.2.2 |
@openclaw-cn/cli | @openclaw-cn | cli | 1.4.1 |
@openclaw-cn/feishu | @openclaw-cn | feishu | 0.2.11 |
@openclaw-cn/libsignal | @openclaw-cn | libsignal | 2.1.1 |
@openclaw-cn/toutiao-ops | @openclaw-cn | toutiao-ops | 1.2.4 |
@opensearch-project/opensearch | @opensearch-project | opensearch | 3.5.3, 3.6.2, 3.7.0, 3.8.0 |
@tanstack/react-router-devtools | @tanstack | react-router-devtools | 1.166.16, 1.166.19 |
@tanstack/react-router-ssr-query | @tanstack | react-router-ssr-query | 1.166.15, 1.166.18 |
@uipath/admin-tool | @uipath | admin-tool | 0.1.1 |
@uipath/agent-sdk | @uipath | agent-sdk | 1.0.2 |
@uipath/agent-tool | @uipath | agent-tool | 1.0.1 |
[培训]《冰与火的战歌:Windows内核攻防实战》!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。