Red Hat npm 包被植入凭证窃取蠕虫:Miasma 供应链攻击的完整技术复盘
前言2026年6月1日Socket 安全团队披露了一起代号为Miasma的供应链攻击事件攻击者向 Red Hat 的redhat-cloud-services命名空间下至少 4 个 npm 包注入了恶意代码。任何开发者执行npm install时恶意代码即触发——窃取本机凭证和密钥并投放自传播蠕虫。这不是孤立事件。同一天Aikido Security 披露了 npm 包codexui-android周下载量超过 29,000 次在过去一个月内持续静默窃取 OpenAI Codex 认证令牌。两起事件叠加释放了一个明确信号开发者本机的凭证和密钥已经成为供应链攻击者的首要目标——攻击者不需要攻陷服务器一条npm install命令就足够了。一、Miasma 攻击的技术拆解1.1 受影响范围字段内容攻击代号Miasma攻击分类Mini Shai-Hulud 系列供应链凭证窃取蠕虫受影响包redhat-cloud-services/vulnerabilities-client、redhat-cloud-services/tsc-transform-imports、redhat-cloud-services/topological-inventory-client、redhat-cloud-services/sources-client等恶意行为安装时执行 → 凭证收集 → CI/CD 攻击 → 加密外传 → 自传播归因无法确定TeamPCP 已开源 Shai-Hulud 工具模仿者众多1.2 攻击链npm install 为什么会泄露你的凭证Miasma 系列攻击的核心战术是install-time execution安装时执行。对于 npm 包而言postinstall脚本在npm install完成后自动以当前用户权限运行——这意味着它能接触到开发机上的所有用户态文件1. 开发者执行 npm install redhat-cloud-services/vulnerabilities-client 2. postinstall 恶意脚本自动触发 3. 扫描目标目录 ~/.npmrc npm 注册表认证令牌 ~/.git-credentials Git 凭据 ~/.aws/credentials AWS IAM 密钥 .env / .env.local / .env.production ~/.ssh/id_rsa SSH 私钥 ~/.config/ 各工具配置文件 4. 收集的凭据打包加密 → 上传至攻击者 C2 5. 投放蠕虫组件扫描本地 Git 仓库 → 修改 package.json → 等待下次 publish1.3 为什么这比传统攻击更危险传统 npm 供应链攻击通常是一次性的攻击者发布恶意包 → 少数开发者上当 → 包被下架 → 攻击结束。但 Miasma 的不同在于蠕虫自传播攻击者不需要持续运营恶意包被感染的开发者如果发布了受到蠕虫修改的包下游使用者 npm install 后同样被感染这种传播方式让攻击呈指数扩散——最初只需要感染一个活跃维护者最终可以污染整个依赖树1.4 与 Shai-Hulud 的关系Miasma 被归类为 Mini Shai-Hulud。Shai-Hulud 是 2025 年下半年爆发的供应链蠕虫家族核心战术为安装时执行 → 凭证收集 → CI/CD 攻击 → 加密外传 → 下游传播。TeamPCP 组织已将 Shai-Hulud 的完整工具链开源这使得模仿攻击的门槛被拉到了极低水平——任何有基础 npm 操作经验的攻击者都可以复现这一攻击模式。二、codexui-android合法包的缓慢投毒Aikido Security 研究员 Charlie Eriksen 在同一天披露了codexui-android包的令牌窃取行为。这个案例比 Miasma 更值得警惕因为它走的不是发布一个恶意包等受害者安装的粗暴模式而是渗透合法包、缓慢投毒。2.1 攻击特征npm 包周下载量超过 29,000 次关联的 GitHub 仓库保持干净无恶意代码痕迹恶意代码在包发布约一个月后被注入——攻击者拥有包的发布权限每次调用都会静默将 Codex 认证令牌外传到攻击者控制的服务器攻击持续了至少一个月才被发现2.2 合法包投毒 vs 冒牌包┌────────────────────────────────────────────────────┐ │ 两种 npm 供应链攻击模式对比 │ ├──────────────┬─────────────────┬───────────────────┤ │ 战术模式 │ typosquat │ 合法包渗透 │ │ 典型行为 │ 注册名称相似的包 │ 获取合法包发布权限│ │ 发现难度 │ 中包名可疑 │ 高仓库干净 │ │ 影响面 │ 低少数人拼错名│ 高已有用户量 │ │ 案例 │ 常规投毒攻击 │ codexui-android │ └──────────────┴─────────────────┴───────────────────┘codexui-android 的教训是npm 安全审计不能只看包的初始版本是否干净——持续监控包的行为变化是基础要求。如果团队在 CI/CD 中只做了npm audit而没有运行时行为检测完全无法发现这类缓慢投毒。三、开发者机器的凭据面比你想的更大Miasma 和 codexui-android 的目标不是服务器而是开发者的本地机器。为什么因为开发机上往往存储着整个组织最有价值的凭据集合npm 令牌有 write 权限的令牌可以发布新版本或被蠕虫用于传播Git 凭据能访问私有仓库等于拿到源代码云厂商密钥AWS AK/SK、阿里云 AccessKey直接控制云基础设施.env文件数据库密码、API Key、加密盐值SSH 私钥直连生产服务器的跳板一个npm install命令就把所有这些暴露给了攻击者。这不是理论风险——Red Hat 的 npm 命名空间被攻陷这个事实本身就说明即使是最受信赖的包来源也不是绝对安全的。四、工程防护从相信 npm install到凭据零落地4.1 原则一开发机上不应该存在持久化凭据对抗 Miasma 这类攻击的关键不是检测恶意包这个永远落后一步而是让开发机上根本没有值得窃取的凭据# 旧做法开发者在本地 .env 里直接写生产凭据# DATABASE_PASSWORDprodpass123 ← 被 postinstall 脚本一锅端# 新做法动态凭据注入# 应用启动时从凭据管理平台拉取临时凭据变量仅在内存中存在importos,subprocess,jsondefget_db_credential():从凭据管理系统获取临时数据库凭据TTL1小时resultsubprocess.run([credential-cli,get,--path,prod/postgres/write],capture_outputTrue,textTrue)credjson.loads(result.stdout)# 凭据仅在内存中写入环境变量但从不落盘os.environ[DB_USER]cred[username]os.environ[DB_PASS]cred[password]returncred4.2 原则二CI/CD 凭据走注入不走代码仓库GitHub Actions / GitLab CI 的 Secrets 机制本身是安全的但很多团队为了方便把密钥直接编码在.github/workflows/*.yml或.gitlab-ci.yml中。Miasma 蠕虫恰恰会扫描这些文件# ❌ 错误做法密钥硬编码在 CI 配置中env:AWS_ACCESS_KEY_ID:AKIAIOSFODNN7EXAMPLE# ← 被蠕虫一锅端AWS_SECRET_ACCESS_KEY:wJalrXUtnFEMI/K7MDENG# ← 同上# ✅ 正确做法从凭据管理系统动态获取env:# 不写具体值运行时由 SDK 从 KSP 拉取AWS_ACCESS_KEY_ID:AWS_SECRET_ACCESS_KEY:更好的做法是CI/CD pipeline 启动时通过 SDK 从密钥管理系统获取临时凭据pipeline 结束后凭据自动失效。这样即使蠕虫窃取了 CI/CD 的运行时环境变量拿到的也是几小时后自动过期的临时凭据。4.3 原则三npm 依赖的行为基线监控对抗 codexui-android 式缓慢投毒需要从单次安全审计切换到持续行为监控// npm 依赖行为基线检测的伪代码逻辑constBASELINE{// 基线定义合法包不应该有的行为filesystemAccess:[~/.ssh,~/.aws,~/.git-credentials,.env*],networkRequests:[npm install阶段不允许外连],childProcess:[不允许在 postinstall 中执行 curl/wget/nc]};functionauditPostinstallScripts(packageName){constmanifestreadPackageManifest(packageName);constscriptsmanifest.scripts||{};for(const[hook,command]ofObject.entries(scripts)){if(hookpostinstall||hookpreinstall){// 检查命令是否存在可疑关键词for(constsuspiciousof[curl,wget,nc,/dev/tcp,eval]){if(command.includes(suspicious)){thrownewError(高危:${packageName}的${hook}脚本包含 {suspicious}已阻止安装);}}}}}4.4 原则四开发环境隔离如果开发项目依赖第三方包将项目开发环境与日常使用的机器环境隔离是一条低成本但高效的措施使用 Dev Container 或虚拟机作为开发环境仅挂载必要的项目目录宿主机的~/.ssh、~/.aws等敏感目录不挂载到开发容器中即使 npm 包在容器内执行恶意代码也无法接触到宿主机的凭据五、npm 生态的结构性弱点Miasma 和 codexui-android 不只是两个安全事件它们暴露了 npm 生态的三个结构性弱点1. postinstall 执行权限过大。npm 的postinstallhook 在设计上拥有当前用户的所有权限——它不是一个沙箱环境。这意味任何npm install都是对执行用户的完全信任授权。2. 包发布者身份验证薄弱。codexui-android 案例表明获得一个合法包的发布权限通过社工、令牌泄露或账号劫持的攻击者可以在 GitHub 仓库完全干净的情况下注入恶意代码。3. 信任知名来源策略失效。Red Hat 是全世界最受信任的开源组织之一但它的 npm 命名空间仍然被攻陷。这推翻了一个长期假设来自知名组织/知名维护者的包是安全的一一从现在开始这个假设不再成立。六、总结Miasma 和 codexui-android 给开发者社区上了三堂课npm install 是一个信任动作而不只是装个依赖。它赋予了包以你当前用户的全部权限去执行任意代码。你需要像审查生产环境 SSH 权限一样审查安装行为。凭据不应该存在于开发机上。动态凭据注入、临时凭据、开发环境隔离——这些措施的目标不是让 npm 更安全而是让攻击者在开发机上找不到有价值的东西可偷。安全审计必须从一次性的变成持续的。codexui-android 在投毒后才被发现而且持续了整整一个月——这一个月里29,000 次/周的下载量意味着数万开发者的 Codex 令牌被窃取。持续的行为基线监控是唯一的防守方式。 话题讨论你们团队的安全策略里开发环境的凭据是怎么管理的有没有遇到过 npm 包的审计问题欢迎评论区聊聊。