【緊急】npm パッケージ「axios」が乗っ取られた事件まとめ — 2026年3月31日のサプライチェーン攻撃

【緊急】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:57plain-crypto-js@4.2.0 公開(無害なダミー版)
3/30 23:59plain-crypto-js@4.2.1 公開(マルウェア入り)
3/31 00:21axios@1.14.1 公開、latest タグ付与
3/31 01:00axios@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.1package.json には、見慣れない依存が追加されていました。

axios@1.14.1 の package.json (抜粋)
{
  "dependencies": {
    "plain-crypto-js": "^4.2.1"
  }
}

そして plain-crypto-js@4.2.1 側には、以下の postinstall フックが仕込まれていました。

plain-crypto-js@4.2.1 の package.json (抜粋)
{
  "scripts": {
    "postinstall": "node setup.js"
  }
}

npm install を実行するだけで setup.js が自動実行されるという構造です。ユーザーの操作は一切不要で、CI/CDパイプライン上でも同じ条件でトリガーされます。

二重に難読化された setup.js

setup.js は静的解析を回避するため、二段階の難読化が施されていました。

  1. 文字列を反転してからBase64デコード
  2. XOR暗号で復号(鍵: OrDeR_7077、位置依存のインデックス 7 * i^2 % 10

重要な文字列はすべて配列にエンコードされて格納されており、実行時に初めてデコードされる作りです。

OS別に異なる RAT を配信

復号後のコードはOSを判定し、各OS用のRAT(Remote Access Trojan)をC2サーバー sfrclak[.]com:8000 からダウンロードします。

OS配信方法保存先偽装名
macOSAppleScript + curl/Library/Caches/com.apple.act.mondApple のデーモン
WindowsVBScript + curl%TEMP%\6202033.ps1Windows Terminal
Linuxcurl + 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) に帰属するマルウェアです。

痕跡を消す自己消去の仕組み

最も厄介だったのが「実行後に痕跡を消す」設計です。

  1. fs.unlink(__filename)setup.js を削除
  2. 事前に用意した無害な package.mdpackage.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 でバージョンを確認

lockfile から axios バージョンを抽出
# npm の場合
grep -A1 '"axios":' package-lock.json | grep '"version"'
 
# yarn の場合
grep -A1 'axios@' yarn.lock | grep version
 
# pnpm の場合
grep -A1 'axios:' pnpm-lock.yaml

1.14.1 または 0.30.4 が含まれていたら影響を受けています。

2. plain-crypto-js が紛れ込んでいないかを確認

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/null

3. 影響があった場合の対処

安全なバージョンへの再固定
# 安全なバージョンに固定
npm install axios@1.14.2
# あるいは旧バージョン系列なら
npm install axios@0.30.3
 
# node_modules を完全に再構築
rm -rf node_modules package-lock.json
npm install

CI/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 環境でのインストール
# CI 環境では npm install ではなく npm ci を使う
npm ci

npm ci は lockfile と一致しないインストールを拒否します。攻撃者が手動で公開した新しいバージョンが、ビルドのたびに自動的に取り込まれる事故を防げます。

postinstall スクリプトを無効化する

.npmrc
ignore-scripts=true

この設定により postinstall フックが実行されなくなります。今回の setup.js のような攻撃ベクターを根元で塞げます。

ただし esbuild / sharp / puppeteer など、正当な目的で postinstall を使うパッケージもあります。導入時はプロジェクトごとに動作確認が必要です。

npm の provenance 機能で来歴を検証する

npm v9.5以降では、パッケージの 来歴(provenance) を検証できます。

署名の検証
npm audit signatures

GitHub Actions の OIDC から公開されたパッケージには署名が付与されています。侵害されたアカウントからの手動公開には署名がありません。今回のような事案は、provenance の有無で気付ける可能性があります。

サプライチェーン特化のスキャナを導入する

ツール特徴
Socketサプライチェーン攻撃に特化。今回も約 6 分で検知
Snyk脆弱性データベースが充実。CI への統合が容易
npm auditnpm 標準。最低限これは必ず実行

npm audit は既知の脆弱性しか検知できませんが、Socket のようなツールは「依存ツリーに突然現れた怪しいパッケージ」「postinstall を持つ新規依存」など、未知の振る舞いも警告してくれます。

Dependabot で自動アップデート

.github/dependabot.yml
version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "daily"
    open-pull-requests-limit: 10

Dependabot は脆弱なバージョンを検知して PR を自動作成してくれます。検知から修正までの時間を大幅に短縮できます。

公開直後のパッケージを避ける

.npmrcmin-release-age を設定すると、公開から一定時間経過していないパッケージのインストールを拒否 できます。

.npmrc
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 設定 を改めて確認することをおすすめします。

参考リンク