投毒预警 官方 npm 账号失陷导致 32 个包遭投毒 通过 easy-day-js 下载远程有效载荷

投毒预警 官方 npm 账号失陷导致 32 个包遭投毒 通过 easy-day-js 下载远程有效载荷

事件概述

一名攻击者接管了一名 Mastra 维护者的账号,并利用该账号对项目进行了大规模篡改。在短短 27 分钟内,他们重新发布了整个 @mastra 目录下的所有包。他们并没有动 Mastra 自身的代码,而是在每个包中都修改了一行代码,添加了一个指向名为 easy-day-js 的伪造组件的隐藏链接——该组件是针对广泛使用的工具 dayjs 的仿冒品。
在这里插入图片描述

Mastra 是一个开源工具包,软件开发者利用它来构建 AI 应用和智能体(agents)。它出自 Gatsby 背后的团队之手,并被广泛采用:该项目的组件每月被构建在其之上的团队下载超过 2800 万次。像大多数现代软件一样,Mastra 以一组小型、可重用的构建块形式分发,其他程序会自动拉取这些构建块。正是这种广泛的影响力,使得一个账号被盗变得如此危险。

easy-day-js 是一种“拼写劫持”(typosquat)攻击。它从描述到捆绑的 dayjs.min.js 文件都在模仿 dayjs,但增加了一个运行“投毒器”(dropper)的安装后钩子(postinstall hook)。安装时,该投毒器会禁用 TLS 证书验证,从一个原生 IP 地址获取第二阶段恶意负载(payload),将其写入临时目录,并作为分离且隐藏的子进程运行,最后自我删除。

在这里插入图片描述

这次事件有三个显著特点:

​ 整个组织账号瞬间沦陷:这并非针对单个包,而是在不到半小时内对 116 个包进行了脚本化的扫荡,大致按下载量排序。这表明是一个拥有整个范围(scope)发布权限的账号被劫持,而非单一的恶意发布。

​ 载体包本身是“干净”的,负载隐藏在下一层:每个 Mastra 包本身都是未经修改的库,仅包含一行被投毒的依赖项。那些仅检查指定包自身代码的扫描工具将无法发现任何异常。恶意行为存在于 easy-day-js 中,而在大多数 Mastra 包中,该依赖项甚至从未被实际导入调用。

​ 预先部署的诱饵依赖:easy-day-js@1.11.21 在一天前就已发布,且没有安装钩子,是一个干净的诱饵。而被武器化的 1.11.22 版本于 UTC 时间 01:01 上线,仅比 Mastra 扫荡开始早了 11 分钟。

影响包

以下所有版本均为恶意版本,发布于2026年6月17日。请固定到每个版本的最后已验证来源发布的版本,并将这些特定版本视为已被入侵。

