axios が乗っ取られた日 ― npm サプライチェーン攻撃の全容と、自分のプロジェクトを守る方法

  • セキュリティ
  • npm
  • サプライチェーン攻撃

Sponsored

2026年3月31日、JavaScript 界隈が一斉にざわつきました。

週間1億ダウンロードを超える HTTP クライアント axios の npm パッケージが乗っ取られ、マルウェア入りのバージョンが公式レジストリに公開されました。しかも犯行時間はわずか約3時間。その短い窓の間に npm install を実行した環境には、クロスプラットフォーム対応の RAT(遠隔操作ツール)が仕込まれていました。

この記事では、何が起きたのか、自分が影響を受けているかの確認方法、そして今後どう守るかを整理します。

何が起きたか

攻撃者は axios のリードメンテナーの npm アカウントを乗っ取り、2つの不正バージョンを公開しました。

  • axios@1.14.1latest タグ)
  • axios@0.30.4legacy タグ)

公開時刻は UTC 2026-03-31 00:21 頃。日本時間だと 3月31日の午前9時21分頃にあたります。npm 側が削除したのが UTC 03:15~03:30 頃なので、悪意あるバージョンがレジストリ上に存在していたのはおよそ3時間弱です。

手口はこうです。axios のソースコード自体は一切変更していません。代わりに package.json の依存関係に plain-crypto-js@4.2.1 という見慣れないパッケージをこっそり追加しています。このパッケージの postinstall フックが setup.js を実行し、OS を判別して Windows / macOS / Linux それぞれに対応した RAT をダウンロード・実行する仕組みでした。

厄介なのは、マルウェアが実行後に自分自身を削除し、package.json も正常な状態に書き戻すこと。事後に node_modules/plain-crypto-js/ を覗いても、きれいな状態しか残っていません。npm audit でも検出できません。証拠隠滅まで自動化されています。

Google の脅威インテリジェンスチーム(GTIG)は、この攻撃を北朝鮮系の脅威アクター UNC1069 によるものと公表しています。

影響を受けるバージョン

影響があるのは以下の2バージョンだけです。

バージョンタグ備考
1.14.1latest正規リリースに GitHub タグなし
0.30.4legacy同上

安全なバージョンは 1.14.0(1.x 系)と 0.30.3(0.x 系)。現在は npm 上から不正バージョンは削除済みで、latest タグは 1.14.0 に戻っています。

自分が影響を受けているか確認する

ここからが実戦パートです。

1. lockfile を grep する

まずは自分のプロジェクトの package-lock.jsonyarn.lock を確認します。

# package-lock.json の場合
grep -E '"axios".*"(1\.14\.1|0\.30\.4)"' package-lock.json
grep 'plain-crypto-js' package-lock.json

# yarn.lock の場合
grep -E 'axios@.*(1\.14\.1|0\.30\.4)' yarn.lock
grep 'plain-crypto-js' yarn.lock

ここで何もヒットしなければ、そのプロジェクトは問題ありません。

2. node_modules の中を直接見る

lockfile だけでは不安な場合、インストール済みの axios のバージョンを直接確認します。

cat node_modules/axios/package.json | grep '"version"'

1.14.10.30.4 が出てきたら要対応です。

もう少し広く調べたいなら、マシン上のすべての node_modules を走査します。

find / -path "*/node_modules/axios/package.json" 2>/dev/null | while read f; do
  version=$(grep '"version"' "$f" | head -1)
  echo "$f -> $version"
done

3. 正規の axios の依存関係を知っておく

正規の axios が持つ依存パッケージは3つだけです。

  • follow-redirects
  • form-data
  • proxy-from-env

ここに plain-crypto-js が混ざっていたら、不正バージョンがインストールされた痕跡です。

cat node_modules/axios/package.json | grep -A 10 '"dependencies"'

lockfile と npm ci を使っていれば被害を回避できた

今回の攻撃でもっとも分かれ目になったのは、lockfile の運用です。

package.json"axios": "^1.14.0" と書いてあっても、攻撃前に生成された lockfile がコミットされていて、デプロイ時に npm ci を使っていた環境は影響を受けていません。

理由は単純で、npm ci は lockfile に記載されたバージョンを厳密にインストールするからです。lockfile に 1.14.0 と書いてあれば、レジストリに 1.14.1 が出ていようが無視します。

一方、npm install は lockfile が存在していても、package.json のセマンティックバージョニング範囲内で新しいバージョンがあれば lockfile を更新してしまうケースがあります。CI/CD パイプラインで npm install を使っていた環境が、今回もっとも被害を受けやすかったわけです。

# NG: CI/CD でこれをやっていると、攻撃窓の間に新バージョンを引いてしまう可能性がある
npm install

# OK: lockfile を厳密に尊重する
npm ci

これは今回に限った話じゃないです。サプライチェーン攻撃全般に対する防御として、CI/CD では npm ci を使うのが鉄則です。

影響を受けていた場合の対応

lockfile に不正バージョンが記録されていた場合、パッケージの入れ替えだけでは不十分です。RAT がインストール時に実行されている以上、その環境は「侵害済み」として扱う必要があります。

やるべきことを挙げると、

  • axios を安全なバージョンに固定し直す(npm install axios@1.14.0 --ignore-scripts
  • node_modules/plain-crypto-js が存在していれば削除
  • そのマシンでアクセス可能だったクレデンシャルをすべてローテーション(SSH 鍵、API キー、npm トークン、クラウドのアクセスキーなど)
  • CI/CD で使っていたシークレットも同様にローテーション
  • 可能であれば、影響を受けたマシンは攻撃前のバックアップからクリーンに復元する

特にクレデンシャルのローテーションは最優先です。RAT が動いていた時間にマシン上にあった秘密情報は、すべて漏洩した前提で動くしかありません。

今後に向けて ― 手元でできる防御策

今回の件を受けて、個人プロジェクトや小規模チームでもやっておくべきことを整理します。

lockfile は必ずコミットする

package-lock.jsonyarn.lock.gitignore に入れているプロジェクトをたまに見かけますが、やめたほうがいいです。lockfile がなければ、npm install のたびにレジストリから最新を引いてきます。それはつまり、攻撃者が公開した不正バージョンをそのまま受け入れるということです。

CI/CD では npm ci を徹底する

繰り返しになりますが、npm ci は lockfile の内容を厳密に再現します。lockfile と package.json に矛盾があればエラーで止まるので、意図しないバージョンの混入を検知できます。

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

今回の攻撃は postinstall フックが起点でした。CI/CD で --ignore-scripts を付けてインストールすれば、このクラスの攻撃を丸ごと無効化できます。

npm ci --ignore-scripts

ただし、ネイティブモジュールのビルドなど postinstall が正当に必要なパッケージもあるので、そこは個別に対処が要ります。

pnpm を検討する

pnpm はデフォルトで lifecycle スクリプト(postinstall 等)を実行しません。明示的に許可リストに追加したパッケージだけが実行されます。今回のような攻撃に対しては、パッケージマネージャーの選択自体が防御になります。

まとめ

今回の攻撃は、axios ほどの超メジャーパッケージでも npm アカウントが1つ乗っ取られるだけで全世界に影響が出る、ということを嫌というほど見せつけました。

被害の大小を分けたのは、結局のところ地味な運用でした。lockfile をコミットしていたか。CI で npm ci を使っていたか。postinstall スクリプトを制御していたか。

特別なセキュリティツールの話ではなく、npm の基本機能をちゃんと使っていたかどうかで明暗が分かれました。怠惰に見えて、実は一番手堅いです。

参考リンク

Sponsored