Mastraのnpm侵害はeasy-day-js依存でpostinstall発火、公式116件・外部143〜144件
目次
TL;DR
影響 2026年6月17日UTC、Mastraの @mastra/* npmパッケージが一括再公開され、easy-day-js 依存経由でインストール時ペイロード(悪意あるコード本体)が実行される状態。外部調査では143〜144パッケージ、Mastra公式インシデントでは116パッケージ
発火点 Mastra本体のコードではなく、追加された "easy-day-js": "^1.11.21"。当時の新規インストールでは悪意ある easy-day-js@1.11.22 が解決され、postinstall の setup.cjs が第2段ペイロードを取得してバックグラウンド実行
対応 2026年6月17日UTCに該当バージョンをインストールした開発端末、CIランナー、ビルド環境は侵害済み扱い。npm ls easy-day-js、ロックファイル、社内npmプロキシ、CIキャッシュを確認し、LLM APIキー、クラウド認証情報、GitHub、npm、ウォレット関連をローテーション
Mastraの @mastra/* スコープで、正規パッケージがまとめて再公開された。
The Hacker Newsは、Endor Labs、JFrog、SafeDep、Socket、StepSecurityの調査を引き、144件のMastra npmパッケージが侵害されたと報じている。
Mastra公式のインシデント報告では、侵害されたメンテナのトークンから116件の悪意あるnpmパッケージが公開され、110件をunpublish、残り6件をdeprecateしたと書いている。
SafeDepは143件、The Hacker Newsは144件、StepSecurityは140件超と数えている。
数が一致しないのは、公開直後に削除されたバージョン、派生パッケージ、調査時点の差があるためだ。
確認時は記事の総数ではなく、自分のロックファイルに残ったパッケージ名とバージョンを照合する。
公式報告の時刻をJSTへ直すと、悪意あるpublishは2026年6月17日10:12〜10:37ごろ。
Mastraは同日12:45ごろに把握し、15:57ごろまでに対象パッケージをunpublishまたはdeprecateした。
17:00ごろには安全な新版を公開し、全パッケージからtoken bypass(npmトークンでMFA確認を迂回して公開できる設定)を外したと説明している。
侵害されたのは現役Mastra従業員の端末で、LinkedIn経由のソーシャルフィッシング中に不審リンクを踏んだ、というのが公式の説明だ。
今回のMastraパッケージ本体には、大きなペイロードが入っていない。
攻撃者は package.json に easy-day-js という依存を1行足し、ペイロードはその依存パッケージ側の postinstall に逃がした。
Mastra本体ではなくeasy-day-jsが動く
JFrogの解析では、影響を受けたMastraパッケージのコードはほぼ触られていない。
追加されたのは、たとえば次のような依存だ。
{
"dependencies": {
"easy-day-js": "^1.11.21"
}
}
easy-day-js は正規の dayjs に名前を寄せたタイポスクワット(名前を似せた偽パッケージ)だった。
2026年6月16日07:05 UTCに、まずクリーンな easy-day-js@1.11.21 が公開される。
その後、2026年6月17日01:01 UTCに、postinstall を持つ easy-day-js@1.11.22 が公開された。
Mastra側の依存指定は ^1.11.21 なので、当時の新規インストールでは 1.11.22 も解決対象になる。
つまり、Mastraの差分だけを確認すると「日付ライブラリらしき依存が1つ増えた」ように映るが、実際のインストールでは悪意ある 1.11.22 が入った。
この手口は、axios汚染で偽依存 plain-crypto-js のpostinstallが走った件に近い。
正規パッケージをレビューしてもペイロード本体に届かず、追加依存とバージョン範囲の差分が残る。
flowchart TD
A["攻撃者がeasy-day-js 1.11.21を公開"] --> B["同1.11.22にpostinstall追加"]
B --> C["侵害されたMastra権限で<br/>@mastra/*を一括再公開"]
C --> D["package.jsonに<br/>easy-day-js ^1.11.21"]
D --> E["利用側の新規インストールで<br/>1.11.22を解決"]
E --> F["setup.cjsが第2段ペイロード取得"]
F --> G["バックグラウンド実行と自己削除"]
G --> H["認証情報とウォレット情報の窃取"]
postinstallのあとに残るプロセスまで追う
easy-day-js@1.11.22 の postinstall は setup.cjs を実行する。
StepSecurityとSafeDepの解析では、このローダーはTLS証明書検証を無効化し、23.254.164[.]92 から第2段ペイロードを取得し、Node.jsプロセスとして一時ディレクトリからバックグラウンド実行する。
そのあとローダー側は自己削除し、npmパッケージ内の痕跡を薄くする。
Socketは、第2段ペイロードをクロスプラットフォームの情報窃取マルウェアとして解析している。
対象はブラウザ履歴、160超の暗号資産ウォレット拡張の保存データ、Windows、macOS、Linuxでの永続化、C2サーバー(攻撃者の指令サーバー)23.254.164[.]123 へのデータ送信だ。
C2はコマンドを返せるため、単発のファイル窃取だけで終わらず、追加モジュールの取得と実行まで届く。
MastraはAIアプリ、エージェント、RAG、MCP、クラウド連携の開発に使われる。
そのため、被害端末には OPENAI_API_KEY、ANTHROPIC_API_KEY、GOOGLE_API_KEY、クラウド認証情報、データベース接続文字列、GitHubやnpmのトークンが置かれていることが多い。
Mastraをimportしたかどうかは境界にならない。
npm install の時点でペイロードは動く。
Mini Shai-Huludが@antvへ広がった件では、依存を戻したあともClaude CodeやVS Code側に起動経路が残った。
今回の公開情報では、Mastra波で同じ .claude/ や .vscode/ 永続化が確認されたとは読めない。
ただし第2段ペイロードはOS側の永続化を持つとされているので、node_modules を消したあとも端末側の自動起動設定と実行中プロセスを追う。
provenanceがないpublishとして弾けた
SafeDepが挙げている差分は、SLSA provenance(出所証明)だ。
Mastraの正規リリースはCIからnpmのtrusted publisher flow(CIのOIDCでnpmへ公開する仕組み)で出ており、provenance attestation(出所証明の署名情報)が付く。
今回の悪意あるバージョンは、個人トークンからpublishされ、provenanceが落ちていた。
ここは5月のMini Shai-Hulud TanStack波と逆だった。
TanStack/Mistral波では、正規GitHub Actions経路が汚染され、SLSA provenance付きの悪意あるパッケージが出た。
Mastra波では、正規CI経路ではないpublishが混ざったため、provenance必須ポリシーや署名検証で落とせる余地があった。
読む側の判定はこう分かれる。
| 事例 | publish経路 | provenanceで分かること |
|---|---|---|
| TanStack/Mistral波 | 正規CIが悪用された | provenanceは付く。中身の安全までは言わない |
| Mastra easy-day-js波 | 個人トークンで一括publish | 正規CI由来ではない差分として弾ける |
Mastra公式も、これまでnpmメンテナにMFAを要求していた一方で、token bypassを許していたことをインシデント報告で認めている。
MFAを要求していても、既存トークンを使ったpublishは止まらなかった。
age gateとallowScriptsで止まる場所
今回の時系列では、release-age gate(公開直後のバージョンを一定期間インストールしない設定)が止める位置に当たる。
easy-day-js@1.11.22 は2026年6月17日01:01 UTCに公開され、Mastra側の一括publishはその11分後から始まった。
公開から1日待つpnpm 11の minimumReleaseAge や、Yarn 4.10の npmMinimalAgeGate が有効なら、新規インストールで easy-day-js@1.11.22 を解決する前に止まる。
pnpm 11とYarn 4.10のage gate記事で書いた「短時間露出型のnpm汚染を待って避ける」パターンそのものだ。
ただし、age gateは公開から時間が経った悪意あるバージョンや、社内プロキシへ取り込まれた後のインストールまでは消さない。
ロックファイルに入った場合、以後のCIは同じバージョンを繰り返し使う。
社内npmミラー、Dockerレイヤー、GitHub Actionsキャッシュ、pnpm storeに残ったものを個別に照合する。
もう一つの境界はinstall scriptだ。
npm v12のallowScripts記事で見た通り、npm v12では未許可の preinstall、install、postinstall が既定で止まる予定だ。
今回の easy-day-js は postinstall なので、未許可ならペイロード起動前に止まる。
この2つは役割が違う。
age gateは「取らない」、allowScriptsは「取っても実行しない」。
Mastra波では両方が同じ場所に当たる。
確認はMastraのバージョン名よりロックファイルから始める
該当するのは、2026年6月17日UTCに @mastra/* を新規インストールした環境だ。
Mastra公式は、日本時間で2026年6月17日10:12〜10:37ごろに悪意あるpublishが起きたと説明している。
外部調査では01:12〜02:39 UTCまで広く見ているので、日本時間では2026年6月17日10:12〜11:39をまず疑う。
2026年6月18日JSTにnpm registryを確認すると、easy-day-js@1.11.22 はメタデータ上から消え、latest は 1.11.21 に戻っている。
現在の npm view easy-day-js で 1.11.22 が出ないことは、当時インストールしていない証明にならない。
ロックファイル、社内npmプロキシ、CIキャッシュに当時のバージョンやtarballが残っていないかを見る。
最初に見るのはロックファイルだ。
npm ls easy-day-js
rg '"easy-day-js"|easy-day-js@1\\.11\\.22|@mastra/' package-lock.json pnpm-lock.yaml yarn.lock
easy-day-js@1.11.22 が出た端末やCIランナーは、import有無に関係なく侵害済みとして扱う。
easy-day-js@1.11.21 だけが出る場合も、該当する @mastra/* のバージョンとインストール時刻を突き合わせる。
npm uninstall で依存を消しても、第2段ペイロードがすでに動いている前提で扱う。
プロセス一覧、一時ディレクトリ、OSの自動起動設定、外向き通信、C2の 23.254.164[.]92 と 23.254.164[.]123 への到達、Node.jsの不審な子プロセスを突き合わせる。
ローテーション対象は、Mastraが触れる範囲に合わせる。
LLM APIキー、GitHubトークン、npmトークン、AWS、GCP、Azure、Vault、Kubernetes、データベース接続文字列、ウォレット拡張を同じ端末で使っていたなら、その値も露出済みとして扱う。
CIランナーで踏んだ場合は、ジョブ単位の環境変数に加え、ランナーホストに残る長期認証情報とキャッシュも確認する。
参考
- The Hacker News: 144 Mastra npm Packages Compromised via Hijacked Contributor Account
- Mastra GitHub Issue: INCIDENT REPORT: 2026-06-16: Mastra hit by supply-chain attack
- JFrog Security Research: easy-day-js: Supply Chain Campaign Targets Mastra npm Packages
- SafeDep: Mastra npm Scope Takeover: 143 Packages Drop a RAT
- Socket: 140+ Mastra npm Packages Compromised in Coordinated Supply Chain Attack
- StepSecurity: Mastra npm Supply Chain Attack: 140+ Packages Backdoored via easy-day-js Typosquat
- npm registry metadata: easy-day-js