Axiosがnpmで侵害され、リモートアクセス型トロイの木馬が配布される
(stepsecurity.io)- 広く使われているaxios HTTPクライアントの2つの悪性バージョンがnpmに公開され、インストール時にリモートアクセス型トロイの木馬(RAT) を配布した
- 攻撃者はメンテナーアカウントの認証情報窃取によってGitHub Actionsを迂回し、手動で悪性パッケージをアップロードした
- 悪性バージョンには偽の依存関係
plain-crypto-js@4.2.1が含まれており、postinstallスクリプトでRATをインストールして痕跡を削除する - RATはmacOS、Windows、Linuxのすべてに感染し、C2サーバー(
sfrclak.com:8000)と通信して追加ペイロードをダウンロードする - npmとGitHubは迅速に悪性バージョンを削除したが、サプライチェーンセキュリティ強化と認証情報保護の重要性が改めて浮き彫りになった
axios npmサプライチェーン攻撃の概要
- 2026年3月31日、広く使われているaxios HTTPクライアントライブラリの2つの悪性バージョン(
axios@1.14.1、axios@0.30.4)がnpmに公開された - 攻撃者はaxios主要メンテナーのnpm認証情報を窃取し、GitHub ActionsのCI/CDパイプラインを迂回して手動で悪性パッケージを公開した
- 2つのバージョンはいずれも**
plain-crypto-js@4.2.1** という偽の依存関係を挿入しており、このパッケージはpostinstallスクリプトを通じてリモートアクセス型トロイの木馬(RAT) をインストールする - RATはmacOS、Windows、Linuxのすべてを対象とし、C2(Command and Control)サーバー(
sfrclak.com:8000)と通信して第2段階ペイロードを取得する - インストール後に悪性コードと痕跡を削除し、クリーンな
package.jsonに置き換えてフォレンジック検知を回避する
攻撃タイムライン
- 3月30日 05:57 UTC:
plain-crypto-js@4.2.0(正常版)公開 - 3月30日 23:59 UTC:
plain-crypto-js@4.2.1(悪性版)公開、postinstallフックを追加 - 3月31日 00:21 UTC:
axios@1.14.1公開、悪性依存関係を挿入 - 3月31日 01:00 UTC:
axios@0.30.4公開、同じ悪性依存関係を挿入 - 3月31日 03:15 UTC: npmが2つの悪性バージョンを削除
- 3月31日 04:26 UTC: npmが
plain-crypto-jsをセキュリティホルダースタブ(0.0.1-security.0)に置き換え
axios概要
- axiosはJavaScriptエコシステムで最も広く使われているHTTPクライアントで、Node.jsとブラウザの両方で利用される
- 週間ダウンロード数は3億回を超え、たった1回の悪性リリースでも広範な被害の可能性がある
- 一般の開発者は
npm install時に悪性コードのインストールに気付きにくい
攻撃段階
-
第1段階 — メンテナーアカウントの乗っ取り
- 攻撃者は**
jasonsaaymannpmアカウント**を乗っ取り、メールアドレスをifstap@proton.meに変更 - その後、1.x系と0.x系のリリースブランチの両方に悪性ビルドを公開
- 正常なリリースはGitHub ActionsのOIDC Trusted Publisherを通じて公開されるが、
axios@1.14.1は手動公開でgitHeadとOIDC署名がない - 攻撃者は有効期限の長いnpmアクセストークンを利用したとみられる
- 攻撃者は**
-
第2段階 — 悪性依存関係の事前配布
plain-crypto-js@4.2.1はnrwise@proton.meアカウントから公開されたcrypto-jsを偽装し、同一の説明文とリポジトリURLを使用"postinstall": "node setup.js"フックを含み、インストール時に自動実行される- 攻撃後に
package.mdをpackage.jsonへ置き換え、証拠削除の準備を行う
-
第3段階 — axiosへの依存関係挿入
plain-crypto-js@^4.2.1をランタイム依存関係として追加- コード内では一度もimportされない → ファントム依存関係(phantom dependency)
npm install時に自動インストールされ、postinstallスクリプトが実行される
RATドロッパー(setup.js)分析
-
難読化手法
- 文字列を配列
stq[]に暗号化保存し、_trans_1(XOR)と_trans_2(Base64+逆順)で復号 - C2 URLは
http://sfrclak.com:8000/6202033 - 復号された文字列にはOS識別子(
win32、darwin)、ファイルパス、シェルコマンドなどが含まれる
- 文字列を配列
-
プラットフォーム別ペイロード
-
macOS
- AppleScriptを
/tmpに書き出してosascriptで実行 - C2からRATバイナリを取得して
/Library/Caches/com.apple.act.mondに保存・実行 - ファイル名はAppleのシステムデーモンのように偽装されている
- AppleScriptを
-
Windows
- PowerShellのパスを探索した後、
%PROGRAMDATA%\\wt.exeへコピー - VBScript経由でC2からPowerShell RATをダウンロードして実行
- 一時ファイル(
.vbs、.ps1)は実行後に削除される
- PowerShellのパスを探索した後、
-
Linux
curlで/tmp/ld.pyをダウンロードし、nohup python3で実行/tmp/ld.pyファイルが残る- 3つのプラットフォームすべてで
packages.npm.org/product0~2のPOSTボディを使い、正規のnpmトラフィックのように偽装する
-
-
自己削除と隠蔽
setup.jsとpackage.jsonを削除package.mdをpackage.jsonへ置き換え、正常パッケージに偽装- その後は
npm auditや手動レビューでは検知できない - ただし、
node_modules/plain-crypto-js/の存在自体が感染の証拠となる
StepSecurity Harden-Runnerによる実行検証
- Harden-RunnerはGitHub Actionsでネットワーク・プロセス・ファイルイベントをリアルタイム記録する
axios@1.14.1のインストール時に2回のC2接続(curl、nohup)が検知された- 1回目の接続は
npm install開始から2秒後に発生 - 2回目は36秒後で、バックグラウンドプロセスとして継続実行された
- 1回目の接続は
- プロセスツリー分析の結果、
nohupプロセスがPID 1(init) に孤児プロセスとして残り、継続実行していることが確認された - ファイルイベントログでは
package.jsonが2回上書きされた- 1回目: インストール中に悪性版を書き込み
- 2回目: 36秒後、クリーンなスタブに置き換え
侵害指標(IOC)
-
悪性npmパッケージ
- axios@1.14.1 · shasum: 2553649f232204966871cea80a5d0d6adc700ca
- axios@0.30.4 · shasum: d6f3f62fd3b9f5432f5782b62d8cfd5247d5ee71
- plain-crypto-js@4.2.1 · shasum: 07d889e2dadce6f3910dcbc253317d28ca61c766
-
ネットワーク
- C2ドメイン: sfrclak.com
- IP: 142.11.206.73
- URL:
http://sfrclak.com:8000/6202033
-
ファイルパス
- macOS:
/Library/Caches/com.apple.act.mond - Windows:
%PROGRAMDATA%\\wt.exe - Linux:
/tmp/ld.py
- macOS:
-
攻撃者アカウント
jasonsaayman(侵害されたメンテナー)nrwise(攻撃者が作成したアカウント)
-
安全なバージョン
- axios@1.14.0(正常)
影響確認と対応手順
npm list axiosまたはpackage-lock.jsonで1.14.1 / 0.30.4を確認node_modules/plain-crypto-jsの存在有無を確認- OSごとのRATファイルが存在する場合はシステム完全侵害と見なす
- CI/CDログで該当バージョンのインストール履歴を確認し、すべての秘密鍵・トークンの交換が必要
復旧手順
- axiosを安全なバージョン(1.14.0または0.30.3) に固定
plain-crypto-jsフォルダを削除後、npm install --ignore-scriptsで再インストール- RATの痕跡が見つかった場合はシステムを再構築
- すべての認証情報(AWS、SSH、CI/CDなど)をローテーション
- CI/CDパイプラインを点検し、秘密鍵を交換
- 自動ビルド時は
--ignore-scriptsオプションを使用 - C2ドメイン/IPをファイアウォールまたは
/etc/hostsで遮断
StepSecurity Enterprise機能
-
Harden-Runner
- GitHub Actionsでネットワーク送信ホワイトリストを適用
- 異常トラフィックを遮断し、ログを記録
sfrclak.com:8000への接続を事前に遮断可能
-
Dev Machine Guard
- 開発者PCでインストールされたnpmパッケージをリアルタイム監視
axios@1.14.1、0.30.4がインストールされた端末を即時検知
-
npm Package Cooldown Check
- 新規公開パッケージに一時的なインストール禁止期間を適用
plain-crypto-js@4.2.1のような迅速な悪性公開を検知可能
-
Compromised Updates Check
- リアルタイム悪性パッケージDBに基づいてPRマージをブロック
axios@1.14.1、plain-crypto-js@4.2.1を即時登録
-
Package Search
- 組織全体のPRとリポジトリから特定パッケージの導入箇所を検索
- 影響範囲(リポジトリ、チーム、PR)を即時把握
-
AI Package Analyst
- npmレジストリをリアルタイム監視し、振る舞いベースの悪性検知を実施
- 2つの悪性バージョンはいずれも公開後数分以内に検知
-
Threat Center Alert
- 攻撃概要、IOC、対応手順を含む脅威インテリジェンスアラートを提供
- SIEM連携によってリアルタイム可視性を確保
謝辞
- axiosメンテナーとコミュニティはGitHub issue #10604を通じて迅速に対応した
- GitHubは侵害されたアカウントを停止し、npmは悪性バージョンの削除とセキュリティホルダー適用を行った
- メンテナー・GitHub・npmの連携対応により、世界中の開発者被害を最小化した
2件のコメント
この規模のパッケージが侵害されるなんて考えたこともなかったですが、axiosは想像以上ですね。
Hacker Newsの意見
npm、bun、pnpm、uv はいずれも パッケージの最小リリース期間設定 をサポートするようになった
私は
~/.npmrcにignore-scripts=trueを追加しているが、この設定だけでも脆弱性を緩和できたbun と pnpm はデフォルトで lifecycle スクリプトを実行しない
各パッケージマネージャーごとの設定例は次のとおり:
exclude-newer = "7 days"min-release-age=7minimum-release-age=10080minimumReleaseAge = 604800興味深いことに、それぞれ 時間単位が異なる
LLM エージェントを使っている場合、この設定によって失敗が発生する可能性があるため、
AGENTS.mdやCLAUDE.mdに関連する指示を追加する必要があるtimeoutではなくtimeoutMinutesのようにmin-release-age=7 # daysが実際には適用されないかもしれない~/.yarnrc.ymlにnpmMinimalAgeGate: "3d"と設定できるAxios が サプライチェーン攻撃 にさらされたというニュースに衝撃を受けた
Axios 自体には悪意あるコードは含まれていなかったが、
plain-crypto-js@4.2.1という偽の依存関係を注入し、RAT(リモートアクセス型トロイの木馬) をインストールする postinstall スクリプトを実行していたpnpm や bun のように postinstall スクリプトを手動承認する必要があるユーザーにとっては、不幸中の幸いと言える
パッケージマネージャーは 失敗した実験 だという主張
SQLite のように単一の
.cファイルで構成された高品質な C ライブラリもあり、こうした方式なら transitive dependency の問題を避けられる攻撃対象領域の大半はこうした間接依存から生じている
OpenSSL ですらコード品質の問題から 再実装が進められており、JS は標準ライブラリの拡張が難しいため ポリフィルの乱立 が深刻だ
その代わり、npm のようなレジストリ側で 品質基準を強化し、責任あるメンテナーだけを登録できるようにすべき という提案が出た
「今日はどの npm パッケージがやられたんだ?」という自嘲気味のあいさつで一日を始める、という冗談が出た
Linux ユーザーなら bwrap を使って npm、pip、cargo、gradle などあらゆるビルドロジックを サンドボックス化 すべきだという勧め
bwrap は Docker のような隔離環境を提供するが、イメージは不要。Flatpak も同じ技術基盤に基づいている
サーバー配備時には コンテナハードニング が重要で、CI/CD 環境を信頼しない領域として扱うことが核心だ
AI 実行時にも同じサンドボックスを使うとよい
requireするだけでも実行されうるためだ依存関係の問題を何度も見ていると、Rust エコシステムもいつか同じことを経験するのではないかと心配 になる
標準ライブラリを肥大化させるのは難しいが、信頼できるパッケージ品質保証の仕組み は必要だ
AI のおかげでこうした追加作業が可能になり、実際は昔からそうすべきだったという反省もあった
NPM サプライチェーン攻撃への露出を最小限にするための 重要な実践項目
--frozen-lockfileオプションだけでも十分守られるという意見もあった「こうした攻撃を完全に避けるにはどうすればいいのか?」という問いに対し、
Qubes OS に移行 してパスワードマネージャーとビルド環境を完全に分離したいという意見が出た
これはまるで 化学実験室の保護具(PPE) のように、開発環境でも隔離と保護が必要だというたとえが使われていた
pip もすでに virtualenv の外へのインストールを防ぎ始めており、今後はパッケージマネージャーが サンドボックス外での実行を拒否するオプション を提供してほしいという期待もあった
pnpm と bun は現在デフォルトで postinstall スクリプトを無視 するが、npm は依然として実行する
~/.npmrcにignore-scripts=trueを設定するのがよいnpm は今なお 週8,000万ダウンロード を記録している
今回の認証情報流出は LiteLLM の以前のインシデントに由来する可能性が高い と推測されている
Python や Node.js の利用に不安を感じるが、実際には もっと普遍的な問題 だとも思える