はじめに

2026年3月31日、JavaScriptのHTTPクライアントとして広く使われているAxiosのnpm配布物に、悪意ある依存関係が一時的に混入した。

対象は [email protected][email protected] で、公開されていた時間は約3時間と短い。しかし、npm install 時点でマルウェアが動作するタイプだったため、もし該当バージョンを取得していた場合は「端末やCI環境の侵害」として扱う必要がある。

本記事では、何が起きたのか、どういう経緯で混入したのか、今感染していないかを確認するために何をすべきか、今後同様の事故に巻き込まれにくくするには何を行うべきかを整理する。

何が起きたのか

今回の問題は、Axios本体のHTTP通信ロジックに脆弱性が見つかった、という話ではない。

公式ポストモーテムによると、2026年3月31日にメンテナーの侵害されたアカウントを通じて [email protected][email protected] がnpmへ公開され、その2つの版には [email protected] という悪意ある依存関係が追加されていた。

この依存関係は、インストール時に postinstall フックを通じて動作し、macOS・Windows・Linux向けにそれぞれ別のRATを取得して実行する仕組みだったと報告されている。つまり、アプリ実行時ではなく、依存関係を入れた瞬間に侵害が始まる構成だった。

重要なのは、Axiosのソースコード本体が改ざんされたのではなく、配布パッケージの依存関係定義が悪用された点である。ソースレビューだけでは見落としうるタイプの事故であり、ソフトウェアサプライチェーン攻撃として扱うべき事案である。

どういう問題が起きたのか

問題の本質は次の通りである。

  • 悪意ある版のAxiosを npm install すると、依存先の [email protected] も一緒に取得される
  • その依存パッケージに仕込まれた postinstall スクリプトが自動実行される
  • スクリプトが外部サーバー sfrclak[.]com:8000 に接続し、OS別の追加ペイロードを取得する
  • 端末上でRATが起動し、攻撃者による遠隔操作や情報窃取の足掛かりになる
  • 実行後は痕跡を隠すため、自身の設定ファイルを差し替えるなど、見つかりにくくする動きもあった

そのため、影響を受けた環境では「Axiosを安全な版に戻せば終わり」では済まない。すでに認証情報や端末自体が抜かれている前提で対処する必要がある。

どういう経緯で混入したのか

Axios公式の説明では、攻撃者は標的型のソーシャルエンジニアリングとRATを使ってリードメンテナーのPCへ侵入し、その結果得たnpm公開権限を用いて悪意ある版を公開したとされている。

時系列としては、概ね次の流れである。

  1. 2026年3月中旬ごろから、メンテナーに対する標的型のソーシャルエンジニアリングが始まる
  2. 2026年3月30日、攻撃用の依存パッケージ plain-crypto-js がnpmに用意される
  3. 2026年3月31日 00:21 UTC に [email protected] が公開される
  4. 同日 01:00 UTC ごろに [email protected] も同様の内容で公開される
  5. 外部研究者やコミュニティが異常に気づき、報告と対応が進む
  6. 同日 03:15 UTC に悪意あるAxios版が削除される
  7. 同日 03:29 UTC に plain-crypto-js も削除される

ここで押さえておきたいのは、通常のリリースフローに沿った正常な更新に見せかけて、配布物だけが汚染された点である。利用者側から見ると「いつもの依存更新」にしか見えないため、ロックファイルやCI運用が甘いとかなり踏みやすい。

今感染していないか確認するために行うこと

1. ロックファイルで該当バージョンを確認する

まずは package-lock.jsonyarn.lock などに、問題の版が含まれていないか確認する。

grep -E 'axios@(1\.14\.1|0\.30\.4)|plain-crypto-js' package-lock.json yarn.lock 2>/dev/null

npm系の依存関係で確認するなら、次のような見方も有効である。

npm ls axios
npm ls plain-crypto-js

もし [email protected][email protected]plain-crypto-js のいずれかが出てくるなら、影響調査対象として扱う。

2. インストールした時刻を確認する

公式には、問題の版が配布されていた時間帯は2026年3月31日 00:21 UTC から 03:15 UTC 前後までとされている。日本時間では2026年3月31日 09:21 から 12:15ごろである。

この時間帯に、ローカル環境やCIで npm installnpm update、依存更新ジョブが走っていなかったかを確認する。ロックファイルが安全な版で固定されていたなら影響は受けにくいが、固定していない自動更新ジョブは特に危ない。

