Skip to content

Instantly share code, notes, and snippets.

@kobitoDevelopment
Created April 1, 2026 06:49
Show Gist options
  • Select an option

  • Save kobitoDevelopment/2bebaa4eb285249f62ba1bde95a9e380 to your computer and use it in GitHub Desktop.

Select an option

Save kobitoDevelopment/2bebaa4eb285249f62ba1bde95a9e380 to your computer and use it in GitHub Desktop.

npm サプライチェーン攻撃対策

前提:MFA

npm アカウントおよび GitHub アカウントの両方で多要素認証を有効化する。


1. 意図しないバージョンの混入防止

1-1. ロックファイルの固定

ロックファイル(package-lock.json / pnpm-lock.yaml)を Git にコミットし、CI では frozen install を使用する。

パッケージマネージャ コマンド / 挙動
npm npm ci(ロックファイルの内容を厳密に再現する)
pnpm CI 環境を検出すると --frozen-lockfile が自動付与される

効果:npm install / pnpm install が semver 範囲内で最新版を解決する動作を抑止し、ロックファイルに記録されたバージョンのみをインストールする。

1-2. 公開直後のバージョンの除外

Renovate の minimumReleaseAge プリセットを設定する。

{
  "extends": ["security:minimumReleaseAgeNpm"]
}

npm パッケージの公開から 3 日間は更新 PR を生成しない。悪意あるバージョンが公開後に発覚・取り下げされるまでの時間的余裕を確保する。

ロックファイル固定は install 時の解決を制御し、minimumReleaseAge はロックファイル更新 PR の生成タイミングを制御する。対象フェーズが異なるため併用する。


2. 混入時の被害の局所化

2-1. install 時スクリプトの無効化

npm は preinstall / postinstall 等のライフサイクルスクリプトをインストール時に実行する。これを無効化すると、悪意あるパッケージが混入した場合でも任意コード実行を防止できる。

プロジェクトルートの .npmrc に追加:

ignore-scripts=true

影響範囲:主要なパッケージ(sharp, esbuild, swc, rollup, lightningcss 等)はプラットフォーム別プリビルドバイナリを optionalDependencies で配布する方式に移行済みであり、postinstall を使用しないため ignore-scripts=true の影響を受けない。

node-gyp によるビルドが必要なパッケージ(bcrypt 等)は影響を受ける。純粋な JS 実装の代替(bcryptbcryptjs)に置き換え可能な場合はそちらを採用する。

どうしても postinstall が必要なパッケージが残る場合、pnpm では package.json に許可リストを記述できる:

{
  "pnpm": {
    "onlyBuiltDependencies": ["some-native-package"]
  }
}

npm にはこの許可リスト機構がないため、ignore-scripts=true を維持したうえで対象パッケージのみ npm rebuild <package> を手動実行する形になる。

2-2. シークレットのファイル非保存

.env 等のファイルにクラウドアクセスキーを記載しない。1Password CLI や Bitwarden CLI を使用し、プロセス起動時に環境変数として注入する。

# 1Password CLI の例
op run --env-file=.env.tpl -- npm start

効果:ファイルシステム経由のシークレット窃取を不可能にする。

注意:ここでの脅威は .env の Git コミットではなく、.gitignore に含まれていてもディスク上にファイルとして存在すること自体である。postinstall 等で実行された悪意あるコードはユーザー権限でファイルシステムを読めるため、ローカルの .env は読み取り可能になる。ランタイム注入方式ではシークレットがファイルとして存在しないため、この経路での窃取が成立しない。


3. CI/CD パイプラインの保護

3-1. GitHub Actions のコミットハッシュ固定

タグ指定(@v5 等)はタグの参照先コミットを第三者が変更できるため、意図しないコードが実行される可能性がある。pinact を使用し、ワークフローファイル内のアクション指定をコミットハッシュに変換する。

go install github.com/suzuki-shunsuke/pinact/cmd/pinact@latest
pinact run

変換前:

uses: actions/checkout@v5

変換後:

uses: actions/checkout@<full-commit-hash> # v5

3-2. GitHub リポジトリ設定によるハッシュ指定の強制

GitHub のリポジトリ設定で、コミットハッシュ指定以外の Actions 実行を禁止する。pinact による変換漏れがあった場合にワークフロー実行自体が失敗するため、二重の防御になる。


チェックリスト

  • npm / GitHub アカウントの MFA 有効化
  • ロックファイルの Git コミット
  • CI での npm ci または frozen install の使用
  • Renovate minimumReleaseAge の設定
  • .npmrc への ignore-scripts=true 追加
  • シークレットのランタイム注入化(.env へのキー直接記載の廃止)
  • GitHub Actions アクションのコミットハッシュ固定(pinact)
  • GitHub リポジトリ設定でのハッシュ指定強制
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment