[紧急预警] axios 被投毒!快查你的 package.json
事件性质: npm 供应链投毒攻击 受影响版本: [email protected], [email protected] 攻击时间: 2026年3月31日 威胁等级: 🔴 严重 阅读时间: 约 10 分钟 | 字数: ~4500 字

01. 紧急自查与修复(必读)
受影响版本
| 分支 | 恶意版本 | 安全版本 |
|---|---|---|
| 1.x | 1.14.1 | 1.14.0 |
| 0.x | 0.30.4 | 0.30.3 |
一键自查命令
🔍 单项目检查(在项目根目录执行)
检查依赖版本:
# 检查当前项目安装的 axios 版本npm list axios 2>/dev/null | grep -E "1\.14\.1|0\.30\.4"
# 检查 package-lock.jsongrep -A1 '"axios"' package-lock.json | grep -E "1\.14\.1|0\.30\.4"
# 检查恶意依赖目录是否存在ls node_modules/plain-crypto-js 2>/dev/null && echo "⚠️ 检测到 plain-crypto-js,系统可能已感染"🌐 全局批量检查(扫描电脑中所有项目)
在你的代码根目录(如 ~/Projects 或 ~/Documents)执行:
macOS / Linux:
# 1. 批量查找所有 node_modules 中的恶意包find . -name "plain-crypto-js" -type d 2>/dev/null | grep "node_modules" && echo "⚠️ 检测到恶意依赖"
# 2. 批量查找 package-lock.json 中的恶意版本grep -rE '"axios":.*(1\.14\.1|0\.30\.4)"' . --include="package-lock.json"Windows (PowerShell):
# 1. 批量查找恶意依赖目录Get-ChildItem -Path . -Directory -Recurse -Filter "plain-crypto-js" -ErrorAction SilentlyContinue | Where-Object { $_.FullName -match "node_modules" }
# 2. 批量查找恶意版本Get-ChildItem -Path . -File -Recurse -Filter "package-lock.json" | Select-String -Pattern 'axios.*1\.14\.1|axios.*0\.30\.4'🖥️ 系统级 RAT 检查(最关键)
| platform | 检查命令 | 结果解读 |
|---|---|---|
| macOS | `[ -e “/Library/Caches/com.apple.act.mond” ] && echo ”🚨 已感染” | |
| Linux | `[ -e “/tmp/ld.py” ] && echo ”🚨 已感染” | |
| Windows | Test-Path "$env:PROGRAMDATA\wt.exe" | 检查 %PROGRAMDATA%\wt.exe |
一键检测脚本:
# macOS / Linux 通用版check_rat() { if [ "$(uname)" = "Darwin" ]; then [ -e "/Library/Caches/com.apple.act.mond" ] && echo "🚨 macOS RAT 文件存在,系统已失陷!" || echo "✅ macOS 安全" else [ -e "/tmp/ld.py" ] && echo "🚨 Linux RAT 文件存在,系统已失陷!" || echo "✅ Linux 安全" fi}check_rat# Windows PowerShell 版if (Test-Path "$env:PROGRAMDATA\wt.exe") { Write-Host "🚨 Windows RAT 文件存在,系统已失陷!" -ForegroundColor Red} else { Write-Host "✅ Windows 安全" -ForegroundColor Green}修复步骤
第一步:固定版本至安全范围
单项目修复:
# 1.x 用户
# 0.x 用户批量修复多个项目(在代码根目录执行):
# 批量固定所有项目到 1.14.0find . -name "package.json" -not -path "*/node_modules/*" -execdir npm install [email protected] --save-exact --ignore-scripts \;💡 参数说明:
--save-exact:固定版本号(1.14.0而非^1.14.0)--ignore-scripts:防止 postinstall 钩子再次触发
在 package.json 中添加强制锁定(覆盖间接依赖):
{ "dependencies": { "axios": "1.14.0" }, "overrides": { "axios": "1.14.0" }, "resolutions": { "axios": "1.14.0" }}第二步:删除 node_modules 重装
rm -rf node_modules package-lock.jsonnpm install --ignore-scripts⚠️
--ignore-scripts防止 postinstall 钩子再次触发
第三步:扫描系统残留文件
| 平台 | 检查路径 | 处理方式 |
|---|---|---|
| macOS | /Library/Caches/com.apple.act.mond | 如存在 → 系统已失陷,需重建 |
| Windows | %PROGRAMDATA%\wt.exe | 如存在 → 系统已失陷,需重建 |
| Linux | /tmp/ld.py | 如存在 → 系统已失陷,需重建 |
🚨 如发现 RAT 文件:
- 禁止就地清理 — RAT 可能已建立持久化或横向移动
- 从可信镜像重建机器
- 轮换所有凭证:npm tokens、GitHub tokens、AWS keys、云凭证、CI/CD secrets、.env 文件
02. 事件影响范围

