2026年3月31日、JavaScriptエコシステムで広く使われているHTTPクライアントであるnpmパッケージ axiosがサプライチェーン攻撃の標的になりました。攻撃者はaxiosメンテナーのnpmアカウントを乗っ取り、通常のCI/CDパイプラインを迂回して、2つの悪意あるバージョン(1.14.1と0.30.4)をnpmレジストリに直接公開しました。インストールすると悪意あるスクリプトが実行されます。
「うちはaxiosがXバージョンだから大丈夫」という話ではありません!axios自体の脆弱性ではなく、乗っ取られたバージョンをインストールすると悪意あるスクリプトが実行される、という話です。ローカルでの npm install も、デプロイ時のビルドも同様です。
ソフトウェアサプライチェーンセキュリティ企業 StepSecurityによる詳細な分析:
Yarnもnpmレジストリと同じパッケージデータを参照するため、Yarnユーザーも同様に影響を受けます。
先日のPythonパッケージLiteLLMに対するサプライチェーン攻撃も踏まえ、重要だと感じたポイントが3つあります。
-
package-lock.jsonといったロックファイルの仕組みの理解 - パッケージの更新前に変更内容の確認
- npmエコシステムの
^というバージョン範囲記法がある(私は今日まで知りませんでした)
ロックファイル無しでパッケージをインストールしたらどうなる
package.json はマニフェストファイルであり、「これらのパッケージをこのようなバージョン範囲で必要とする」と宣言するだけです。正確なバージョンを固定するものでもなく、推移的依存関係(依存パッケージがさらに依存するパッケージ)も記述しません。
ロックファイルが存在しない状態で npm install を実行すると、npmは package.json の要件に適合するすべてのパッケージと推移的依存関係のバージョンを解決します。このとき、侵害されたバージョンが解決されると脆弱な状態になります。
npmがすべての依存関係を解決しインストールすると、package-lock.json が生成されます。このロックファイルは、推移的依存関係を含むすべてのパッケージの正確なバージョンを固定します。
ロックファイルがあっても、明示的なバージョン更新は自己責任
ロックファイルが存在する状態での npm install は固定されたバージョンに従います。
ただし、バージョンを明示的に変更する場合、ロックファイルは保護になりません。npm update や npm install ...@latest を実行すると、新しいバージョンが解決し、インストールされ、ロックファイルも更新されます。実際にアップグレードを行う前に --dry-run フラグで変更内容を確認できます。これはセキュリティに限った話ではなく、すべての直接と推移的依存関係への影響を事前に把握しておくことは一般的に良い習慣だと思います。
package.jsonにたくさんある^について
依存関係に "axios": "^1.2.3" のように記述されていることがよくあります。その ^ を無視してはいけません。npmエコシステムにおいて ^ は後方互換性のあるアップグレードを許容するバージョン範囲を意味します。つまり、^1.2.3 自体は今回の悪意あるバージョンを排除しません。
セマンティックバージョニング は MAJOR.MINOR.PATCH の形式です。
- MAJORの増加は破壊的変更を意味します
- MINORの増加は後方互換性のある機能追加を意味します
- PATCHの増加は後方互換性のあるバグ修正を意味します
セマンティックバージョニング自体は一般的ですが、^記法はnpmエコシステム特有のものです。私はJavaScript開発者ではありません。Vue.jsのプロジェクトに携わったことはありますが、^ の存在に気づいていませんでした。
もう一つ、やや複雑な記法として ~があります。後続の表記によって意味が変わります。詳細はこちら:
バージョン範囲の完全な仕様については、npm semverの公式ドキュメントを参照してください: