警惕:广泛使用的 color npm 包遭入侵,植入恶意代码窃取加密货币

一次针对开源生态供应链的攻击,波及数十个热门 npm 包,影响不可小觑。

2025 年 9 月 8 日,一个再平常不过的周一,JavaScript 开源生态系统却经历了一场严重的安全风波。一位名为 Josh Junon(在 npm 上用户名是 qix)的开发者账户被入侵,其名下维护的多个热门 npm 包被发布了携带后门的恶意版本。

事件是如何开始的?

事件始于世界协调时(UTC)9 月 8 日下午 13:00 左右。攻击者成功控制了 Josh 的 npm 账户,并开始向他维护的多个流行包中发布带有恶意代码的版本。

幸运的是,开源社区的警惕性很高。有人很快注意到了这些可疑的更新,并立即通过社交媒体联系了 Josh。

Charlie Eriksen 通知 Josh 其账户可能被入侵

Josh 很快确认了他的账户确实遭到了入侵。原因是一个看起来非常逼真的双因素认证(2FA)重置钓鱼邮件。他提到,只有 npm 账户受影响,并已联系 npm 支持团队,希望能尽快恢复访问权限。

Josh 确认自己遭遇钓鱼攻击

狡猾的钓鱼邮件

攻击者使用的钓鱼邮件发件人域名是 npmsj.help(该域名注册于攻击发生前 3 天)。邮件内容伪装成 npm 官方的安全提醒,声称为了账户安全,要求用户更新他们的双因素认证(2FA)设置。

邮件正文写道:“您好!作为我们持续承诺账户安全的一部分,我们要求所有用户更新其双因素认证(2FA)凭证。我们的记录显示,您上次更新 2FA 已超过 12 个月。” 并威胁说如果不在 2025 年 9 月 10 日前更新,账户将被暂时锁定。

钓鱼邮件内容

这封邮件的原始版本已被公开,分析表明它可能是通过邮件测试服务 Mailtrap 发送的。

哪些包受到影响?

安全研究人员 Kevin Beaumont 在 Mastodon 上列出了已知受影响的包列表。这些包在之前的总下载量已达到数十亿次:

  • supports-hyperlinks
  • chalk-template
  • simple-swizzle
  • slice-ansi
  • error-ex
  • is-arrayish
  • wrap-ansi
  • backslash
  • color-string
  • color-convert
  • color
  • color-name

其中,color 包本身每周就有约 3170 万 次下载,可见其影响范围之广。

color 包每周下载量巨大

恶意代码做了什么?(技术分析)

恶意代码的完整载荷已被公开。根据初步分析,这些代码似乎并非设计在服务器环境(如 Node.js 或 Bun)或开发者机器上运行,而是专门针对浏览器环境

这意味着这次攻击要成功窃取资金,需要满足一系列特定条件:

  1. 某个加密货币网站或 Web 应用的维护者必须升级了受感染的依赖项。
  2. 这些依赖项必须被用于网站的前端(浏览器)部分。
  3. 该加密货币网站必须完成了构建、打包和部署流程。
  4. 用户必须在该后门活跃期间进行了交易。

简单来说,如果开发者只是合并了一个更新依赖项的拉取请求(PR),并且在 CI 中运行了一些测试,那么可能尚未造成实际损害。但安全社区仍在全力分析载荷的完整功能和所有受影响的确切范围。

通过对混淆代码进行反混淆处理,我们可以清晰地了解其恶意行为。

简而言之,其核心目的是篡改加密货币地址,将资金转入攻击者控制的钱包。

具体攻击手段

  1. 劫持网络请求:代码挂钩了 fetchXMLHTTPRequest 函数,用于监控所有网络响应。任何在响应体中发现的、类似于比特币(Bitcoin)、Solana、莱特币 v2(Litecoin v2)等的加密货币地址都会被动态替换成攻击者预先准备好的地址列表中的一个。

  2. 针对 MetaMask 等钱包:代码每隔 500 毫秒会尝试检查是否有以太坊账户已通过 MetaMask 等钱包授权。一旦发现,便会劫持 window.ethereum.request 方法,篡改特定的交易请求:

    • approve(address,uint256):替换目标地址并将授权金额设置为最大上限。此路径还会记录去中心化交易所(DEX)的名称(如 Uniswap, PancakeSwap, 1inch, SushiSwap)。
    • permit(address,address,uint256,uint256,uint8,bytes32,bytes32):替换目标地址并最大化其值。
    • transfer(address,uint256):替换目标地址,但保持转账金额不变。
    • transferFrom(address,address,uint256):替换目标地址,但保持转账金额不变。
  3. 针对 Solana 链:代码中也包含处理 Solana 交易的路径,会将相关字段修改为特定的字符串 19111111111111111111111111111111,但其有效性尚不完全明确。