3. 端末やCIに痕跡がないか確認する

公開情報ベースでは、主に次のIOCが挙がっている。

  • ネットワーク接続先: sfrclak[.]com または 142.11.206.73:8000
  • macOS: /Library/Caches/com.apple.act.mond
  • Windows: %PROGRAMDATA%\\wt.exe
  • Linux: /tmp/ld.py

端末のプロセス、EDR、FW、Proxy、DNSログ、CIランナーの通信ログにこれらの痕跡がないかを見る。

4. 該当したら「端末侵害」として扱う

Axios公式は、該当したマシンを侵害済みとして扱うよう案内している。つまり、単に依存関係を消すだけでなく、少なくとも以下を実施するべきである。

  • 安全な版へ戻す
  • node_modules/plain-crypto-js/ を除去する
  • その端末で使ったシークレット、トークン、認証情報をローテーションする
  • CIランナーなら、そのジョブに注入した環境変数やクラウド認証情報も全交換する
  • 必要に応じて端末の再イメージ化やクリーンビルドを行う

RAT系は「入ったかもしれない」で終わらせると後で被害が広がる。曖昧な場合でも、保守的に侵害前提で動くほうが安全である。

今後感染しないように行うこと

ロックファイルを必ずコミットし、CIでは npm ci を優先する

今回のような事故では、ロックファイルが古い安全版を固定していれば踏まない可能性が高い。開発端末でもCIでも、npm install を漫然と叩くより、ロックファイルに従う npm ci を基本にしたほうがよい。

依存更新を自動実行する時間帯と対象を見直す

夜間バッチや定期ビルドで自動的に npm install を回している構成は、汚染版を取り込みやすい。依存更新は、PRベースで差分確認できる形に寄せるほうが安全である。

パッケージ追加時に「新しい依存」が増えていないか確認する

今回の混入は、Axios本体ではなく依存の増加が入口だった。メジャー更新でなくても、依存パッケージが急に増えていないか、インストールフックが付いていないかを確認する習慣が有効である。

インストールフックを監視する

postinstall は便利だが、攻撃面でもある。組織としては、依存関係スキャン、SBOM、Allowlist/Blocklist、インストールスクリプト監視などを組み合わせ、未知の postinstall 実行を検知できるようにしたい。

.npmrc でインストール時のリスクを下げる

今回のように postinstall が悪用される事案では、.npmrc の設定で被害の起点を減らせる。特にCIや本番ビルド環境では、次のような設定を検討しやすい。

ignore-scripts=true
fund=false
audit=true
save-exact=true

この中で特に重要なのは ignore-scripts=true である。これを有効にすると postinstallpreinstallprepare などのライフサイクルスクリプトが自動実行されなくなるため、今回のような「インストールした瞬間に発火する」攻撃への耐性が上がる。

ただし、副作用もある。ネイティブモジュールのビルドや、正当なセットアップ処理まで止まるため、すべての開発環境で常時有効にできるとは限らない。そのため、まずはCI、依存更新ジョブ、検証用ランナーなど、不要なスクリプト実行を止めやすい場所から適用するのが現実的である。

例えば、CI専用の .npmrc では次のような方針が取りやすい。

  • CIでは ignore-scripts=true を基本にする
  • どうしても必要なジョブだけ、明示的に npm rebuild や許可済みコマンドで後段実行する
  • npm ci と組み合わせて、ロックファイルに固定された依存だけを再現する

また、save-exact=true は新規導入時に曖昧なバージョン範囲を避けやすくし、意図しない版の取り込みを減らす助けになる。これだけでサプライチェーン攻撃を防げるわけではないが、「いつの間にか別版を拾う」事故を抑えやすい。

.npmrc は万能な防御ではないが、ロックファイル運用や npm ci と合わせることで、少なくとも「インストールフックが無条件で走る」状態を減らせる。今回のような事案では、かなり実務的な防御策になる。

開発端末と公開権限の分離を進める

Axios側も再発防止策として、個人端末依存の公開から、OIDCやimmutableなリリースフローへ寄せると説明している。これは利用側にも参考になる。個人端末に強い権限を集中させず、公開・署名・配布の経路を自動化して分離したほうがよい。

シークレットを長寿命にしない

