Miasma Worm:大多数受感染 GitHub 仓库仍在线

目录

Miasma 蠕虫 将一个 4.3 MB 的凭证窃取程序植入公共 GitHub 仓库八天后——以及该蠕虫锁定的维护者夺回账户三天后——大多数受感染仓库仍在加载有效载荷。SafeDep 于 6 月 5 日发布了受害者名单并于 6 月 11 日运行了新一轮 GitHub 代码搜索。在这两个时间点之间,横跨 56 个账户的 123 个仓库仍在 665 个分支上运行活动状态的 dropper。任何克隆这些仓库并在 VS Code、Cursor、Claude Code 或 Gemini 中打开它的人,都会在无需进一步交互的情况下运行凭证收集器。

几乎所有被清理的仓库背后都有安全团队支持。微软的 Azure/durabletaskAzure-Samples/llm-fine-tuning 是干净的。icflorescu 的全部五个仓库、所有 jagreehal 以及 jahirfiquitiva/Frames 也都是干净的。继续传播的是那些没有安全组织监控其仓库的个人开发者、学生和小型团队。尼日利亚银行的企业网站、去中心化金融交易所的交易协议、大学课程的学生作业,以及数十个个人项目,此刻仍在提供恶意软件。

我们的测量方法

检测方法是 icflorescu 在蠕虫攻击后 发布的:不要信任提交作者,应在每个分支上检查有效载荷文件。dropper 位于 .github/setup.js,单行约 4.3 MB。没有合法的仓库会携带这个文件。

扫描过程从不检出工作树,也从不执行任何代码。只需进行一次无 blob 的 --no-checkout 克隆加上每个分支的对象存在性测试就足够了。

bash
# Defensive scan. Nothing is checked out, nothing runs. git clone --no-checkout --filter=blob:none https://github.com/<owner>/<repo>.git probe cd probe git fetch origin '+refs/heads/*:refs/remotes/origin/*' for b in $(git for-each-ref --format='%(refname:short)' refs/remotes/origin | sed 's#origin/##'); do git cat-file -e "origin/$b:.github/setup.js" 2>/dev/null && echo "INFECTED: $b" done

两份数据集驱动了本次运行。第一份是 SafeDep 于 6 月 5 日发布的 123 个仓库列表,这些仓库在披露时已携带 node .github/setup.js 钩子。第二份是 6 月 11 日对相同调用字符串进行的新一轮 GitHub 代码搜索,发现了 58 个候选仓库。其中 41 个不在原始发布列表上。随后对每个结果在所有分支上进行 git 扫描,以确认有效载荷存在并记录每个被污染的提交位于哪个分支。

这两个数字都存在低估。GitHub 代码搜索仅索引默认分支,并跳过大于约 384 KB 的文件,因此 4.3 MB 的 setup.js 本身从未被索引。小型启动器配置是这一切可被搜索的唯一原因,而蠕虫隐藏在侧分支上的习惯使得大多数有效载荷完全超出代码搜索范围。

发布列表中 70% 的仓库仍被感染

6 月 5 日发布的 123 个仓库,截至 6 月 11 日的状态分布如下。

结果(6 月 11 日)仓库数占比
仍被感染,有效载荷活动8670%
已清理,仓库仍在线2117%
已禁用、删除或设为私有1613%

在公开名单公布这些仓库六天后——在此活动因击中 73 个微软仓库 而登上国际新闻之后——七成的仓库仍在提供活动有效载荷。21 个完成清理的几乎都是有安全团队支持的名字:Azure/durabletaskAzure-Samples/llm-fine-tuningicflorescujagreehal 以及 jahirfiquitiva 仓库。16 个消失的仓库是被 GitHub 或其所有者下线的。其他一切均未受影响。

仍在提供有效载荷的是谁

截至 6 月 11 日经确认仍被感染的完整仓库列表,以及每个仓库的中毒分支数量和有效载荷大小:

miasma-still-infected-repos.csv