1亿+ 周下载量的风险
axios 是 JavaScript 生态中最流行的 HTTP 客户端之一:
| 指标 | 数据 |
|---|---|
| 周下载量 | 8300 万+ |
| 依赖项目数 | 174,025 个 |
| 覆盖范围 | 前端框架、后端服务、企业应用、移动端 |
暴露窗口: 2026-03-31 00:21 UTC ~ 08:00 UTC(约 8 小时)
任何在此期间执行 npm install axios 或 npm update 的项目都可能被感染。
CI/CD 流水线为何是重灾区
这次攻击对 CI/CD 环境的打击尤为致命:
- 自动触发 — 流水线每次构建都会执行
npm install,postinstall 钩子自动运行 - 高权限访问 — CI runner 往往拥有生产环境部署权限 and 敏感 secrets
- 难以追溯 — 临时构建环境销毁后,取证线索丢失
- 横向渗透 — 被感染的 CI 可能将恶意代码部署到所有下游环境
检查你的 CI/CD:
# 审计 GitHub Actions 日志,查找恶意版本
# 所有在此期间运行过的 runner 视为失陷03. 攻击手法复盘

劫持维护者账号:攻击源起
攻击者盯上了 axios 主要维护者 jasonsaayman 的 npm 账号:
- 账户篡改 — 将注册邮箱改为攻击者控制的 ProtonMail:
[email protected] - 获取 Token — 使用长期有效的 Classic npm access token
- 绕过 CI/CD — 直接通过 npm CLI 发布,跳过 GitHub Actions OIDC 可信发布机制
关键证据:GitHub Releases 页面没有 1.14.1/0.30.4 的发布记录,说明这不是通过正常 CI 流程发布的。
恶意依赖 plain-crypto-js:隐藏的木马下载器
攻击者精心策划了一个 Phantom Dependency 攻击:
干净版本 [email protected] 依赖:├── follow-redirects├── form-data└── proxy-from-env
恶意版本 [email protected] 依赖:├── follow-redirects├── form-data├── proxy-from-env└── plain-crypto-js@^4.2.1 ← 唯一新增项关键点:对 axios 全部 86 个源文件进行搜索,plain-crypto-js 的引用次数为 零。这个依赖存在的唯一目的就是触发 postinstall 钩子。
投放器 setup.js 的混淆技术:
- 双层混淆:XOR + Base64
- 敏感字符串运行时解码
- 解码密钥:
"OrDeR_7077"
解码后的核心字符串包括 C2 地址 http://sfrclak.com:8000/ 和各平台的攻击载荷。
自清理机制:为何你发现不了?
这是这次攻击最狡猾的设计 — 执行后自我销毁:
setup.js 执行后:1. fs.unlink(__filename) → 删除自身2. fs.unlink("package.json") → 删除含 postinstall 的 manifest3. fs.rename("package.md", "package.json") → 替换为干净的 stub攻击者预置了一个干净的 package.md(版本 4.2.0,无 postinstall 钩子),在恶意代码执行后将其重命名为 package.json。
结果:事后检查时,package.json 看起来完全正常,没有任何可疑的 scripts 字段。
检测提示:即使 package.json 被恢复,只要 node_modules/plain-crypto-js/ 目录存在,就说明系统已被感染。
04. 防御建议

别再信任 latest
这次攻击再次敲响警钟:永远不要在生产环境使用 latest 标签。
// ❌ 危险做法{ "dependencies": { "axios": "latest" }}
// ✅ 安全做法{ "dependencies": { "axios": "1.14.0" }}如何配置 npm 安全策略
1. 锁定依赖版本
# 使用精确版本号
# 或在 .npmrc 中配置save-exact=true2. 禁用生命周期脚本
ignore-scripts=true
# 或在安装时指定npm install --ignore-scripts3. 启用安全审计
# 在 CI 中添加npm audit --audit-level=high
# 使用 npm audit fix 自动修复npm audit fix4. 使用锁定文件
# 始终提交 package-lock.json# CI 中使用 npm ci 而非 npm installnpm ci --ignore-scripts5. 监控依赖变化
# 检查依赖树变化npm ls --depth=0
# 使用工具监控npx npm-check-updates6. 网络层阻断
# 阻断已知 C2 域名echo "0.0.0.0 sfrclak.com" | sudo tee -a /etc/hosts总结
| 关键点 | 行动项 |
|---|---|
| 🔴 立即检查 | 运行自查命令,确认 axios 版本 |
| 🟠 如已感染 | 降级版本 + 删除 node_modules + 轮换凭证 |
| 🟢 长期防御 | 锁定版本 + 禁用 scripts + 启用审计 |
记住:供应链攻击不需要你的代码有漏洞,只需要你信任的依赖被攻破。今天是 axios,明天可能是另一个包。
发布于: 2026年4月1日 · 修改于: 2026年4月2日