
【緊急】npm パッケージ「axios」が乗っ取られた事件まとめ — 2026年3月31日のサプライチェーン攻撃
2026年3月31日(UTC)、JavaScriptで最も使われるHTTPクライアントライブラリの一つ「axios」のnpmパッケージが乗っ取られ、悪意あるバージョンが公開されました。
axiosの週間ダウンロード数は 1億回超。Node.jsを使うプロジェクトであれば、ほぼ確実に直接または間接的に依存しています。今回の事件は、OSSのサプライチェーン全体の信頼性を改めて問う深刻なインシデントとなりました。
この記事では、事件の全容と技術的な仕組み、そして「自分のプロジェクトは大丈夫か」の確認手順、今後の防御策をまとめます。
事件の概要
| 項目 | 内容 |
|---|---|
| 発生日時 | 2026年3月31日 00:21〜01:00(UTC) |
| 影響パッケージ | axios |
| 影響バージョン | axios@1.14.1 / axios@0.30.4 |
| 安全なバージョン | axios@1.14.0 以前、axios@0.30.3 以前、axios@1.14.2 以降 |
| 仕込まれた依存 | plain-crypto-js@4.2.1(ファントム依存) |
| 攻撃の起点 | メンテナーアカウント jasonsaayman の乗っ取り |
| 攻撃者 | 北朝鮮系脅威アクター「Sapphire Sleet」(別名 UNC1069)と分析 |
| 公開時間 | 約2〜3時間でnpmから削除 |
攻撃の時系列
攻撃は周到に準備されていました。UTC時刻での主な流れは以下の通りです(日本時間に直すには +9時間)。
| 時刻 (UTC) | 出来事 |
|---|---|
| 3/30 05:57 | plain-crypto-js@4.2.0 公開(無害なダミー版) |
| 3/30 23:59 | plain-crypto-js@4.2.1 公開(マルウェア入り) |
| 3/31 00:21 | axios@1.14.1 公開、latest タグ付与 |
| 3/31 01:00 | axios@0.30.4 公開、legacy タグ付与 |
| 3/31 00:05頃 | Socket社の自動検知が plain-crypto-js をフラグ |
| 3/31 約03:20 | 悪意あるバージョンがnpmから削除 |
攻撃者はまず無害な plain-crypto-js@4.2.0 を公開し、npmの自動スキャンを通過させました。約18時間後に悪意あるコードを含む 4.2.1 を公開し、それを依存に組み込んだaxiosを公開する、という二段構えの手口です。
技術的な分析
起点は postinstall フック
侵害された axios@1.14.1 の package.json には、見慣れない依存が追加されていました。
{
"dependencies": {
"plain-crypto-js": "^4.2.1"
}
}そして plain-crypto-js@4.2.1 側には、以下の postinstall フックが仕込まれていました。
{
"scripts": {
"postinstall": "node setup.js"
}
}npm install を実行するだけで setup.js が自動実行されるという構造です。ユーザーの操作は一切不要で、CI/CDパイプライン上でも同じ条件でトリガーされます。
二重に難読化された setup.js
setup.js は静的解析を回避するため、二段階の難読化が施されていました。
- 文字列を反転してからBase64デコード
- XOR暗号で復号(鍵:
OrDeR_7077、位置依存のインデックス7 * i^2 % 10)
重要な文字列はすべて配列にエンコードされて格納されており、実行時に初めてデコードされる作りです。
OS別に異なる RAT を配信
復号後のコードはOSを判定し、各OS用のRAT(Remote Access Trojan)をC2サーバー sfrclak[.]com:8000 からダウンロードします。
| OS | 配信方法 | 保存先 | 偽装名 |
|---|---|---|---|
| macOS | AppleScript + curl | /Library/Caches/com.apple.act.mond | Apple のデーモン |
| Windows | VBScript + curl | %TEMP%\6202033.ps1 | Windows Terminal |
| Linux | curl + python3 | /tmp/ld.py | なし |
実装言語はOSごとに異なります(Windows: PowerShell、macOS: C++、Linux: Python)が、C2との通信プロトコルは共通でした。
| 項目 | 内容 |
|---|---|
| 通信方式 | HTTP POST で Base64 エンコードした JSON を送信 |
| User-Agent | 古い IE8 を偽装(mozilla/4.0 (compatible; msie 8.0; ...)) |
| ビーコン間隔 | 60 秒 |
| 実行可能なコマンド | kill / peinject(バイナリ注入)/ runscript / rundir |
Googleの脅威分析チーム(GTIG)は、macOSバイナリが「WAVESHAPER」バックドアと一致すると報告しています。WAVESHAPERは北朝鮮系の脅威アクター UNC1069(Sapphire Sleet) に帰属するマルウェアです。
痕跡を消す自己消去の仕組み
最も厄介だったのが「実行後に痕跡を消す」設計です。
fs.unlink(__filename)でsetup.jsを削除- 事前に用意した無害な
package.mdをpackage.jsonにリネーム
事後に node_modules を調べても何も残らないため、発見と被害把握が極めて困難でした。
影響範囲
axiosは週間1億ダウンロードを超え、^1.14.0 のような キャレット範囲指定 をしていれば npm install で自動的に 1.14.1 が降ってきます。
特に注意が必要なのは以下のようなケースです。
- CI/CD パイプライン:ビルドのたびに
npm installを実行する構成 - Docker のマルチステージビルド:イメージ作成時に依存解決
- ローカル環境での
npm install実行:package-lock.jsonを破棄して再インストールした場合 npx実行:一時ディレクトリに依存を展開するケース
公開時間が短かった(約2〜3時間)とはいえ、世界中のCIが同時刻に走っていたであろうことを考えると、影響範囲は決して小さくありません。
自分のプロジェクトを今すぐ確認する
1. lockfile でバージョンを確認
# npm の場合
grep -A1 '"axios":' package-lock.json | grep '"version"'
# yarn の場合
grep -A1 'axios@' yarn.lock | grep version
# pnpm の場合
grep -A1 'axios:' pnpm-lock.yaml1.14.1 または 0.30.4 が含まれていたら影響を受けています。
2. plain-crypto-js が紛れ込んでいないかを確認
# node_modules 内を確認
ls node_modules/plain-crypto-js 2>/dev/null \
&& echo "危険: 存在します" \
|| echo "OK: 存在しません"
# lockfile も念のため確認
grep "plain-crypto-js" package-lock.json yarn.lock pnpm-lock.yaml 2>/dev/null3. 影響があった場合の対処
# 安全なバージョンに固定
npm install axios@1.14.2
# あるいは旧バージョン系列なら
npm install axios@0.30.3
# node_modules を完全に再構築
rm -rf node_modules package-lock.json
npm installCI/CD 環境で影響があった場合は、これに加えて以下も実施してください。
- npm トークン(
NPM_TOKENなど)の 無効化と再発行 - 環境変数に含まれるシークレットの ローテーション(AWS / GCP / Azure 認証情報、SSH 鍵、API キーなど)
- ビルド成果物の 再検証(過去にデプロイしたものに紛れ込んでいないか)
特に macOS 開発機で npm install を実行した場合、/Library/Caches/com.apple.act.mond の存在を確認し、見つかった場合は端末ごとクリーンインストールを検討してください。
今後の防御策
ひとつのメンテナーが侵害されただけで世界中のサービスが影響を受ける、というのが今回の教訓です。「有名パッケージだから安全」という前提はもう通用しません。
lockfile を厳密に管理する
package-lock.json(または yarn.lock / pnpm-lock.yaml)は 必ずコミット してください。CI では npm install ではなく npm ci を使います。
# CI 環境では npm install ではなく npm ci を使う
npm cinpm ci は lockfile と一致しないインストールを拒否します。攻撃者が手動で公開した新しいバージョンが、ビルドのたびに自動的に取り込まれる事故を防げます。
postinstall スクリプトを無効化する
ignore-scripts=trueこの設定により postinstall フックが実行されなくなります。今回の setup.js のような攻撃ベクターを根元で塞げます。
ただし esbuild / sharp / puppeteer など、正当な目的で postinstall を使うパッケージもあります。導入時はプロジェクトごとに動作確認が必要です。
npm の provenance 機能で来歴を検証する
npm v9.5以降では、パッケージの 来歴(provenance) を検証できます。
npm audit signaturesGitHub Actions の OIDC から公開されたパッケージには署名が付与されています。侵害されたアカウントからの手動公開には署名がありません。今回のような事案は、provenance の有無で気付ける可能性があります。
サプライチェーン特化のスキャナを導入する
| ツール | 特徴 |
|---|---|
| Socket | サプライチェーン攻撃に特化。今回も約 6 分で検知 |
| Snyk | 脆弱性データベースが充実。CI への統合が容易 |
npm audit | npm 標準。最低限これは必ず実行 |
npm audit は既知の脆弱性しか検知できませんが、Socket のようなツールは「依存ツリーに突然現れた怪しいパッケージ」「postinstall を持つ新規依存」など、未知の振る舞いも警告してくれます。
Dependabot で自動アップデート
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "daily"
open-pull-requests-limit: 10Dependabot は脆弱なバージョンを検知して PR を自動作成してくれます。検知から修正までの時間を大幅に短縮できます。
公開直後のパッケージを避ける
.npmrc で min-release-age を設定すると、公開から一定時間経過していないパッケージのインストールを拒否 できます。
min-release-age=72h今回のように2〜3時間で削除されるケースであれば、この設定だけでも被害を防げた可能性があります。
まとめ
今回の axios 侵害事件から得られる教訓を整理します。
- メンテナーアカウントの侵害は、利用者側では防ぎようがない。依存先を信頼するだけでは不十分
npm install一発で RAT が入る。postinstallフックは強力な攻撃ベクター- 証拠隠滅まで自動化 されており、事後調査では見つけにくい
- lockfile の厳密管理 と CI/CD での
npm ciが最低限の防御ライン - Socket 等のサプライチェーン特化スキャナ が実際に約 6 分で検知した実績がある
- provenance /
min-release-age/ignore-scriptsなど、npm 側にも防御機構が増えている
axios のように世界中で使われているパッケージでも、メンテナーが一人侵害されれば一気に汚染が広がります。これを機に、自分のプロジェクトの lockfile 管理状況 と CI 設定 を改めて確認することをおすすめします。
参考リンク
- Post Mortem: axios npm supply chain compromise (axios/axios#10636)
- Supply Chain Compromise Impacts Axios Node Package Manager | CISA
- Supply Chain Compromise of axios npm Package | Huntress
- Threat Brief: Widespread Impact of the Axios Supply Chain Attack | Unit 42
- Mitigating the Axios npm supply chain compromise | Microsoft Security Blog
- Axios NPM Package Compromised | Trend Micro