もし開発端末やCIが侵害されても、短命トークンや最小権限設計になっていれば被害は縮む。クラウド鍵、npm token、GitHub token、各種APIキーは、定期ローテーションと最小権限を前提に運用したい。

まとめ

今回のAxios事案は、公開経路と依存関係を悪用したサプライチェーン攻撃だった。

影響があるのは主に [email protected][email protected] を取得した環境であり、該当する場合は「依存を戻す」だけでは不十分である。端末侵害、認証情報流出、CIシークレット漏えいまで含めて確認する必要がある。

まずはロックファイル、インストール時刻、IOC、CIの実行履歴を確認し、怪しい場合は保守的に隔離と資格情報ローテーションを進めるのがよい。今後に向けては、ロックファイルの厳格運用、npm ci の利用、インストールフック監視、公開権限の分離が実践的な防御になる。

参考情報

コピペ用Skill

以下は、Codexなどでそのまま SKILL.md として使える、npmサプライチェーン対策用のSkill例である。
Node.js系プロジェクトで、依存追加、依存更新、Dockerビルド、CI設定変更を扱うときの安全側の手順をまとめてある。

日本語版

# npmサプライチェーン対策Skill

## 目的
- npm依存の追加、更新、ビルド設定変更時に、サプライチェーン事故を踏みにくい手順で作業する
- ロックファイルと再現性を重視し、インストールスクリプトの自動実行リスクを下げる
- 侵害疑いがある場合に、単なる依存更新ではなく端末侵害前提で切り分ける

## 基本方針
- `package-lock.json` を必ず確認し、未コミット変更がある場合は勝手に上書きしない
- 依存の再現には `npm ci` を優先する
- CIやDockerビルドでは、必要性が明確でない限り `npm ci --ignore-scripts` を優先する
- `npm install` は、新規依存追加や明示的な更新が必要な場合に限定する
- 依存更新時は、追加されたパッケージ数、ライフサイクルスクリプト、公開元を確認する
- lockfileだけの変化でも、内容を読まずに安全とみなさない

## 作業開始時の確認
1. `package.json``package-lock.json``.npmrc``Dockerfile`、CI設定を確認する
2. `npm` scripts と `postinstall``prepare``preinstall` の有無を確認する
3. 変更対象パッケージの現在バージョンと、更新理由を確認する
4. 自動更新ジョブや Renovate、Dependabot の影響範囲を確認する

## 依存追加・更新時のルール
- バージョンは曖昧範囲より固定を優先し、必要に応じて `.npmrc``save-exact=true` を使う
- 依存追加後は `package-lock.json` の差分を読み、新しい依存が増えていないか確認する
- 新しく入るパッケージに `postinstall``preinstall``prepare` がないか確認する
- Git URL依存、未知の公開元、急に増えたトランジティブ依存は要注意として扱う
- ユーザーの明示依頼がない限り、大量の依存更新はまとめて行わない

## DockerとCIでのルール
- Dockerfileでは `package.json` だけでなく `package-lock.json` も先にコピーする
- Dockerビルド時の依存インストールは、可能なら `npm ci --ignore-scripts` を使う
- CIでも `npm install` より `npm ci` を優先する
- `.npmrc` がある場合は、`audit=true``save-exact=true` などの設定を確認する
- インストールスクリプトを有効にする必要がある場合は、その理由と影響を先に説明する

## レビュー観点
- ロックファイルが存在するのに `npm install` を常用していないか
- `package-lock.json` がコミット対象から漏れていないか
- 依存追加に対して説明のない新規パッケージが増えていないか
- DockerfileやCIで無条件にインストールスクリプトが走る構成になっていないか
- 秘密情報を扱うCIジョブで、不要な依存更新やインストールをしていないか

## 侵害疑い時の初動
- 該当バージョンを取得していた可能性がある場合、単なる更新ではなく侵害前提で扱う
- 当該端末やCIジョブで使用したトークン、APIキー、クラウド認証情報を洗い出す
- 必要に応じて認証情報をローテーションし、端末隔離やクリーン再構築を提案する
- IOC確認、インストール時刻確認、CI実行履歴確認を優先する

## 出力ルール
- 変更時は、再現性、スクリプト実行有無、ロックファイル影響を必ず説明する
- `package-lock.json` を更新した場合は、その理由を明記する
- `--ignore-scripts` を採用しない場合は、なぜ不要または不適切かを説明する
- 不確実な点は推測で断定せず、確認すべきファイルやコマンドを示す