仓库所有者中毒分支数有效载荷字节数
1Abner97/InvitationsApiAbner9734634669
2Abner97/tournaments-appAbner9724634669
3Agentic-Insights/dreamgenAgentic-Insights104646419
4Agentic-Insights/foundryAgentic-Insights24646419
5Agreon/budgieAgreon124634464
6Agreon/stycoAgreon64634464
7aiyeola/nextjs-blogaiyeola24477023
8aiyeola/scrapeaiyeola24477023
9A-Mitch/learningRoRA-Mitch24471909
10A-Mitch/spotify-codes-simulationA-Mitch24471909
11anasdevv/customer-portalanasdevv24361318
12anasdevv/hotel-management-backendanasdevv64448127
13anasdevv/my-calendaranasdevv24361318
14anasdevv/reservation-systemanasdevv34361318
15angular-indonesia/angular-indonesia.github.ioangular-indonesia24634519
16angular-indonesia/starter-angular-loopback-bulmaangular-indonesia114634519
17baltruschat/jira-bug-trackerbaltruschat44634733
18beatrizamante/facial-recognition-apibeatrizamante24635011
19beatrizamante/interactive-fiction-reviewerbeatrizamante44635011
20beatrizamante/utfpr_classlogbeatrizamante84635011
21beatrizamante/utfpr_classlog_frontendbeatrizamante84635011
22beatrizamante/watchme_frontendbeatrizamante44635011
23bhagyamudgal/cuju-webbhagyamudgal24377645
24bhagyamudgal/notisolbhagyamudgal24377645
25bhagyamudgal/worktree-clibhagyamudgal34377645
26bitzquad/bitzquad.combitzquad1
27bitzquad/bitzquad.com-2.0bitzquad1
28bitzquad/nebula-docsbitzquad1
29braune-digital/bd-php-to-ts-converter-bundlebraune-digital24634733
30braune-digital/BrauneDigitalImagineBundlebraune-digital44634733
31Code-Web-Basic/CompilerGoCode-Web-Basic54634925
32CurryMessi/tiktok-videoCurryMessi24635243
33czech-sfl/konferenceczech-sfl24634914
34dandycheung/Framesdandycheung14559058
35dcc-cc3002/citric-liquid-Benjjvvdcc-cc300284619268
36dcc-cc3002/citric-liquid-cpereiramdcc-cc300294619268
37dcc-cc3002/citric-liquid-ihumiredcc-cc300294619268
38dcc-cc3002/citric-liquid-Jarinxdcc-cc300294619268
39dean-s list/business-visa-serverdean-s-list24377645
40dean-s list/deanslist-platformdean-s-list24647225
41dean-s list/deanslist-servicesdean-s-list24377645
42dsrikant/smarcartdsrikant44620322
43dzhu8/dzhu.github.iodzhu824634066
44EdsonVillarroel/e-commerceEdsonVillarroel64635467
45EdsonVillarroel/portfolioEdsonVillarroel114635467
46EdsonVillarroel/vision-kitEdsonVillarroel24635467
47erbieio/erbieerbieio154390381
48Factlink/js-libraryFactlink34548618
49Factlink/url_normalizerFactlink24548618
50GNF-Labs/millenium-lms-web-appGNF-Labs44463853
51jchable/gpx-utility-analyzerjchable24634567
52jedsada-gh/ApiMovie-UPjedsada-gh34645945
53jedsada-gh/blockchain-playgroundjedsada-gh24634301
54jedsada-gh/co-work-adminjedsada-gh44634301
55jedsada-gh/co-work-androidjedsada-gh34634301
56jedsada-gh/co-work-apijedsada-gh34634301
57jedsada-gh/co-work-katalonjedsada-gh24634301
58jedsada-gh/co-work-providerjedsada-gh34634301
59jedsada-gh/node-js-netpiejedsada-gh94634301
60jgutierrezdtt/skills-hello-github-actionsjgutierrezdtt24643795
61jgutierrezdtt/Sports-Centerjgutierrezdtt104643795
62jgutierrezdtt/Vulndemojgutierrezdtt34643795
63killerapp/mermaid-renderkillerapp44646419
64KSU-Quantum-Capstone/CS4850-DL1KSU-Quantum-Capstone44630939
65kylezap/ctrl-alt-winkylezap214645618
66kylezap/kylezapcicdotcomkylezap24377461
67kylezap/rightsize-mealskylezap214645618
68kylezap/tree-viewkylezap24377461
69leanderloew/explainability-simulationleanderloew24633915
70lucasconnellm/openclaw-fluxerlucasconnellm44633825
71messismore/Digitale-Ausstellungmessismore44634208
72messismore/Studio-Grottomessismore44634208
73metersphere/helm-chartmetersphere34646584
74mhar-andal/MyBlokmhar-andal64508470
75mhar-andal/stock-forum-ethereummhar-andal24508470
76mmlngl/contacttracing.app-graphql-apimmlngl34647729
77mmlngl/flua-launchmmlngl34647729
78nasher721/3dgeneratornasher72124634138
79nasher721/AnkiFellowCollabnasher72184634138
80nasher721/Extract721nasher72134646453
81nasher721/Medical-OCRnasher721134646453
82nasher721/note-claritynasher72144634138
83nasher721/remix-of-remix-of-round-robin-notesnasher721204646453
84nasher721/remix-of-round-robin-notesnasher72164634138
85nasher721/schedulernasher721214646453
86nasher721/textcleanernasher72134634138
87neilfarmer/k8s-healthneilfarmer94634793
88neilfarmer/platform-specneilfarmer84634793
89Netpoc/companyNetpoc24646713
90nodejs-indonesia/blogsnodejs-indonesia24634519
91nodejs-indonesia/starter-loopback-fireloopnodejs-indonesia144645302
92otaviosoaresp/what-the-forkotaviosoaresp24622883
93paulmojicatech/angular-dc-meetup-may-24-2022paulmojicatech44634921
94paulmojicatech/pmtpaulmojicatech64634921
95paulmojicatech/wonder-wormpaulmojicatech24634921
96PositionExchange/decentralized-perpetual-trading-protocol-cross-chainPositionExchange274645446
97PositionExchange/dptp-client-sdkPositionExchange34648910
98PositionExchange/evm-matching-enginePositionExchange44648910
99PositionExchange/position-protocolPositionExchange275351744
100Pouleyy/nodeAirBnBPouleyy24635440
101rhemlock7/ecommerce-back-endrhemlock744646471
102rhemlock7/express-note-takerrhemlock774646471
103rhemlock7/minimalist-portfolio-mkiirhemlock794646471
104rhemlock7/NoSQL-Social-Networkrhemlock754646471
105rhemlock7/SQL-Employee-Trackerrhemlock764646471
106rhemlock7/svg-logo-makerrhemlock764646471
107rhemlock7/TeamSync-Clientrhemlock734646471
108rhemlock7/TeamSync-KanBanrhemlock784646471
109rhemlock7/weather-app-apirhemlock794646471
110rudy-marquez/WebGoatNetrudy-marquez34634940
111Saul9201/daily-trendsSaul920124645778
112Saul9201/hello-circleciSaul920124376490
113Skipperlla/rn-swiper-listSkipperlla84611776
114Slickteam/hubspot-javaSlickteam44549341
115snoopyrain/rails102snoopyrain94635175
116Summit-Bank-Limited/corporate-websiteSummit-Bank-Limited124646713
117tumolaha/lerning-setuptumolaha24646776
118Weasledorf-Inc/taskmasterWeasledorf-Inc74634793
119WilChrist/SecurityAuditAppWilChrist24549461
120WilChrist/WilCovEstWilChrist24549461
121wormholes-org/wormholes-clientwormholes-org54650163
122Zaynex/13f-visZaynex94549400
123Zaynex/x-atmZaynex34549400