这种攻击非常狡猾,它不修改用户发出的请求内容(request body),而是修改服务器返回的响应内容(response body)。它很可能针对的是那些通过 API 调用获取收款地址,然后再通过其他方式发起转账的网站或应用。

当前情况与应对

截至 2025 年 9 月 8 日 17:19 UTC

  • npm 官方已联系 Josh,表示正在努力移除恶意的软件包。

截至 2025 年 9 月 8 日 17:11 UTC

  • Josh 仍然被锁在自己的 npm 账户之外。
  • 受影响的著名包 chalk 已被其合作维护者 Sindre Sorhus 修复。
  • 但其他一些包(如 simple-swizzle)的恶意版本仍然存在于 npm 上,未被下架。
simple-swizzle 包的代码中仍可见混淆的恶意代码

面对如此紧急的安全事件,npm 官方的响应速度受到了社区的批评。Josh 在事件发生后近两小时仍未收到 npm 的任何邮件回复,这给攻击者留下了更长的窗口期来扩大危害。

总结与反思

这次 color 等 npm 包被入侵的事件,再次为开源软件供应链安全敲响了警钟。它揭示了几个关键问题:

  1. 开发者账户是薄弱环节:攻击者不再需要直接攻破庞大的平台,而是通过钓鱼等方式 targeting 单个维护者,就能影响成千上万的项目。
  2. 依赖关系的复杂性:一个基础包的妥协,会通过依赖树迅速向上传播,影响无数上层应用。许多开发者可能甚至不知道自己间接依赖了 color
  3. 平台响应机制:在紧急安全事件中,官方平台需要更快速、更透明的响应和处理流程,以保护整个生态系统。
  4. 安全意识至关重要:对于所有开发者而言,对钓鱼邮件保持警惕、启用并安全地管理 2FA、定期审查依赖项,是必不可少的自我保护措施。

对于普通用户而言,此次事件主要影响的是加密货币相关网站和应用的开发者及使用者。建议近期在进行任何链上交易时格外谨慎,多次核对收款地址,并留意社区发布的安全警告。

开源生态的强大在于协作,但其脆弱性也在于此。维护每一个环节的安全,需要平台、维护者和开发者共同的努力和警惕。


FAQs

1. 我的项目是否受到影响?
如果你在项目中直接或间接依赖了上述列表中的包(如 color, chalk 等),并且最近(9月8日后)升级了版本,那么你的项目可能包含了恶意代码。建议立即检查 package-lock.jsonyarn.lock 文件,锁定并回退到已知安全的版本。

2. 作为开发者,我现在应该做什么?

  • 立即检查你的项目依赖,确认是否使用了受影响包的最新恶意版本。
  • 将依赖版本回退到之前已知安全的版本。
  • 如果你运行了可能包含恶意代码的项目,检查你的系统是否有未经授权的访问或交易。
  • 如果你是库的维护者,请审核你的依赖项并更新至安全版本。

3. 这次攻击会窃取我电脑上的文件或个人数据吗?
根据当前分析,此恶意代码的主要目标是篡改浏览器中的加密货币交易。目前没有证据表明它旨在窃取本地文件或个人数据。但其能力最终取决于攻击者的意图,保持警惕是必要的。

4. 如何避免此类钓鱼攻击?

  • 永远不要点击邮件中的链接来重置 2FA 或登录账户。始终直接访问官方网站进行操作。
  • 仔细检查发件人邮箱地址,官方邮件通常来自公司域名。
  • 启用硬件安全密钥或认证器应用的 2FA,这比 SMS(短信)2FA 更安全。
  • 对任何声称“紧急”或“需要立即行动”的邮件保持怀疑。

5. npm 官方会如何处理这些恶意包?
通常,npm 安全团队在确认后会将恶意包下架,使其无法被继续安装。但对于已经安装了恶意版本的系统,需要开发者自行检查和清理。