2026年3月31日,著名的云安全平台 StepSecurity 监测到,JavaScript生态中极受欢迎的HTTP客户端库 Axios 遭遇了严重的供应链攻击。这款库的周下载量超过3亿次,影响范围极广。攻击者通过劫持Axios核心维护者 (jasonsaayman) 的 npm 账户,在官方仓库发布了两个被植入恶意代码的版本:axios@1.14.1 和 axios@0.30.4。
令人警惕的是,这两个恶意版本并未直接修改Axios自身的源代码,而是偷偷注入了一个名为 plain-crypto-js@4.2.1 的隐藏依赖项。这个包充当了“木马投递器”的角色,一旦开发者在执行 npm install 时安装了被污染的axios版本,它就会自动触发,悄无声息地释放出针对 Windows、macOS 和 Linux 系统的远程访问木马 (RAT),从而窃取环境凭据并控制受感染的机器。
攻击时间线与战术揭秘
整个攻击过程策划周密,环环相扣:
- 提前潜伏:在发布带毒的axios版本前18个小时,攻击者用一个临时账户 (
nrwise@proton.me) 发布了 plain-crypto-js@4.2.1 这个恶意依赖。其前一个版本 plain-crypto-js@4.2.0 是一个干净的“诱饵包”,仅包含合法 crypto-js 的代码,目的是为该包建立发布历史,规避安全检查。
- 账号劫持与绕过CI/CD:攻击者篡改了受害维护者npm账户的注册邮箱。值得注意的是,合法的axios版本是通过GitHub Actions的OIDC机制自动化发布的,而这两个恶意包是攻击者使用窃取来的长期有效的npm Access Token 人工发布 的,完全绕过了正常的源代码提交流程(没有Commit或Tag)。
- 精准投毒:为了最大化打击面,攻击者在短短39分钟内,连续向Axios的主流1.x分支和老旧的0.x分支发布了投毒更新。
- 迅速止损:两个恶意版本在分别存活了约2小时53分钟和2小时15分钟后,被npm官方紧急撤回,并替换为安全阻断存根。
| 时间线 |
事件详情 |
| 2026-03-30 05:57 |
plain-crypto-js@4.2.0 由 nrwise@proton.me 发布——干净的诱饵包,无恶意钩子。 |
| 2026-03-30 23:59 |
plain-crypto-js@4.2.1 由 nrwise@proton.me 发布——新增恶意载荷,引入 postinstall: "node setup.js" 钩子和混淆的投放器。 |
| 2026-03-31 00:21 |
axios@1.14.1 由被入侵的 jasonsaayman 帐户(邮箱:ifstap@proton.me)发布,将 plain-crypto-js@4.2.1 作为运行时依赖注入,针对1.x用户。 |
| 2026-03-31 01:00 |
axios@0.30.4 由同一被入侵帐户发布,向0.x分支注入相同恶意依赖。 |
| 2026-03-31 ~03:15 |
npm取消发布 axios@1.14.1 和 axios@0.30.4。latest 标签恢复至 axios@1.14.0。 |
| 2026-03-31 03:25 |
npm对 plain-crypto-js 发起安全保留。 |
| 2026-03-31 04:26 |
npm官方账户 (npm@npmjs.com) 发布安全持有者存根 plain-crypto-js@0.0.1-security.0 正式替换恶意包。 |
恶意机制如何运作?
当开发者安装受污染的 axios@1.14.1 或 0.30.4 时,npm会连带安装其隐藏的恶意依赖 plain-crypto-js。攻击随即通过以下步骤展开:
1. 利用生命周期钩子
恶意依赖的 package.json 中配置了 "postinstall": "node setup.js" 钩子。这导致npm在解析完依赖树后,立即执行恶意脚本,甚至在 npm install 命令完全结束前,就开始连接C2(命令与控制)服务器。
2. 免杀与深度混淆
setup.js 脚本采用了两层定制化的加密混淆机制(如异或配合Base64),用于隐藏敏感的C2域名 (http://sfrclak.com:8000/) 和执行命令,从而成功避开了常规的静态代码安全扫描。
3. 跨平台木马释放
脚本会识别宿主机操作系统,并释放针对性的RAT载荷:
- macOS平台:在后台执行AppleScript,拉取专版木马,将其隐藏伪装在系统级缓存目录 (
/Library/Caches/com.apple.act.mond)。
- Windows平台:将PowerShell副本伪装成Windows Terminal进程 (
%PROGRAMDATA%\wt.exe),然后通过无窗口的VBScript下载 ps1 载荷并在内存中执行。
- Linux平台:使用系统curl拉取恶意Python脚本 (
/tmp/ld.py) 并使用 nohup 放入后台执行。
4. 反取证清理
当一阶段载荷发射完毕并建立C2连接后,setup.js 脚本会进行“自杀式”清理——删除自身文件,并将包含恶意钩子的 package.json 替换为一个提前准备好的干净版本。这意味着,事后审计时在 node_modules 目录下检查,只会看到一个看似无害的模块,大大增加了排查难度。
IOC(入侵指标)
- 恶意包SHA1:
axios@1.14.1: 2553649f232204966871cea80a5d0d6adc700ca
axios@0.30.4: d6f3f62fd3b9f5432f5782b62d8cfd5247d5ee71
plain-crypto-js@4.2.1: 07d889e2dadce6f3910dcbc253317d28ca61c766
- C2信息:
- 域名: sfrclak[.]com
- IP: 142[.]11[.]206[.]73
- URL:
http[:]//sfrclak[.]com[:]8000/6202033
- 恶意文件路径:
- macOS:
/Library/Caches/com.apple.act.mond
- Windows (持久化):
%PROGRAMDATA%\wt.exe
- Linux:
/tmp/ld.py
- 安全版本:
axios@1.14.0 (安全) SHA1: 7c29f4cf2ea91ef05018d5aa5399bf23ed3120eb
排查与紧急补救指南
如果你或你的团队在2026年3月31日凌晨的窗口期内执行过构建或安装,相关系统应直接视为 “已被深度妥协” 。
📌 如何判断是否受影响?
-
检查项目中是否安装了恶意axios版本:
# 方法一:通过npm list检查
npm list axios 2>/dev/null | grep -E "1\.14\.1|0\.30\.4"
# 方法二:检查package-lock.json
grep -A1 '"axios"' package-lock.json | grep -E "1\.14\.1|0\.30\.4"
-
检查是否存在恶意依赖目录:
plain-crypto-js 目录的存在本身就是证据。即使其下的 package.json 看起来是干净的(已被替换),该目录的存在也足以证明恶意投放器已执行。
ls node_modules/plain-crypto-js 2>/dev/null && echo "POTENTIALLY AFFECTED"
-
检查系统是否存在后门文件:
# macOS
ls -la /Library/Caches/com.apple.act.mond 2>/dev/null && echo "COMPROMISED"
# Linux
ls -la /tmp/ld.py 2>/dev/null && echo "COMPROMISED"
# Windows (在cmd.exe中执行)
dir "%PROGRAMDATA%\wt.exe" 2>nul && echo COMPROMISED
-
审查CI/CD流水线日志:查找任何拉取了 axios@1.14.1 或 axios@0.30.4 的 npm install 记录。任何执行了安装的流水线都应视为已遭入侵。
🛠️ 补救措施
-
强制降级并锁定版本:立即回滚至安全版本,并利用包管理器的覆盖功能强制锁定。
npm install axios@1.14.0
在 package.json 中添加覆盖配置:
{
"dependencies": {
"axios": "1.14.0"
},
"overrides": {
"axios": "1.14.0"
},
"resolutions": {
"axios": "1.14.0"
}
}
-
清理恶意依赖:
rm -rf node_modules/plain-crypto-js
npm install --ignore-scripts
-
彻底重构环境:一旦检测到木马踪迹,最安全的做法是将受影响的开发环境、测试环境或服务器推翻重构,而非尝试清理。
-
全面轮换凭证(最关键!):此次木马会窃取环境变量。必须立即轮换/重置当时机器上存储的所有高权限密钥,包括云服务密钥、SSH私钥、CI/CD流水线机密以及任何 .env 文件中的敏感信息。
-
强化防御最佳实践:
- 在CI/CD中运行安装命令时,强制使用
npm ci --ignore-scripts 以防止任意脚本执行。
- 配置严格的网络防火墙出站策略(Egress Control)。
-
网络层阻断:作为临时预防措施,可以在防火墙或hosts文件中阻断C2通信。
# Linux防火墙规则示例
iptables -A OUTPUT -d 142.11.206.73 -j DROP
# 通过hosts文件屏蔽 (macOS/Linux)
echo "0.0.0.0 sfrclak.com" >> /etc/hosts
此类针对 Node.js 生态核心库的供应链攻击 再次敲响了警钟。开发者需要时刻保持对依赖安全的警惕,建立自动化的漏洞扫描和依赖审计流程。保持关注 云栈社区 的技术安全板块,可以获取更多前沿的安全资讯和防御实践。
参考链接:https://www.stepsecurity.io/blog/axios-compromised-on-npm-malicious-versions-drop-remote-access-trojan
|