123 行

| 4 列 |

受害者按账户聚集,因为蠕虫会遍历被盗令牌可访问的每个仓库。rhemlock7 有 9 个仓库仍被感染,nasher721 有 9 个,jedsada-gh 有 8 个,beatrizamante 有 5 个。一组被盗凭证会污染整个个人账户。

受影响者的分类样本(非按 GitHub stars 分类):

  • 一家银行。Summit-Bank-Limited/corporate-website 在 12 个分支上携带有效载荷,提交以地址 [email protected] 伪造。
  • 一个去中心化金融交易所。PositionExchange/position-protocol 和三个同级仓库处于活动状态,协议仓库在 27 个分支上被污染,提交伪造为 [email protected]
  • 一门大学课程。四个 dcc-cc3002/citric-liquid-* 仓库是智利大学软件设计课程的学生作业,每个在 8 到 9 个分支上被污染,提交以学生的 @ug.uchile.cl 地址伪造。
  • 一个毕业项目团队。KSU-Quantum-Capstone/CS4850-DL1,位于肯尼索州立大学。
  • 一个基础设施项目。metersphere/helm-chart,MeterSphere 测试平台的 Helm chart,提交伪造为其真正的 @fit2cloud.com 维护者。

有效载荷大小从 4.36 MB 到 5.35 MB 不等,约有 38 种不同大小。dropper 针对每个受害者重新编译,包含轮换的 AES 密钥和凯撒移位,因此文件哈希会变化但架构保持不变。只有小型启动器配置保持不变,扫描正是匹配这些。

