Node min-release-age:依赖发布冷静期、依赖发布最小时间、避免依赖投毒、预防 0day 攻击、避免漏洞传播扩散

新闻

  • 关于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、全盘病毒查杀:本次攻击具备远程投放木马能力,请安装最新杀毒软件对全盘文件进行查杀。如受攻击时已安装杀毒软件,请清空杀软信任区/白名单后进
    

文档

相关文档

  1. node、npm、npx 对应关系
  2. Node 配置文件

解决方案

  1. 在项目根目录新增 .npmrc 文件
  2. .npmrc 文件新增 min-release-age=,填写冷静期,单位:。作用:只会安装发布时间大雨该天数的依赖。
  3. 要求:npm >= 11
  4. 生效范围:npm install axios,只在 安装指定软件依赖时生效,如:
    1. 当前时间:2026-05-12
    2. 假设 .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 ±✚ 
      
    3. 假设 .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
  5. 说明:node 投毒非常严重,可通过设置依赖冷静期,让社区先排查,避免第一时间中毒。社区排查后,如果发现被投毒,官方会删除对应的版本。

如何快速检查?

  1. 前提条件:.npmrc 中配置的 min-release-age=,仅在 安装指定软件依赖时生效,所以要在 CI/CD 中使用,必须基于 npm install ... 才能生效

  2. 如果读取 package.json 中的依赖列表,并将依赖列表放在 npm install ... 中,虽然可以用于检查,但是会存在依赖自动升级和降级(依赖版本号带 ^~ 时,可能自动升级;如果原来存在 ^~,执行时去掉,可能自动降级)

  3. 正确的方案是读取 package-lock.json 中的依赖列表,只需要读取的 JSON 节点:

    1. packages[''].dependencies:依赖,这里的版本需要去掉 ^~
    2. packages[''].devDependencies:开发依赖,这里的版本需要去掉 ^~
  4. 根据上述分析,可以得到代码:

    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(' '))\")"
      }
    }
    
  5. 特别说明:上述 npm install $(node -e "...") 命令,不会修改 package.jsonpackage-lock.json 中的最终要使用的依赖版本,如果发现执行完成后,
    package.jsonpackage-lock.json 文件发生变化,可能的原因:

    1. 由于 nodenpm 版本不同导致的问题,如:
      1. 代码:GitHub - alibaba/nacos at 3cf4aa35026b54a359a7bbb418de46ec483a89eb · GitHub
      2. 模块:nacos/console-ui-next at 3cf4aa35026b54a359a7bbb418de46ec483a89eb · alibaba/nacos · GitHub
      3. 使用 node v22.22.2npm 10.9.7 执行 npm install 时,package.jsonpackage-lock.json 文件保持不变
      4. 使用 node v24.15.0npm 11.12.1 执行 npm install 时,package.json 文件保持不变,package-lock.json 中存在两个 node_modules/yaml,版本号分别是:2.8.31.10.3,会删除一个
      5. 此问题解决方案是需要使用相同的 nodenpm 版本,执行 npm install $(node -e "...") 前,先执行 npm install 不带具体依赖名称的命令,先看看 package-lock.json 是否有变化
    2. npm 镜像地址不同,如:
      1. 使用 registry=https://registry.npmjs.org(默认地址)安装过 A 依赖,相关依赖的 resolved URL 使用 https://registry.npmjs.org
      2. 使用 registry=https://registry.npmmirror.com(国内镜像地址)安装过 B 依赖,相关依赖的 resolved URL 使用 https://registry.npmmirror.com
      3. 使用 npm install $(node -e "...") 执行时,会被指定为当前命令运行时使用的 registry= 镜像地址,除了域名以外,其他内容不会发生变化
      4. 此问题解决方案是:提前替换为同一个域名,执行 npm install $(node -e "...") 时,也使用同一个域名
      5. 说明:如果是测试依赖版本,CI/CD 检查依赖是否符合 min-release-age=,不必在乎此变更
    3. package.json 中原本使用 ^~ 版本,会与 package-lock.json 进行同步,并不影响所使用的版本(因为具体使用什么版本是 package-lock.json 控制的)

启发

  1. node 项目不要使用依赖自动升级
  2. 定期进行软件供应链(项目依赖、编译工具、开发软件等等)进行安全扫描
  3. 禁止使用 node 安装依赖完成后自动执行脚本的能力(某些依赖可能无法正常安装)