PackageMalicious versionPublished (UTC)Downloads/month
@mastra/schema-compat1.2.121:125,279,923
@mastra/core1.42.11:154,013,267
mastra1.13.11:202,139,510
@mastra/memory1.20.41:162,057,689
@mastra/server2.1.11:171,864,647
@mastra/deployer1.42.11:191,858,620
@mastra/observability1.14.21:181,695,048
@mastra/loggers1.1.31:181,672,903
@mastra/pg1.13.11:251,361,195
@mastra/mcp1.10.11:251,203,924
@mastra/ai-sdk1.4.61:271,069,650
@mastra/libsql1.13.11:26977,312
@mastra/langfuse1.3.61:29617,580
@mastra/evals1.3.11:29476,879
@mastra/rag2.2.21:30307,033
@mastra/datadog1.2.51:30253,586
@mastra/duckdb1.4.31:32222,862
@mastra/braintrust1.1.41:33187,050
@mastra/dynamodb1.0.91:31160,266
@mastra/hono1.4.261:32152,792
@mastra/otel-bridge1.2.31:33132,788
@mastra/editor0.11.31:34128,885
@mastra/langsmith1.2.41:34120,459
@mastra/mcp-docs-server1.1.471:3797,609
@mastra/mongodb1.9.31:3592,100
@mastra/posthog1.0.291:3690,917
@mastra/fastembed1.1.31:3977,220
@mastra/s30.5.31:3864,299
@mastra/sentry1.1.41:3563,793
@mastra/fastify1.3.311:3961,020
@mastra/auth1.0.31:3859,979
@mastra/inngest1.5.21:3951,427
@mastra/acp0.2.21:55not separately reported
@mastra/agent-browser0.3.21:42not separately reported
@mastra/agent-builder1.0.421:59not separately reported
@mastra/agentcore0.2.22:23not separately reported
@mastra/agentfs0.1.12:17not separately reported
@mastra/arize1.2.31:44not separately reported
@mastra/arthur0.3.32:22not separately reported
@mastra/astra1.0.22:06not separately reported
@mastra/auth-auth01.0.21:54not separately reported
@mastra/auth-better-auth1.0.41:45not separately reported
@mastra/auth-clerk1.0.31:46not separately reported
@mastra/auth-cloud1.1.42:08not separately reported
@mastra/auth-firebase1.0.12:20not separately reported
@mastra/auth-okta0.0.52:18not separately reported
@mastra/auth-studio1.2.42:16not separately reported
@mastra/auth-supabase1.0.21:47not separately reported
@mastra/auth-workos1.5.31:55not separately reported
@mastra/azure0.2.32:18not separately reported
@mastra/blaxel0.4.21:57not separately reported
@mastra/brightdata0.2.22:19not separately reported
@mastra/browser-viewer0.1.32:15not separately reported
@mastra/chroma1.0.21:45not separately reported
@mastra/claude1.0.32:02not separately reported
@mastra/clickhouse1.10.11:37not separately reported
@mastra/client-js1.24.11:26not separately reported
@mastra/cloudflare1.4.21:55not separately reported
@mastra/cloudflare-d11.0.71:50not separately reported
@mastra/codemod1.0.42:23not separately reported
@mastra/convex1.2.21:46not separately reported
@mastra/couchbase1.0.41:58not separately reported
@mastra/cursor0.2.12:04not separately reported
@mastra/daytona0.4.21:41not separately reported
@mastra/deployer-cloud1.42.12:05not separately reported
@mastra/deployer-cloudflare1.1.441:47not separately reported
@mastra/deployer-netlify1.1.202:02not separately reported
@mastra/deployer-vercel1.1.381:41not separately reported
@mastra/docker0.3.11:53not separately reported
@mastra/dsql1.0.31:57not separately reported
@mastra/e2b0.3.41:44not separately reported
@mastra/elasticsearch1.2.12:20not separately reported
@mastra/express1.3.311:31not separately reported
@mastra/files-sdk0.2.12:06not separately reported
@mastra/gcs0.2.31:48not separately reported
@mastra/github-signals0.1.22:07not separately reported
@mastra/google-cloud-pubsub1.0.62:03not separately reported
@mastra/google-drive0.1.12:21not separately reported
@mastra/koa1.5.142:00not separately reported
@mastra/laminar1.2.32:09not separately reported
@mastra/lance1.0.72:04not separately reported
@mastra/longmemeval1.0.501:54not separately reported
@mastra/mcp-registry-registry1.0.22:00not separately reported
@mastra/mssql1.3.21:56not separately reported
@mastra/mysql0.1.12:21not separately reported
@mastra/nestjs0.1.151:51not separately reported
@mastra/openai1.0.22:05not separately reported
@mastra/opencode0.0.472:17not separately reported
@mastra/opensearch1.0.32:04not separately reported
@mastra/otel-exporter1.2.31:28not separately reported
@mastra/perplexity0.1.12:24not separately reported
@mastra/pinecone1.0.21:52not separately reported
@mastra/playground-ui33.0.11:49not separately reported
@mastra/qdrant1.0.31:46not separately reported
@mastra/react1.0.11:42not separately reported
@mastra/redis1.1.31:48not separately reported
@mastra/redis-streams0.0.42:03not separately reported
@mastra/s3vectors1.0.71:50not separately reported
@mastra/slack1.3.12:19not separately reported
@mastra/spanner1.1.22:22not separately reported
@mastra/stagehand0.2.51:40not separately reported
@mastra/tavily1.0.31:45not separately reported
@mastra/temporal0.1.141:53not separately reported
@mastra/turbopuffer1.0.31:52not separately reported
@mastra/twilio1.0.22:16not separately reported
@mastra/upstash1.1.31:43not separately reported
@mastra/vectorize1.0.31:58not separately reported
@mastra/voice-aws-nova-sonic0.1.42:01not separately reported
@mastra/voice-azure0.11.22:23not separately reported
@mastra/voice-deepgram0.12.21:53not separately reported
@mastra/voice-elevenlabs0.12.21:51not separately reported
@mastra/voice-google0.12.31:51not separately reported
@mastra/voice-google-gemini-live0.12.21:43not separately reported
@mastra/voice-openai0.12.31:42not separately reported
@mastra/voice-openai-realtime0.12.61:40not separately reported
create-mastra1.13.11:56not separately reported
PackageVersionRole
easy-day-js1.11.22Weaponized, postinstall dropper, published 2026-06-17 01:01 UTC
时间线
时间 (UTC)事件
2026-06-16 07:05发布 easy-day-js@1.11.21,一个没有安装钩子(install hook)的干净诱饵
2026-06-17 01:01发布 easy-day-js@1.11.22,携带安装后投毒器(postinstall dropper)
2026-06-17 01:12第一个 Mastra 包被重新发布 (@mastra/schema-compat)
2026-06-17 01:12 - 01:3932 个 Mastra 包由 ehindero 重新发布,且无Attestations信息(no provenance)
IOC失陷指标
软件包指标 (Package indicators)