提交是以维护者自己的名义伪造的

这些感染在侧分支上存活的原因是它们被设计成不被注意。SafeDep 最初的分析描述了 icflorescu 的 main 分支上的 github-actions <[email protected]> 作者。那是响亮的一半。在本次扫描记录的 808 个引入有效载荷的提交中,除三个外所有提交都是用真实维护者的姓名和邮箱伪造的,而非机器人的。每个提交都带有 [skip ci] 以抑制通知,提交日期被回溯到 2013 年到 2026 年之间的时间跨度,使每个被污染的提交融入该分支自身的历史。

bash
# PositionExchange/position-protocol, develop branch # https://github.com/PositionExchange/position-protocol/commit/ce456191d71c3399c114b3d539666477df1322bc author: Justin <[email protected]> date: 2022-11-14T15:51:31Z # backdated ~3.5 years verified: false # unsigned message: Update README.md [skip ci] [skip ci] [skip ci] [skip ci] skip-checks:true

angular-indonesia/starter-angular-loopback-bulma 在提交 57ae9502 中携带其有效载荷,伪造为 Julian GM Alimin <[email protected]> 并回溯到 2017 年。该组织的 GitHub Pages 站点 angular-indonesia.github.io 以同样的方式被污染,伪造为维护者 Irfan Maulana <[email protected]>。MeterSphere 提交保留了他们冒充的工程师原始的中文提交信息。伪造针对每个仓库和每个分支进行了调整。

如果您审计自己的仓库,不要通过提交作者来检测。这通过了所有"这是机器人吗?"检查。通过有效载荷文件来检测。

仅清理 main 分支是不够的

最清晰的说明是 metersphere/helm-chart。其默认分支 v3.x 于 6 月 8 日被标题为 Remove Miasma config injection indicators 的提交清理。维护者知情并已修复。然而在 6 月 11 日,4.6 MB 的有效载荷仍在其他三个分支 fix/pvcpr@main@build_redisrefactor/kafka 上活动。

这就是大多数仓库保持感染的方式。维护者在 main 上看到提交,回退或重置它,并认为工作完成了。蠕虫已在每个可访问的分支上植入了相同的有效载荷,每个都在看似合理的回溯提交下,而那些分支从未被扫描。在发布列表中 86 个仍被感染的仓库中,许多有一个看起来已清理的默认分支,而在相邻分支上有一个活动有效载荷。

