サプライチェーンセキュリティ標準
全プロジェクトに適用。ルールは2026-11-11(Shai-Hulud / Mini Shai-Hulud ワーム後)にレビュー済み。
マシンレベルのデフォルト設定(~/.npmrc)
minimum-release-age=1440 # pnpmのみ — 分数(1440 = 24時間)
min-release-age=1 # npm 12+のみ — 日数(1 = 24時間)
2つのパッケージマネージャーは異なるキー名と異なる単位を使用している。 2026-08-21に各ツールのソースを読んで確認済み:pnpmは Date.now() - minimumReleaseAge * 60 * 1e3(分)を計算。npmのmin-release-ageの設定定義には hint: '<days>'と記載されている。両方の行が必要 — どちらか一方では不十分であり、npmキーに 1440 をコピーすると1440 日 となり、事実上すべてのインストールがブロックされる。
npmはインストール時に Unknown user config "minimum-release-age" と出力し、将来のメジャーバージョンで機能しなくなると警告する。これはキーが ~/.npmrc に存在する限り回避不可能:pnpm 11はグローバル設定の書き込みを削除した(pnpm config set --global は現在プロジェクト単位の pnpm-workspace.yaml にリダイレクトする)ため、~/.npmrc がグローバルなpnpmゲートを配置できる唯一の場所である。警告を受け入れ、キーを削除してはならない。
これらに依存しないこと — 実際には無効であることが確認済み
-
block-exotic-subdependencies— npmおよびpnpmのソースのいずれにも存在しない。このキーは一度も機能したことがない。エキゾチックな依存関係はレビューで検出する必要があり、このキーに頼ってはならない。 -
ignore-scripts=true— このスキルは以前、グローバルに設定されていると主張していた。実際には設定されておらず、npm config get ignore-scriptsはfalseを返すため、ライフサイクルスクリプトはインストール時に実行される。2026-08-21に決定:オフのままにし、有効にしてはならない。 postinstall はnpmの主要な侵害ベクトルであるため、これは既知の許容されたギャップであり — 修正すべき見落としではない。これをグローバルに有効にすると、すべてのプロジェクトにわたってネイティブビルド(esbuild、swc、sharp、node-gyp)が壊れ、その障害は原因から遠く離れた場所で発生する。上記の24時間リリースエイジゲートが代わりにこのリスクを負う。特定のプロジェクトでスクリプトの分離が必要になった場合は、そのプロジェクトに限定して対応すること — 決してグローバルには行わない。
このような主張は、このファイルではなくツールに対して確認すること — ここにある3つのエントリはすべて監査時に誤りであった。
サプライチェーン攻撃の分類(監査前に参照)
1. タイポスクワッティング / 依存関係混乱
人気パッケージとほぼ同じ名前のパッケージ、または内部スコープ名と一致する公開パッケージ。2025年だけで454,648の悪意のあるnpmパッケージが公開された。
検出方法: 未知のパッケージに対して npm info <pkg> | grep -E 'created|repository' を実行。内部レジストリ名と照合する。
2. メンテナーアカウント乗っ取り
攻撃者がメンテナーをフィッシングし、postinstallペイロードを含む新しいバージョンを公開する。2025年9月のShai-Huludはchalk、debug、ansi-styles(週間ダウンロード数26億)を攻撃。Axios(週間1億超)は2026年3月に北朝鮮のソーシャルエンジニアリングにより攻撃された。
検出方法: npm diff <pkg>@<last-known-good> <pkg>@latest -- package.json scripts を実行し、パッチバージョンで追加された新しいライフサイクルスクリプトを確認。
3. リポジトリ乗っ取り / 名前空間スカッティング
攻撃者は放棄されたGitHubユーザー名またはnpm名前空間を登録し、リポジトリを再作成して悪意のあるコードを提供する。
検出方法: package.json の repository フィールドを確認。パッケージの最初のnpm公開日以降に作成されたGitHubアカウントにフラグを立てる。
4. CI/CDパイプラインインジェクション(pull_request_target / キャッシュポイズニング)
攻撃者は、特権のある公開ジョブとキャッシュを共有する pull_request_target を使用するリポジトリに対してPRを送信する。pnpmストアを汚染し、次のリリースワークフローがnpm OIDCトークンを漏洩させる。TanStackベクトル(2025年11月、2026年5月のMini Shai-Hulud、300以上のパッケージ、週間ダウンロード数1600万)。
検出方法:
grep -r "pull_request_target" .github/workflows/
grep -r "cache" .github/workflows/ | grep -i "pnpm\|npm\|store"
ハードルール: ワークフローがPRコードをチェックアウトしたり、特権ジョブとキャッシュを共有する場合は、決して pull_request_target を使用しない。
5. Dockerイメージポイズニング
攻撃者はDocker Hubの認証情報を侵害し、既存のイメージタグ(latestを含む)を悪意のあるバイナリで上書きする。Trivy aquasec/trivy のタグ 0.69.4–0.69.6 と latest が2026年3月に汚染された。KICSは2026年4月 — 5つのタグが上書きされ、シークレットを含むTerraform/K8s設定をスキャン。
検出方法: docker inspect <image> --format '{{.Id}}' を設定内の固定されたダイジェストと比較。
ハードルール: すべてのイメージを @sha256: ダイジェストに固定する。セキュリティツールイメージには決して latest を使用しない。
6. GitHub Actionsタグ再設定
攻撃者はアクションメンテナーのトークンを侵害し、既存のバージョンタグを悪意のあるコードを指すように移動する。tj-actions/changed-files CVE-2025-30066(2025年3月、23,000以上のリポジトリ)はすべてのCIシークレットをログにダンプした。2026年5月:人気アクションのタグが偽のコミットにリダイレクトされた。 検出方法:
grep -r "uses:.*@v[0-9]" .github/workflows/ # タグ固定(悪)にフラグ
grep -r "uses:.*@[a-f0-9]\{40\}" .github/workflows/ # SHA固定(正)にフラグ
ハードルール: すべてのサードパーティアクションをバージョンタグではなく、40文字の完全なコミットSHAに固定する。actions/*(ファーストパーティ)はメジャーバージョンタグを使用してもよい。
7. ロックファイル改ざん / 整合性バイパス(PackageGateクラス)
攻撃者はロックファイルを変更して悪意のあるパッケージバージョンを置き換えたり、整合性ハッシュを削除して次のインストールが異なるtarballをサイレントにフェッチするようにする。2026年1月に6つのゼロデイロックファイル脆弱性が文書化された(Koi Security)。 検出方法:
grep -E '"resolved".*git\+|tarball' package-lock.json pnpm-lock.yaml
grep -v "integrity" pnpm-lock.yaml | grep "resolved"
ハードルール: CIは pnpm install --frozen-lockfile または npm ci を使用しなければならない — 決して裸の npm install を使用してはならない。
8. サブ依存関係シャドウイング
攻撃者は3レベル以上の推移的依存関係を標的とする。$ctrl/tinycolor はShai-Huludの伝播ノードであった。
検出方法: npm ls --all 2>/dev/null | grep -E "postinstall|preinstall"。PRには socket scan を使用する。
9. ソーシャルエンジニアリングによるメンテナー権限譲渡
攻撃者は採用担当者やビジネスパートナーを装い、npm公開権限を取得する。UNC1069(北朝鮮)は2026年3月にAxiosメンテナーを標的にし、Socket CEO、Lodash作成者、Fastifyリーダーも標的にした。
検出方法: 重要な依存関係については npm owner ls <pkg> を実行。不審なリリースの前に新しいコラボレーターを監視する。
10. プロテストウェア(意図的なメンテナーによるサボタージュ)
メンテナーが意図的に破壊的なコードを注入する。colors.js v1.4.44–1.4.2(2022年1月、無限ループ)、node-ipc v10.1.1–10.1.3(2022年3月、ロシアIPに対してファイルを削除)。2026年5月に3つの新しい悪意のある node-ipc バージョン。
検出方法:
npm diff <pkg>@<prev> <pkg>@<new> -- lib/
grep -r "networkInterfaces\|geoip\|fs.rmdir\|fs.unlink" node_modules/<pkg>/
node-ipc、colors、faker を既知の正常バージョンに固定する。
11. ワーム型自己複製マルウェア
ペイロードはnpmトークン/PATを盗み、被害者がメンテナーする他のパッケージの悪意のあるバージョンを自律的に公開する。2025年9月のShai-Huludで初めて観測。2026年5月のMini Shai-Hulud(300以上のパッケージ、週間ダウンロード数1600万、npmとPyPIで同時発生)。 IOC検出方法:
find .github/workflows -name "*.js" # ワークフロー内のbundle.js
grep -ri "shai-hulud" . # ワーム文字列
find node_modules -name "data.json" -newer package.json # 流出ステージング
find node_modules -name "cloud.json"
12. 潜伏型 / 環境条件付きペイロード
ペイロードは AWS_SECRET_ACCESS_KEY、GITHUB_TOKEN、または CI=true が存在する場合にのみアクティブになる — サンドボックススキャナーを回避する。
検出方法:
grep -r "process.env.AWS_SECRET\|process.env.GITHUB_TOKEN\|process.env.NPM_TOKEN" node_modules/
正当な理由なくこれらの変数を読み取るパッケージにフラグを立てる。
13. 攻撃ベクトルとしてのセキュリティツール
攻撃者は、CI内でシークレットやインフラ設定への昇格されたアクセス権を持って実行されるため、特にセキュリティスキャンツール(Trivy、KICS、Semgrep)を標的にする。TrivyとKICSは両方とも2026年3月から4月に攻撃された。 ハードルール: すべてのセキュリティツールのDockerイメージをタグではなくダイジェストに固定する。ダイジェストをベンダーのリリースノートと帯域外で検証する。
14. 非レジストリ / CDN依存関係
Git URL、GitHub tarball、カスタムCDN(例:cdn.sheetjs.com)から解決されるパッケージは、レジストリのセキュリティゲートと証明をバイパスし、リリースエイジゲートの対象外でもある — リリースエイジゲートはレジストリバージョンにのみ適用される。一部には整合性ハッシュがまったく欠如している。これらを自動的にブロックするものはなく、レビューで検出する必要がある。
検出方法:
grep -E '"resolved".*github\.com|cdn\.' package-lock.json pnpm-lock.yaml
grep -E '"version":\s*"(git\+|https?:)' package.json
プロジェクト別のnpm/pnpm衛生管理
- ロックファイルをコミットする。CIは
pnpm install --frozen-lockfile(またはnpm ci)を使用しなければならない。CIで裸のnpm installを決して使用してはならない。 package.jsonのpackageManagerを固定して、pnpm/npmのバージョンをロックする。- 侵害された名前空間のパッケージを正確なバージョンに固定する:
@tanstack/*、posthog-node、@mistralai/*、@langchain/mistralai、@ctrl/*、ngx-*、rxnt-*、@zapier/*、@postman/*、@uipath/*、agent-mcp、@semgrep/*、node-ipc、colors、faker。 package.jsonにワイルドカードの"*"バージョンは使用しない。pkg.pr.newURLs は使用しない — これらは一時的なPRプレビュービルドであり、不変のアーティファクトではない。- npm/yarnプロジェクトの場合、ローカルの
.npmrcに同じnpmrcゲートをミラーリングする。 - 新しいプロジェクトにはpnpmを優先する。セキュリティだけを理由に動作中のプロジェクトを移行しない。
GitHub Actionsの堅牢化
ハードルール
- 決して
pull_request_targetを使用しない。ワークフローがPRコードをチェックアウトする場合、PRコードからインストール/ビルド/テストを実行する場合、または特権ワークフローとキャッシュを共有する場合。 pull_request_targetは、チェックアウトなしでPRメタデータ(ラベル、コメント、タイトル)を読み取る場合にのみ許容される。- PRトリガージョブと公開/リリースジョブ間でキャッシュを共有しない。
- CI内の可変ブランチ(
@main、@master)に対してcurl | bashやwget | shを決して使用しない。インストーラスクリプトは常に特定のリリースに固定し、チェックサムを検証する。
workflow_run ガード
workflow_run を使用して親ワークフローの後に特権ジョブをチェーンする場合、if: は以下のすべてをアサートしなければならない:
if: >
github.event_name == 'workflow_dispatch' ||
(github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.head_branch == 'main' &&
github.event.workflow_run.head_repository.full_name == github.repository &&
github.event.workflow_run.event == 'push')
アクションの固定
- すべてのサードパーティアクションを
@v1/@v6ではなく、40文字の完全なコミットSHAに固定する。 - 監査可能性のために人間が読めるタグをコメントとして追加する:
docker/login-action@65d0a9e # v3 - ファーストパーティの
actions/*はメジャーバージョンタグを使用してもよい。 - 現在のSHAを取得する:
gh api repos/<owner>/<action>/git/ref/tags/<tag> - 自動化するには:
npx pin-github-action .github/workflows/*.yml - ジョブごとに
permissions:を最小化する。デフォルトはcontents: read。公開ステップにのみid-token: writeを追加する。
npm公開ワークフロー
- npmアカウントで2FAを要求する:
npm profile enable-2fa auth-and-writes。 - 長期間有効な
NPM_TOKENシークレットの代わりに信頼できる公開(OIDC)を使用する。 --provenance(またはprovenance: true)を追加して、コンシューマーが発信元を検証できるようにする。mainブランチへのタグプッシュによってトリガーされるrelease.ymlからのみ公開する。PRトリガーワークフローから決して公開しない。
Docker / コンテナの衛生管理
- すべての
FROMをダイジェストに固定する:FROM node:22-slim@sha256:<hash> - 本番DockerfileやCIで
latestやタグなしイメージを決して使用しない。 - セキュリティツールイメージ(Trivy、KICS、Semgrep、Snyk、Grype、Hadolint)は最もリスクが高い — これらを最初に固定する。
- 現在のダイジェストを取得する:
docker buildx imagetools inspect node:22-slim --format '{{json .Manifest.Digest}}' - プライベートレジストリイメージの場合:不変タグとダイジェストを使用して公開する。
開発者ツールと設定ファイル
- APIトークンやシークレットを
~/.cursor/mcp.json、~/.claude/settings.json、または類似の設定ファイルに平文で保存しない。環境変数またはキーチェーンを使用する。 - MCPサーバーパッケージを正確なバージョンに固定する(
[email protected]であり、mcp-remote@latestではない)。 - サプライチェーンインシデント後は、
~/.vscode/tasks.jsonと~/.cursor/に予期しない自動実行フックがないか確認する。
検出 / 監視
- ワークフローを持つリポジトリには、CIで zizmor または
snyk-labs/github-actions-scannerをインストールする。 - パッケージを公開するリポジトリ(公開可能なライブラリ)には、socket.dev GitHub Appを追加する。
- npmセキュリティアドバイザリRSSとPyPIマルウェアフィードを購読する。
IOCクイックスキャンチェックリスト
# Shai-Hulud / ワームIOC
grep -ri "shai-hulud" .
find .github/workflows -name "*.js"
find node_modules -name "cloud.json"
# 侵害されたワークフローパターン
grep -r "pull_request_target" .github/workflows/
grep -r "curl.*|.*sh\|wget.*|.*sh\|base64.*eval" .github/workflows/
# 固定されていないアクション
grep -r "uses:.*@v[0-9]" .github/workflows/
# ロックファイルのエキゾチックな依存関係
grep -E '"resolved".*git\+|cdn\.' package-lock.json pnpm-lock.yaml
grep -v integrity pnpm-lock.yaml | grep resolved
# Docker
grep -r "FROM.*:latest\|FROM.*[^@]$" Dockerfile* docker-compose*.yml