supply-chain-hardening について
npm と bun の依存関係を管理するチーム向けのサプライチェーン強化スキルです。リリース後の待機期間、例外時のサンドボックススキャン、インストールスクリプトの無効化を組み合わせ、対策の対象外となるリスクも説明します。
主な機能
- 01npm と bun のリリース待機期間の設定
- 02候補パッケージのサンドボックススキャン
- 03待機期間を省くインストールでライフサイクルスクリプトを無効化
- 04パッケージ内容と既知の脆弱性の確認
- 05ロックファイルと推移的依存関係の制約の説明
活用シーン
- 01新しいマシンでの依存関係インストールの強化
- 02待機期間を省く際のパッケージ確認
- 03postinstall ペイロード実行リスクの低減
- 04ロックファイルと既存依存関係の監査
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ jamditis/ claude-skills-journalism --skill supply-chain-hardeningインストール後、Claude Code で/supply-chain-hardeningを入力して読み込まれたか確認します。
同梱ファイルagents/openai.yaml
詳細
サプライチェーンの強化
ジャーナリズムツールチェーンを、主流の npm/bun サプライチェーン攻撃パターンから守ります。メンテナーアカウントまたは CI パイプラインが侵害され、悪意のあるバージョンが公開され、誰かが気付く前にマシンへインストールされるというパターンです。最近の例として、Mini Shai-Hulud TanStack attack (2026-05-11) では、42 個の @tanstack/* パッケージにわたる 84 個のバージョンが侵害され、postinstall スクリプトを介して AWS / GCP / Vault / GitHub / SSH の認証情報が流出しました。
防御は多層構造で、意図的にシンプルにしています。
- インストール時のクールダウン。公開から N 日未満のパッケージバージョンはインストールしません(デフォルトは 7 日)。これが主要な防御策です。クールダウンが終了する頃には、ほぼ常にセキュリティコミュニティが侵害されたバージョンに警告を出し、レジストリがそのバージョンを取り下げています。
- サンドボックス化されたインストール前スキャン。クールダウンを回避する必要がある場合(CVE パッチ、新しい依存関係、緊急インストール)は、候補の tarball を静的解析スキャンにかけ、サプライチェーンマルウェアの診断シグネチャを調べます。スキャンは
bwrap/firejail/unshare内で実行されるため、悪意のあるパッケージが検査から逃れることはできません。 - インストール時に
--ignore-scriptsを指定。postinstall は最大の攻撃経路です。クールダウンを回避するすべてのインストールで、ライフサイクルスクリプトをスキップします。
この 3 つを組み合わせれば、人の介入がなくても、標準的なノート PC 上で Mini Shai-Hulud TanStack attack を防げていたでしょう。
クールダウンを設定する
検証済みの設定キー(npm v11+ および bun 1.3+):
| パッケージマネージャー | ファイル | キー | 単位 | 除外キー |
|---|---|---|---|---|
| npm | ~/.npmrc(またはプロジェクトの .npmrc) | min-release-age | 日 | まだありません。npm/cli#8994 で提案されています |
| bun | ~/.bunfig.toml(またはプロジェクトの bunfig.toml) | [install] minimumReleaseAge | 秒 | [install] minimumReleaseAgeExcludes = [](正確な名前のみ。glob は不可) |
最小限の設定:
# ~/.npmrc
min-release-age=7
# ~/.bunfig.toml
[install]
minimumReleaseAge = 604800 # 7 days
minimumReleaseAgeExcludes = []
npm 11 以降が必要です。 古い npm は不明なキーを警告なしで無視するため、設定が正しく見えても機能しません。npm --version と npm config get min-release-age で確認してください(null ではなく 7 が表示されるはずです)。
コマンドごとの回避
クールダウンによって、実際に必要なインストールがブロックされた場合:
npm install <pkg>@<version> --min-release-age=0 --ignore-scripts
bun add <pkg>@<version> --minimum-release-age=0 --ignore-scripts
bun add --minimum-release-age=0 CLI フラグは、ドキュメントに記載されていませんが 1.3 以降で機能します。これは bun の bunfig key → kebab-case flag という規則に従っています。
回避オプションには必ず --ignore-scripts を組み合わせてください。 postinstall はサプライチェーンマルウェアで最もよく使われるペイロード実行経路です(Mini Shai-Hulud、event-stream、ua-parser-js、coa はすべてこれを使用しました)。postinstall が正当に必要なネイティブモジュールでは、人が読めるレビューを行った後、スクリプトを手動で実行できます:
(cd node_modules/<pkg> && cat package.json | jq .scripts) # eyeball it
(cd node_modules/<pkg> && npm run postinstall) # run if it checks out
バイパスする前にスキャンする場合
スキャンが必要なのは、危険な場面です。つまり、クールダウンをバイパスすると決めたときに、念のため確認する必要があります。このスキルには、ヒューリスティックを実装した参考スクリプト(scripts/hotpatch.example.sh)が付属しています。お使いのマシンに合わせて調整してください。Bash スクリプトは bwrap(Linux)を前提としています。macOS ユーザーは sandbox-exec に置き換えるか、トレードオフについて文書化したうえでサンドボックス層を省略してください。
スキャンで実施する静的チェック(それぞれ実際の攻撃事例に基づいています):
| チェック | 診断対象 | 重大度 |
|---|---|---|
optionalDependencies / dependencies に github: または git+ の URL が含まれている | Mini Shai-Hulud(github:tanstack/router#<sha> の参照経由でペイロードを配信) | RED |
パッケージのルートにある大きな JS ファイルが、main/module/exports/bin/files から参照されていない | 埋め込みペイロードのパターン(Mini Shai-Hulud の router_init.js) | RED |
| 展開後のサイズが直前の安定版の 3 倍を超える | 大量のペイロードの隠匿 | RED |
fileCount の差が 1~4 で、サイズが 2 倍を超えて増加している | ファイルを 1 つ埋め込んだパターン | RED |
preinstall/install/postinstall/prepare スクリプトが存在する | ライフサイクルスクリプトを利用した攻撃ベクトル(event-stream、ua-parser-js など) | YELLOW |
.ssh/、.aws/、.npmrc、GITHUB_TOKEN、AWS_SECRET、kube 設定を参照する JS ファイル | 認証情報の窃取 | YELLOW |
npm レジストリで deprecated とされ、「security」/「compromised」/「malicious」という文言が含まれているバージョン | メンテナーまたはレジストリによる取り下げ | RED |
OSV.dev が <pkg>@<version> の既知の脆弱性を返す | 公開済み CVE | RED(重大度に応じて) |
サイズ差分の基準からプレリリースバージョンを除外する理由: dev/beta/rc バージョンは安定版とサイズが大きく異なり、誤検知につながるためです。
クールダウンで防げないこと
この設定を行う相手には、制限について正直に伝えてください。
- 新たに悪意のあるバージョンが公開された古いパッケージも、クールダウン期間内であればブロックされますが、その不正なバージョン 自体も クールダウンを通過してしまう場合(まれですが、侵害が 7 日を超えて検知されない可能性があります)、クールダウンだけでは防げません。スキャンでその大半を検出できます。
- トランジティブ依存関係。安全な
<pkg>をインストールしても、侵害されたトランジティブ依存関係が取り込まれることがあります。対策:解決済みの依存関係ツリーをスキャンし(npm audit、osv-scanner)、クールダウンをグローバルに有効にして、トランジティブ依存関係の解決にも適用されるようにします。 - 既存のロックファイルに対する
npm ci。クールダウンは、すでにバージョンが固定されたパッケージのインストール時ではなく、解決時に適用されます。ロックファイルで侵害されたバージョンが固定されている場合、npm ciはそれをインストールします。対策:CI でロックファイルをosv-scanner --lockfile=package-lock.jsonを使ってスキャンします。 node_modulesにすでに存在する侵害されたパッケージ。強化策が保護するのは今後のインストールであり、過去にインストールされたものではありません。既存の依存関係は個別に監査してください(npm audit、osv-scanner、ツリー内で最近公開された依存関係の手動レビュー)。
新しいマシンでのクイックスタートワークフロー
- npm が 11 以上であることを確認します:
npm --version。古い場合はアップグレードします(sudo npm i -g npm@latest、または自己アップグレード時に競合が起きる場合は tarball の入れ替え)。 - 上記の設定で
~/.npmrcと~/.bunfig.tomlを作成します。 - 確認します:
npm config get min-release-ageが7を返すこと。cat ~/.bunfig.tomlで[install]ブロックが表示されること。 scripts/hotpatch.example.shをユーザー所有のツールディレクトリにコピーします。実行可能にします。付属の合成 Mini Shai-Hulud フィクスチャに対して./hotpatch.sh --self-testを実行し、ヒューリスティックが機能することを確認します。- チームのメンバーが見つけられる場所に、バイパスのワークフローを記載します。このスキルは、バイパスがデフォルトではなく、まれで、レビュー済みであることを前提としています。
脅威モデル:防御できるものとできないもの
| 防御できるもの | 防御できないもの |
|---|---|
| メンテナーアカウントの侵害(npm トークンの窃取) | クールダウン期間が過ぎるのを待つように仕組まれた標的型攻撃 |
| CI/CD パイプラインの乗っ取り(Mini Shai-Hulud、有効な OIDC トークン、SLSA 認証済みの悪意あるコード) | ロックファイルですでに固定されている推移的依存関係の侵害 |
タイポスクワッティング(よく似たパッケージ名)への対策。ただし、npm pkg fix の実行とロックファイルの確認を併用した場合 | 自分で作成した開発用依存関係に含まれる悪意あるコード |
postinstall ペイロードの実行(クールダウンと --ignore-scripts の併用による二重の防御) | ランタイムのサプライチェーン攻撃(例:CDN から悪意あるコードを動的に読み込む攻撃) |
新しい推移的依存関係の npm install による無差別なインストール | レジストリ自体の侵害(非常にまれであり、対象外) |
参考資料
- Mini Shai-Hulud に関する StepSecurity の初回分析(TanStack 攻撃、2026-05-11):https://www.stepsecurity.io/blog/mini-shai-hulud-is-back-a-self-spreading-supply-chain-attack-hits-the-npm-ecosystem
- npm の
min-release-age設定:https://docs.npmjs.com/cli/v11/using-npm/config - bun の
minimumReleaseAge設定:https://bun.com/docs/runtime/bunfig - OSV.dev API(無料、認証不要):https://osv.dev/docs/#tag/api
- 以前の Shai-Hulud ワームに関する情報:https://github.com/advisories?query=shai-hulud