## 推奨コマンド例
```bash
npm ci
npm ci --ignore-scripts
npm audit
rg -n "postinstall|preinstall|prepare" package.json package-lock.json node_modules
```

英語版

# npm Supply Chain Defense Skill

## Goal
- Handle npm dependency additions, updates, and build configuration changes with supply chain safety in mind
- Prioritize lockfile-based reproducibility and reduce the risk of auto-running install scripts
- Treat suspicious cases as possible host compromise instead of a simple dependency update issue

## Core Policy
- Always inspect `package-lock.json` and do not overwrite uncommitted changes without explicit approval
- Prefer `npm ci` for reproducible installs
- In CI and Docker builds, prefer `npm ci --ignore-scripts` unless there is a clear reason not to
- Use `npm install` only when adding a new dependency or performing an explicit update
- When dependencies change, review added packages, lifecycle scripts, and package sources
- Do not assume a lockfile-only change is safe without reading the diff

## Initial Checks
1. Review `package.json`, `package-lock.json`, `.npmrc`, `Dockerfile`, and CI settings
2. Check whether `postinstall`, `prepare`, or `preinstall` exist in npm scripts
3. Confirm the current version of the target package and the reason for the change
4. Check whether Renovate, Dependabot, or scheduled update jobs are involved

## Rules For Dependency Additions And Updates
- Prefer exact versions over broad ranges and use `save-exact=true` in `.npmrc` when appropriate
- After adding a dependency, inspect the `package-lock.json` diff for unexpected new packages
- Check whether newly introduced packages use `postinstall`, `preinstall`, or `prepare`
- Treat git URL dependencies, unknown publishers, and sudden transitive dependency growth as suspicious
- Do not bundle large dependency updates unless the user explicitly asks for them

## Rules For Docker And CI
- In Dockerfiles, copy `package-lock.json` along with `package.json` before install steps
- Prefer `npm ci --ignore-scripts` for dependency installation during Docker builds when possible
- Prefer `npm ci` over `npm install` in CI
- If `.npmrc` exists, review settings such as `audit=true` and `save-exact=true`
- If install scripts must be enabled, explain why and describe the impact before changing behavior

## Review Checklist
- Check whether the project is using `npm install` routinely even though a lockfile exists
- Check whether `package-lock.json` is missing from the committed change set
- Check whether unexplained new packages were added as part of a dependency change
- Check whether Dockerfiles or CI run install scripts automatically without review
- Check whether secret-bearing CI jobs are performing unnecessary dependency updates or installs

## First Response For Suspected Compromise
- If the affected version may have been installed, treat the case as a possible compromise rather than a normal update task
- Identify tokens, API keys, and cloud credentials used on the affected machine or CI job
- Recommend credential rotation, host isolation, or clean rebuilds when needed
- Prioritize IOC review, install-time verification, and CI execution history checks

## Output Rules
- When making changes, always explain reproducibility, script execution behavior, and lockfile impact
- If `package-lock.json` changes, state why it changed
- If `--ignore-scripts` is not adopted, explain why it is unnecessary or inappropriate
- Do not state uncertain conclusions as facts; point to the files and commands that should be checked

## Recommended Commands
```bash
npm ci
npm ci --ignore-scripts
npm audit
rg -n "postinstall|preinstall|prepare" package.json package-lock.json node_modules
```

前後の記事

関連記事

技術(バックエンド) 2026/4/14

フレームワークや言語のアップデートを行うことで設計やロジックの勉強になる

簡単とみなされがちかつ業務として避けられがちなフレームワークや言語のアップデートを行うことで結構設計やロジックの勉強になるということ。

技術 2026/4/11

Webサイト運用で押さえたいレスポンス設計とクローラー対策

Webサイトを運用するときに見落としやすいHTTPレスポンスの扱いと、検索エンジン向けクローラー対策の基本を整理する。

技術(バックエンド) 2026/4/6

PHP 8系の新機能を整理する。trait・enum・パイプ演算子は何が違うのか

PHP 8系で注目したい機能を、PHP 7系以下との違いがわかる具体的なコード付きで整理する。traitの位置づけ、enum、match、Attributes、そしてPHP 8.5で追加されたパイプ演算子までまとめて紹介。