根本原因:一个超越一切的凭证

入口向量现已从 GitHub 自己的日志中确认,来源是 icflorescu 的后续。提交是通过他的 GitHub CLI OAuth 令牌进行的,该令牌创建于 1 月 17 日,五个月后从微软 Azure IP 范围内通过 GitHub API 使用。该凭证是一个令牌,而非他的密码或双因素认证,这就是为什么两者都无法阻止它。

一个结构性细节解释了一个盗窃为何能遍历如此多的账户。GitHub 在一个 OAuth 应用授权下堆叠了许多访问令牌,每台机器和每次重新登录各一个。撤销单个令牌、重新认证,甚至 GitHub 自己自动驱逐旧令牌,都不会撤销授权。只有撤销整个授权才能杀死其下的所有令牌。icflorescu 在 5 月轮换了令牌并重建了两台笔记本电脑,但 1 月的令牌在 6 月仍然有效,因为底层的授权从未被撤销。该令牌最可能是通过 TanStack 供应链攻击更早被收割的,在某些常规的 npm install 期间拉取了被感染的依赖项,并在数周后重复使用。

这就是 Shai-Hulud 循环。一个被污染的依赖项收割了一个写作用域凭证,蠕虫用它将有效载荷推送到凭证可访问的每个仓库,而有效载荷在开发者于 AI 编辑器中打开任何这些仓库时收割更多凭证。

该技术改进了较旧的方法。2025 年 8 月对 Nx 构建系统的 s1ngularity 攻击 compromising 2,180 个 GitHub 账户并暴露了 7,200 个仓库,将被盗数据泄露到名为 s1ngularity-repository 的公共仓库。那款恶意软件使用开发者自己安装的 Claude、Q 和 Gemini CLI 来枚举和收割密钥。在 s1ngularity 使用 AI 代理收割凭证的地方,Miasma 植入了使这些相同代理首先运行窃取程序的配置文件。

如何检查您自己的仓库

这些项目的已发布 npm 包是干净的。在此次攻击中,mantine-datatable、AntV 包或其他任何包都没有向注册表发布过恶意版本。危险完全是本地的,且在 npm uninstall 后仍然存在。如果您克隆了在 Shai-Hulud 或 Miasma 活动期间活跃的任何仓库:

  • 不要在 VS Code、Cursor、Claude Code 或 Gemini 中打开工作副本,不要运行 npm test。无检出的克隆可将有效载荷保留在磁盘之外。
  • 使用本文顶部的命令扫描每个分支以查找 .github/setup.js。通过有效载荷文件检测,而非通过提交作者。
  • 如果找到它,将受影响的分支重置到被污染提交的前一个提交,而非 git revert,后者会在旧 SHA 处留下可检索的 dropper。然后请求 GitHub 垃圾回收孤立的提交。
  • 撤销您怀疑的任何 CLI 的 OAuth 应用授权,而不仅仅是其令牌。撤销令牌会使授权保持活动状态。
  • 在每次差异和您克隆的每个仓库中,将 .claude/.gemini/.cursor/.vscode/ 文件视为可执行代码。它们在文件夹打开和会话开始时自动运行命令,大多数审查工作流都会忽略它们。

蠕虫赌的是克隆源代码感觉是安全的。AI 编码代理和 IDE 自动运行功能改变了这一点,而从 123 个仓库八天后仍活动这一证据来看,大多数生态系统尚未跟上。

相关阅读:Miasma 蠕虫通过 GitHub 仓库针对 AI 编码代理(原始 source-repo 分析),迷你 Shai-Hulud"Miasma"袭击 @redhat-cloud-services(分阶段的 Bun 加载器,已逆向),以及 nx 构建系统妥协(s1ngularity 先例)。

  • github
  • malware
  • supply-chain
  • shai-hulud
  • ai-coding-agents

SafeDep 博客的最新内容

关注以获取开源安全与工程的最新更新和见解