新闻
- 关于axios npm供应链投毒的安全公告-网络安全宣传专题网
一、 情况分析 Axios 是npm生态中下载量最高的HTTP客户端库之一,广泛应用于React前端、Node.js后端及AI编程工具(如Codex、Claude Code)等场景。 近期监测到axios npm遭遇供应链投毒攻击,攻击者通过劫持Axios核心维护者账号,绕过GitHub Actions CI/CD流程,手动发布axios@1.14.1(针对1.x主线)和axios@0.30.4(针对0.x旧分支)两个恶意版本,植入伪装为crypto-js的恶意依赖plain-crypto-js@4.2.1。该依赖通过postinstall钩子触发混淆脚本setup.js,下载并执行跨平台RAT,实现远程控制、数据窃取与持久化驻留。 二、 影响版本 axios 0.30.4 axios 1.14.1 三、 排查方法 # 检查是否安装恶意版本 npm list axios # 查看具体版本 npm list axios --depth=0 # 检查lock文件 grep -A 5 '"axios"' package-lock.json | grep version # 检查plain-crypto-js依赖 npm list plain-crypto-js 四、处置建议 1、使用安全版本:使用非axios 0.30.4和axios 1.14.1的安全版本。 2、更换所有凭证:更换SSH密钥、数据库密码、云服务AccessKey、环境变量等所有鉴权信息 3、全盘病毒查杀:本次攻击具备远程投放木马能力,请安装最新杀毒软件对全盘文件进行查杀。如受攻击时已安装杀毒软件,请清空杀软信任区/白名单后进
文档
相关文档
解决方案
- 在项目根目录新增
.npmrc文件 - 在
.npmrc文件新增min-release-age=,填写冷静期,单位:天。作用:只会安装发布时间大雨该天数的依赖。 - 要求:npm >= 11
- 生效范围:
npm install axios,只在安装指定软件依赖时生效,如:- 当前时间:
2026-05-12 - 假设
.npmrc中配置min-release-age=365(此处为了测试,设置的是365天),package.json中使用的axios版本是^1.13.6(发布时间:2026-02-27T15:35:51.983Z,不符合min-release-age=365)xuxiaowei@172 ~/IdeaProjects/github.com/alibaba/nacos-2/console-ui-next xuxiaowei/min-release-age ±✚ npm i axios npm error code ETARGET npm error notarget No matching version found for axios@^1.13.6 with a date before 5/12/2025, 12:02:20 AM. npm error notarget In most cases you or one of your dependencies are requesting a package version that doesn't exist. npm error A complete log of this run can be found in: /Users/xuxiaowei/node_cache/_logs/2026-05-11T16_02_20_717Z-debug-0.log ✘ xuxiaowei@172 ~/IdeaProjects/github.com/alibaba/nacos-2/console-ui-next xuxiaowei/min-release-age ±✚ - 假设
.npmrc中配置min-release-age=14(此处为了测试,设置的是14天),执行npm i axios时,会把原来package.json中使用的axios版本是^1.13.6升级到^1.15.2(发布时间:2026-04-21T17:53:03.731Z,符合min-release-age=14),安装正常- 当前时间,
axios发布最新版本是1.16.0(发布时间:2026-05-02T15:04:00.274Z),没有被安装,因为不符合min-release-age=14
- 当前时间,
- 当前时间:
- 说明:node 投毒非常严重,可通过设置依赖冷静期,让社区先排查,避免第一时间中毒。社区排查后,如果发现被投毒,官方会删除对应的版本。
如何快速检查?
-
前提条件:
.npmrc中配置的min-release-age=,仅在安装指定软件依赖时生效,所以要在 CI/CD 中使用,必须基于npm install ...才能生效 -
如果读取
package.json中的依赖列表,并将依赖列表放在npm install ...中,虽然可以用于检查,但是会存在依赖自动升级和降级(依赖版本号带^、~时,可能自动升级;如果原来存在^、~,执行时去掉,可能自动降级) -
正确的方案是读取
package-lock.json中的依赖列表,只需要读取的 JSON 节点:packages[''].dependencies:依赖,这里的版本需要去掉^、~packages[''].devDependencies:开发依赖,这里的版本需要去掉^、~
-
根据上述分析,可以得到代码:
const p=require('./package-lock.json'); const root=p.packages['']; const all={...root.dependencies,...root.devDependencies}; console.log(Object.entries(all).map(([k])=>k+'@'+(version||'?')).join(' '))转化为单行 node 命令
node -e "const p=require('./package-lock.json'); const root=p.packages['']; const all={...root.dependencies,...root.devDependencies}; console.log(Object.entries(all).map(([k])=>k+'@'+((p.packages['node_modules/'+k]||{}).version||'?')).join(' '))"转化为
npm install ...命令npm install $(node -e "const p=require('./package-lock.json'); const root=p.packages['']; const all={...root.dependencies,...root.devDependencies}; console.log(Object.entries(all).map(([k])=>k+'@'+((p.packages['node_modules/'+k]||{}).version||'?')).join(' '))")为了快速检查,也可以在
package.json添加scripts{ "scripts": { "min-release-age": "npm install $(node -e \"const p=require('./package-lock.json'); const root=p.packages['']; const all={...root.dependencies,...root.devDependencies}; console.log(Object.entries(all).map(([k])=>k+'@'+((p.packages['node_modules/'+k]||{}).version||'?')).join(' '))\")" } } -
特别说明:上述
npm install $(node -e "...")命令,不会修改package.json、package-lock.json中的最终要使用的依赖版本,如果发现执行完成后,
package.json、package-lock.json文件发生变化,可能的原因:- 由于
node、npm版本不同导致的问题,如:- 代码:GitHub - alibaba/nacos at 3cf4aa35026b54a359a7bbb418de46ec483a89eb · GitHub
- 模块:nacos/console-ui-next at 3cf4aa35026b54a359a7bbb418de46ec483a89eb · alibaba/nacos · GitHub
- 使用
node v22.22.2、npm 10.9.7执行npm install时,package.json、package-lock.json文件保持不变 - 使用
node v24.15.0、npm 11.12.1执行npm install时,package.json文件保持不变,package-lock.json中存在两个node_modules/yaml,版本号分别是:2.8.3、1.10.3,会删除一个 - 此问题解决方案是需要使用相同的
node、npm版本,执行npm install $(node -e "...")前,先执行npm install不带具体依赖名称的命令,先看看package-lock.json是否有变化
npm镜像地址不同,如:- 使用
registry=https://registry.npmjs.org(默认地址)安装过 A 依赖,相关依赖的resolvedURL 使用https://registry.npmjs.org - 使用
registry=https://registry.npmmirror.com(国内镜像地址)安装过 B 依赖,相关依赖的resolvedURL 使用https://registry.npmmirror.com - 使用
npm install $(node -e "...")执行时,会被指定为当前命令运行时使用的registry=镜像地址,除了域名以外,其他内容不会发生变化 - 此问题解决方案是:提前替换为同一个域名,执行
npm install $(node -e "...")时,也使用同一个域名 - 说明:如果是测试依赖版本,CI/CD 检查依赖是否符合
min-release-age=,不必在乎此变更
- 使用
package.json中原本使用^、~版本,会与package-lock.json进行同步,并不影响所使用的版本(因为具体使用什么版本是package-lock.json控制的)
- 由于
启发
- node 项目不要使用依赖自动升级
- 定期进行软件供应链(项目依赖、编译工具、开发软件等等)进行安全扫描
- 禁止使用 node 安装依赖完成后自动执行脚本的能力(某些依赖可能无法正常安装)