除上表列出的所有 32 个 Mastra 版本外,还包括:

指标备注
easy-day-js@1.11.22武器化的投毒器 (Dropper)
easy-day-js@1.11.21干净的诱饵,但仍由攻击者控制,应予以封禁
发布者 ehindero / ehindero2016@tutamail.com用于所有恶意发布的账号
2026-06-17 发布且无 SLSA 溯源的任何 @mastra/* 或 mastra 版本在 CI 流程之外进行的手动发布
网络指标 (Network indicators)
指标备注
https://23.254.164.92:8000/update/49890878第二阶段恶意负载 (Payload) 的 URL
23.254.164.123:443位于同一 /24 网段的次要端点
文件与行为指标 (File and behavioral indicators)
指标备注
~/.pkg_history包含安装路径的标记文件
~/.pkg_logs由钩子 (hook) 投放的标记文件
主目录下随机命名的 <24位十六进制>.js 文件获取到的第二阶段负载
npm install 期间运行 node setup.cjs投毒器正在运行
安装脚本设置了 NODE_TLS_REJECT_UNAUTHORIZED=0禁用了 TLS 证书验证
安装期间生成了分离的 node 子进程恶意负载正在后台运行
代码特征 (Code markers)
特征码备注
"postinstall": "node setup.cjs --no-warnings"存在于 easy-day-js@1.11.22
process.env.NODE_TLS_REJECT_UNAUTHORIZED='0'存在于 setup.cjs
Buffer.from(... ); ... spawn(process.execPath, ...).unref()分离式启动恶意负载的代码
fs.rmSync(__filename, { force: true })finally 代码块中的自删除操作
处置建议
1. 检查暴露情况

检查你的依赖树中是否存在受影响的软件包或投毒器:

# 检查是否存在 easy-day-js
npm ls easy-day-js

# 在 lock 文件中查找 Mastra 相关包或 easy-day-js
grep -REn "@mastra/|\"mastra\"|easy-day-js" package-lock.json yarn.lock pnpm-lock.yaml 2>/dev/null

在主机和 CI 运行器(CI Runners)上寻找留下的痕迹(Artifacts):

# 检查标记文件是否存在
ls -la ~/.pkg_history ~/.pkg_logs 2>/dev/null


# 查找 2026-06-17 之后在主目录下生成的随机 .js 文件
find "$HOME" -maxdepth 1 -type f -name '*.js' -newermt '2026-06-17' 2>/dev/null

预防措施:

  • 将所有 Mastra 依赖锁定 (Pin) 在最后一个通过 GitHub Actions 发布且带有溯源信息 (Provenance) 的版本。
  • easy-day-js 添加到你的私有仓库或镜像源的黑名单中。

2. 如果你已经安装了受影响的版本

请视该主机为已失陷(Compromised)。 投毒器在进程内禁用了 TLS 验证,并启动了一个内容在运行时动态获取的脱离父进程的子进程。因此,安装钩子(Install Hook)所表现出的行为并不是攻击的全部。

  • 轮换凭据: 更换受影响主机或 CI 运行器可以访问的所有凭据,包括:云端密钥(Cloud Keys)、仓库令牌(Registry Tokens)、CI 密钥(Secrets)以及构建过程可读取的环境变量中的任何内容。
  • 清理进程与文件: 搜寻并杀掉在安装时间前后生成的任何脱离父进程的 node 进程,并删除主目录下的随机 .js 文件。
  • 封禁网络通信: 封禁发往 23.254.164.9223.254.164.123 的所有出站流量,并审查自 UTC 时间 2026-06-17 01:12 以来发往这两个 IP 的出站日志。

库令牌(Registry Tokens)、CI 密钥(Secrets)以及构建过程可读取的环境变量中的任何内容。

  • 清理进程与文件: 搜寻并杀掉在安装时间前后生成的任何脱离父进程的 node 进程,并删除主目录下的随机 .js 文件。
  • 封禁网络通信: 封禁发往 23.254.164.9223.254.164.123 的所有出站流量,并审查自 UTC 时间 2026-06-17 01:12 以来发往这两个 IP 的出站日志。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值