safeinstall について
SafeInstallは、npmとpnpm向けのローカル優先のインストールポリシーゲートです。パッケージを導入する開発者やAIエージェントを対象に、インストール前にポリシーと成果物の紐付けを検証し、エージェント設定ファイルも監視できます。
主な機能
- 01npm・pnpmのインストール前にポリシーを確認
- 02ロックファイルのバージョンと成果物ハッシュを検証
- 03公開直後のリリースやライフサイクルスクリプトのリスクを遮断
- 04オプションのタイプスクワット・来歴チェック
- 05エージェントのインストールコマンドをガード
- 06エージェント設定の変更を追跡
活用シーン
- 01AIエージェントによるパッケージ導入の制御
- 02ローカルポリシーに基づく直接依存関係の確認
- 03パッケージの来歴と信頼する公開元の照合
- 04コミット済みエージェント設定の差異検出
MCP 対応
エージェントがSafeInstallのポリシーを照会するためのMCPツールを提供します。また、Claude Code、Codex、Cursorでインストールコマンドを実行前に捕捉するシェルガードも備えています。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
SafeInstall
AI エージェント時代のサプライチェーンセキュリティ。
npm と pnpm 向けの、アーティファクトに基づくインストールゲートです。install と入力する人、その代わりに実行する AI エージェント、そしてエージェントを動かす設定を対象としています。
まずポリシーを実行し、その後にパッケージマネージャーを実行します。順序を逆にしてはいけません。
ローカルファースト · クラウド不要 · アカウント不要 · MIT · 永久無料
できること
SafeInstall はパッケージマネージャーより先にポリシーを実行します。ローカルで、デフォルトではインストールをブロックします。1 つのツールで 3 層の防御を実現します。
- 🧑💻 自分でインストールする人向け — サポート対象のインストールコマンドの前に、
safeinstall pnpm add axiosのように付けて実行します。まずポリシーを実行し、解決済みのロックファイルを承認済みのバージョンと SHA-512 に照合してから、フローズンインストールを実行します。リリースからの経過日数、インストールスクリプト、信頼できないソース、タイポスクワッティング、暗号学的な来歴をポリシーチェックで確認します。 - 🤖 代わりにインストールする AI エージェント向け — エージェントが呼び出せるMCP ツールに加えて、Claude Code、Codex、Cursor でインストールコマンドを実行前にインターセプトするシェルガードを提供します。シェルのインターセプトはベストエフォートです。エージェントが協力しない場合でも作動する防御層の 1 つであり、確実にすべてを捕捉できる保証ではありません。
- 🔒 エージェントを動かすファイル向け — Agent Trust Surface は、設定、フック、ルール、MCP ファイルのハッシュベースラインをコミットし、ローカルで照合して CI で再検証します。ルールの改ざんを、将来のすべてのセッションを気付かれずに乗っ取るのではなく、ドリフトとして検出できます。ただし、完全に整合性のある書き換えは自動チェックだけでは検出できないため、差分を人が確認する必要があります。
SafeInstall を選ぶ理由
AI コーディングツールは、数秒でパッケージを提案します。公開日を確認しません。インストールスクリプトを読みません。ソースも検証しません。「はい」と入力して先に進むだけです。
SafeInstall は、提案と実行の間に置くゲートです。
$ safeinstall pnpm add [email protected]
Install blocked.
- [email protected]
Blocked: release too new (published 3 hours ago; minimum is 72 hours).
Blocked: install script present (has postinstall).
ダッシュボードもアカウントもクラウドも不要です。コマンドの前に 1 つ付けるだけで、ローカルでポリシーを実行し、デフォルトでブロックしてから、本来のツールを呼び出します。
メンテナー侵害攻撃を阻止する
Sigstore の署名が有効であるだけでは不十分です。npm メンテナーのアカウントを侵害した攻撃者は、すでに信頼しているパッケージの悪意あるバージョンを公開できます。その悪意あるバージョンのアテステーションも、実際のリポジトリをフォークした中で攻撃者が制御する GitHub Actions ワークフローによって署名されているため、暗号学的な検証に成功します。
SafeInstall はこれを検知します。provenance.trustedPublishers で期待するソースリポジトリを固定すれば、それ以外の場所からビルドされたものは、署名が有効であってもすべてブロックされます。
$ safeinstall check
Using config: ./safeinstall.config.json
Check blocked.
- [email protected]
Blocked: publisher mismatch for axios (expected axios/axios, got evil-org/axios).
Suggestion: Verify the package source. Update provenance.trustedPublishers only if the change is intentional.
これは、インストール時のポリシーゲートでこの種のチェックを行う唯一のものです。CVE スキャナーは既知の脆弱性を探します。コンテンツアナライザーは不審なコードを探します。SafeInstall は、暗号学的な信頼の連鎖が、信頼すると合意したリポジトリを指していることを検証し、どれほど正規に見えても、それ以外はすべて拒否します。
SafeInstall 自体も Sigstore アテステーション付きで公開されています。自らのツールで検証できます。来歴検証を有効にし、safeinstall-cli を Mickdownunder/SafeInstall に固定すれば、SafeInstall が公開 Sigstore 透明性ログを照合して自身の信頼の連鎖を検証する様子を確認できます。
$ safeinstall check
Using config: ./safeinstall.config.json
Info: safeinstall-cli: provenance verified from Mickdownunder/SafeInstall via .github/workflows/release.yml.
Check passed: no direct dependency policy violations found.
インストール
npm install -g safeinstall-cli
Node.js >=20 · macOS、Linux、Windows · コマンド:
safeinstall
クイックスタート
safeinstall init # config + agent guard hooks + trust lock, in one command
safeinstall pnpm add axios # policy runs, then pnpm
safeinstall npm install # lockfile-aware project install
safeinstall check # audit direct deps against policy
仕組み
Resolve → Policy → Lockfile-only preparation → Verify artifact binding → Frozen install
Any failed policy or binding check → Exit 2 (blocked)
- 要求されたバージョンを解決し、レジストリの tarball URL と SHA-512 を取得します
- レジストリのメタデータ(公開日時、宣言されたスクリプト)を取得します
- ポリシールールを評価します
- パッケージを明示的に追加する場合、評価済みのバージョンを固定し、スクリプトを無効にしたロックファイルのみの準備を実行します
- 影響を受けるロックファイルの範囲内にある、レジストリからのすべての直接依存関係について、記録されている場合は評価済みのバージョン、SHA-512、tarball URL と照合します。設定された推移的依存関係のチェックも適用します
- スクリプトを無効にし、設定されたレジストリを強制した状態で
npm ciまたはpnpm install --frozen-lockfileを実行します。評価中またはインストール中にマニフェスト/ロックファイルが変更された場合は拒否します
レジストリプロキシはありません。tarball の書き換えもありません。クラウドへの依存もありません。
ポリシーのデフォルト設定
| ルール | デフォルト | ブロック時のメッセージ |
|---|---|---|
| リリース経過時間 | 最低72時間 | Blocked: release too new |
| ライフサイクルスクリプト | preinstall、install、postinstall をブロック | Blocked: install script present |
| ソースの種類 | registry、workspace、file、directory を許可 | Blocked: untrusted source |
| 信頼レベルの低下 | 更新時に registry→git/url への変更、または新たなスクリプトを検知 | Blocked: trust level dropped |
| タイポスクワッティングの検知 | デフォルトではオフ。typoSquat.mode で有効化 | Blocked: suspected typo-squat |
| 来歴の検証 | デフォルトではオフ。provenance.mode で有効化 | Blocked: attestation missing/invalid/publisher mismatch |
| 推移的依存関係 | デフォルトではオフ。transitive.mode で有効化 | Blocked: transitive install script / untrusted source |
| 来歴の継続性 | デフォルトではオフ。continuity.mode で有効化 | Blocked: provenance downgrade / identity discontinuity |
すべてのルールは設定可能です。曖昧または不完全なメタデータは許可せず、ブロックします。
プロベナンスの継続性 — npm の標準設定では検出できない問題を捕捉
これは SafeInstall の最も特徴的なチェックであり、他のコンシューマー側ツールにはない機能です。npm は公開時にプロベナンスを検証し、パッケージをソースリポジトリに紐付けますが、バージョン間の継続性は強制しません。侵害されたメンテナーアカウントから、アテステーションなし(盗まれたトークンを使用)、または別のリポジトリから新しいバージョンが公開されても、npm は警告しません。これは、2026 年の攻撃の波(Mastra、休眠アカウントからの再公開)に見られる特徴です。
継続性チェックでは、最近のバージョンのプロベナンス ID からパッケージごとの信頼ベースラインを学習し、逸脱をブロックします。
provenance-downgrade— 最近のバージョンにはアテステーションがあるのに、このバージョンにはありません。個人用トークンを使ったアカウント侵害による公開の典型的な指紋です。(これは Mastra の事例です。)identity-discontinuity— このバージョンのアテステーションは、確立されたベースラインとは異なるソースリポジトリからのものです。
ベースラインはパッケージごとに学習されるため、プロベナンスを採用していない大多数のパッケージで誤検知は発生しません。そうしたパッケージにはベースラインがなく、チェックは何も報告しません。「プロベナンスを必須にする」という強引な一律設定はありません。
npm が公開しているアテステーションメタデータを読み取るため、オプションの sigstore パッケージがなくても動作します。continuity.mode を "warn" または "block" に設定して有効にしてください。
正直なところ、限界もあります: 継続性チェックでは、正規のリポジトリからの有効なプロベナンスを伴う、正当に侵害された CI ワークフローを経由する攻撃(例:Shai-Hulud ワームの類)は検出できません。この場合、検出対象となる ID の不連続性がないためです。SafeInstall は、2026 年に主流となった攻撃パターンへの防御を強化しますが、すべての侵入口を塞ぐものではありません。
推移的依存関係
デフォルトでは、SafeInstall は直接の依存関係を評価します。しかし、サプライチェーン攻撃の多くは、推移的な依存関係、つまり自分では選んでいない、何階層も下で取り込まれるパッケージを通じて発生します。transitive モードを有効にすると、ロックファイルのツリー全体をたどります。
次の 2 つのチェックは、どちらもロックファイルから直接読み取るため、レジストリへの追加呼び出しはゼロで推移的に実行されます。
install-script— ライフサイクルスクリプトを宣言している推移的パッケージにフラグを立てます(ua-parser-js型の攻撃:深くネストした依存関係がインストール時にコードを実行します)。npm はこれをロックファイルに記録しますが、pnpm のロックファイルには記録されないため、現時点では npm 専用のチェックです。untrusted-source— レジストリではなく、git、url、または tarball のソースから解決される推移的パッケージにフラグを立てます。npm と pnpm の両方で動作します。
公開からの経過時間、タイポスクワット、プロベナンスの各チェックは、意図的に推移的には実行されません。大量のノイズが発生するか、パッケージごとにレジストリへの往復通信が必要になるためです。推移的評価は、safeinstall check、プロジェクトのインストール、および明示的な npm/pnpm の追加に備えて作成されたロックファイルに適用されます。
{
"transitive": {
"mode": "warn",
"checks": ["install-script", "untrusted-source"]
}
}
タイポスクワットの検出
よく知られた人気パッケージ名とよく似ているものの完全一致ではないパッケージ名でのインストール要求にフラグを立てます。これは最も一般的なサプライチェーン攻撃のパターンです。例:lodash を狙った lodsh、axios を狙った axois、react を狙った raect など。
- アルゴリズム: Damerau-Levenshtein 距離(文字の入れ替えは 1 回の編集としてカウント)
- 対象リスト: 人気のあるエコシステムパッケージを集めたリスト。ビルド時に埋め込まれるため、実行時のネットワーク取得はありません。
- デフォルトのモード:
"off"—typoSquat: { "mode": "warn" }または"block"を設定して有効にします。 - 誤検知の軽減: リストとの完全一致はフラグが立てられません。短い名前(4 文字未満)はスキップされ、プロジェクトごとの
ignoreリストも使用できます。
出所の検証
レジストリからのインストール時に npm の出所証明を暗号学的に検証し、パッケージごとの信頼できる公開元パターンを使用して、ソースリポジトリを任意で固定します。
- npm レジストリの
/-/npm/v1/attestations/<pkg>@<version>エンドポイントから証明バンドルを取得します - 公式の
sigstoreパッケージを使用して Sigstore バンドルを検証します(署名、Rekor 透明性ログ、Sigstore の公開信頼ルート) - SLSA v1 の出所証明ステートメントからソースリポジトリ、コミット参照、ワークフローパスを抽出します
- ソースリポジトリのスラッグをパッケージごとの
trustedPublishersパターンと照合します。これにより、改ざんされた tarball だけでなく、攻撃者が管理するフォークから正規品に見えるパッケージを再公開するメンテナー侵害攻撃も検知します - 公開元の不一致は、「warn」モードでも常にブロックします。誤ったリポジトリからの有効な署名は、まさにメンテナー侵害の兆候だからです
デフォルトモードは "off" です。provenance.mode を "warn" または "require" に設定すると有効になります。
使用方法
# Ad-hoc installs
safeinstall pnpm add axios
safeinstall npm install [email protected]
# Project installs (lockfile-aware for npm/pnpm)
safeinstall pnpm install
safeinstall npm ci
# Monorepo — select a package; shared-lockfile installs review all importers
safeinstall pnpm -C packages/app install
safeinstall npm --prefix packages/app ci
# Utilities
safeinstall check # direct dependency audit
safeinstall check --json # machine-readable
safeinstall init # one-command onboarding: config, guard hooks for
# detected agents (.claude/, .codex/, .cursor/), trust lock
safeinstall init --force # overwrite an existing config (hooks/lock stay idempotent)
safeinstall init --client codex # force specific agents instead of detection
safeinstall init --no-guard --no-lock # config only (the old behavior)
safeinstall mcp # MCP server for AI coding agents
safeinstall guard install # register agent shell hooks (Claude Code, Codex, Cursor)
safeinstall trust lock # baseline the Agent Trust Surface
safeinstall trust lock --ci github # ...and scaffold the CI re-verification workflow
safeinstall trust status # reconcile the trust surface (exit 2 on drift; read-only)
safeinstall trust approve # review drift and re-baseline (interactive)
safeinstall trust unlock # remove the baseline (lock, ledger, head mirror)
safeinstall --help
safeinstall --version
# JSON output (CI/automation)
safeinstall --json pnpm add axios
# Explicit config file (skips upward discovery)
safeinstall --config ./ci/safeinstall.config.json check
プロジェクトのインストール
pnpm install および npm install / npm ci では、依存関係のバージョンは package.json の緩い範囲指定ではなく、ロックファイルに基づきます。
- pnpm の場合は
pnpm-lock.yaml - npm の場合は
package-lock.jsonまたはnpm-shrinkwrap.json - 古い、存在しない、または一致しないロックファイルのエントリーはフェイルクローズします
package.jsonにpackageManagerが設定されている場合、異なる CLI の使用はブロックされます- ワークスペースを対象とするフラグ(
--filter、--workspace)はブロックされます。-Cまたは--prefixを使用してください - アーティファクトに紐づく Bun のインストールが実装されるまでは、
bun add/bun installはフェイルクローズします。checkと MCP ポリシーのクエリは引き続き利用できます
アーティファクトに紐づくインストールの契約
インストールには、検査済みのレジストリマニフェストと一致するロックファイルのエントリーに、正規の SHA-512 ダイジェストが 1 つ必要です。SHA-1 のみのエントリーや整合性情報のないエントリーはブロックされます。異なるコマンドラインレジストリ、スクリプトを有効にするフラグ、グローバルインストール、不明なインストールオプションはブロックされます。環境変数やスコープ付き .npmrc 設定でレジストリを選択しても、別のアーティファクトは許可されません。生成されるロックファイルは、引き続き検査済みのバインディングと一致する必要があります。
明示的に追加した依存関係は、評価済みの正確なバージョンを含むロックファイルに解決してからインストールされます。準備処理では、後続のバインディング/ポリシーチェックでブロックされた場合でも、package.json とロックファイルが更新されたり、パッケージマネージャーのキャッシュが生成されたりすることがあります。これらのファイルは確認用に残され、自動的にはロールバックされません。npm の凍結フェーズでは ci を使用し、node_modules を置き換えます。ワークスペースでロックファイルを共有している場合、選択したパッケージだけでなく、記録されているすべてのインポーターの直接依存関係が、選択したポリシーに基づいて審査されます。
レガシーの packageManagerDefaults.*.ignoreScripts が false の場合も含め、ライフサイクルスクリプトは常に無効です。allowedScripts はポリシー上の例外を許可するものであり、スクリプトの実行を許可するものではありません。pnpm の実行可能な .pnpmfile.cjs フックも無効です。レジストリ以外からの明示的な追加は、現在ブロックされます。既存のローカル/ワークスペース依存関係は allowedSources によって引き続き管理されますが、レジストリアーティファクトへのバインディングが適用されるとは限りません。
MCP サーバー / AI エージェント
CLI は、safeinstall と入力する人に利用されます。MCP サーバーは AI コーディングエージェント(Claude Code、Codex、Cursor、Windsurf、Cline)に利用されるため、誰も何も入力しなくても、エージェントがインストールを提案または実行する前にポリシーエンジンを参照できます。
safeinstall mcp は、stdio 経由で Model Context Protocol サーバーを起動し、CLI とまったく同じエンジン(リリースからの経過期間、インストールスクリプト、信頼できないソース、タイポスクワッティング、Sigstore の来歴、来歴の継続性)に基づく check_package ツールを 1 つ公開します。
重要
MCP ツールは助言を提供するものです。サーバーをインストールすると
check_packageが利用可能になりますが、エージェントに呼び出しを強制するわけではありません。「一度インストールすれば、ずっと保護」するには、MCP 設定ブロック 1 つとルールのスニペット 1 つ(mcp/agent-rule.md)が必要です。このルールで、インストールのたびにツールを呼び出すようエージェントに指示します。
エージェントに接続する
Claude Code / Claude Desktop — MCP 設定(claude_desktop_config.json または .mcp.json)に追加します。
{
"mcpServers": {
"safeinstall": { "command": "npx", "args": ["safeinstall-cli", "mcp"] }
}
}
Cursor — 同じブロックを .cursor/mcp.json に追加します。
続いて、mcp/agent-rule.md のルールを CLAUDE.md / Cursor Rules に貼り付けます。設定の詳細については、mcp/README.md を参照してください。
エージェントに表示される内容
check_package は name(必須)、version(省略可能。デフォルトは最新バージョン)、manager(省略可能。情報提供用)を受け取り、JSON 形式の判定結果を返します。
{
"verdict": "block",
"name": "raect",
"version": null,
"reasons": [
{ "code": "typo-squat-suspected", "message": "Blocked: Suspected typo-squat: \"raect\" is 2 edit(s) away from popular package \"react\".", "suggestion": "Verify you meant to install \"react\"." }
],
"warnings": [],
"infos": [],
"sourceRepository": null,
"ageHours": null
}
いずれかのポリシー上の理由によってインストールがブロックされる場合、verdict は "block" になります。それ以外の場合は "allow" になります。
safeinstall.config.json が見つからない場合、MCP サーバーは推奨セキュアプリセットを使用します。これは組み込みのデフォルト設定で、エージェントのユースケースでは最大限のシグナルが必要となるため、typoSquat と continuity が "block" に引き上げられています。設定ファイルが見つかった場合は、その内容がそのまま適用されます(CLI と同じ解決方法です)。
MCP SDK はオプションの依存関係として提供され、safeinstall mcp の実行時にのみ遅延読み込みされます。CLI のみを使うユーザーがインストールする必要はありません。SDK が見つからない場合、コマンドはインストールを促すメッセージを表示し、ゼロ以外の終了コードで終了します。
エージェントガード — 助言ではなく強制
MCP ツールは助言を提供するものです。エージェントはこれを参照できます。ガードはより強力なレイヤーで、エージェントのシェルレイヤーにフックし、コマンドの実行前に検査します。エージェントが SafeInstall の存在を知らない場合でも動作します。これはベストエフォートのシェルインターセプトであり、多層防御の一部であって完全な境界ではありません。また、コマンドの解析は網羅的ではありません(ガードの制限事項を参照)。
safeinstall guard install # Claude Code, Codex, and Cursor
safeinstall guard install --client codex # or just one client
これにより、プロジェクトレベルのフック設定が書き込まれます(既存の設定を破壊せずにマージされ、再実行しても冪等です)。
- Claude Code —
.claude/settings.jsonのBashツールにPreToolUseフックを設定します。permissionDecisionを指定せずにupdatedInputを使い、SafeInstall CLI 経由で生のインストールコマンドをその場で書き換えます。そのため、Claude の通常の権限確認が引き続き表示され、書き換えられたコマンドをユーザーが確認して承認できます。 - Codex —
.codex/hooks.jsonのBashにPreToolUseフックを設定します。Codex のupdatedInputを使い、SafeInstall CLI 経由で生のインストールコマンドをその場で書き換えます。インストール後、Codex で/hooksを開き、新しいプロジェクトフックを信頼してから実行してください。 - Cursor —
.cursor/hooks.jsonにbeforeShellExecutionフックを設定し、failClosed: trueを指定します。これにより、ガードがクラッシュまたはタイムアウトした場合に、何も警告せず許可するのではなくブロックします。
登録後、CLI はプロジェクトの状態に合った Trust Surface のステップを報告します。ベースラインのないプロジェクトには、safeinstall trust lock の実行が案内されます。すでにベースラインがあり、ガードによって変更された場合は、safeinstall trust status で差分全体を確認し、すべての変更が意図したものだと確認できた場合にのみ safeinstall trust approve を実行してください。すでに登録済みのガードを再実行しても、ステータスで差分が報告されない限り、再承認は不要です。
ガードの判定方法
ガードはポリシー自体を評価することはありません。パッケージのインストールを検出し、判定を担う CLI に処理をルーティングします。
| エージェントの実行内容 | ガードの応答 |
|---|---|
git status、npm test、... | 許可 — インストールではありません |
npm install axios(npm i、pnpm add、bun a、npm ci、corepack pnpm add、pnpm --dir app add、...も対象) | Claude/Codex:実行前に safeinstall npm install axios へその場で書き換え(許可プロンプトにはルーティング後のコマンドが表示されます)。Cursor:SafeInstall で置き換えるよう拒否 |
cd app && npm i axios && npm test | 書き換えではインストール部分のみの先頭にコマンドを追加します。Claude/Codex はそのまま適用し、Cursor はエージェントに返します |
safeinstall npm install axios | 許可 — すでにポリシーエンジンを経由しています |
npm install $(cat list.txt)、bash -c "npm install ..." | 拒否 — 安全に解析できません(フェイルクローズ) |
yarn add axios | 拒否 — SafeInstall は yarn のポリシーチェックができません |
typescript がローカルにインストールされた状態での npx tsc | 許可 — npx はローカルのバイナリを解決するため、何もダウンロードされません |
npx create-next-app、pnpm dlx ...、bunx ...、yarn dlx ... | Claude/Cursor:確認を求めます。Codex:Codex の PreToolUse は現在 ask 判定に対応していないため、拒否 |
CLI 経由のルーティングは、単純な許可/拒否よりも重要です。審査済みでも生の npm install はライフサイクルスクリプトを実行します。SafeInstall 経由なら、同じインストールに対して完全なポリシー評価を行い、インストールスクリプトを無効にして実行します。
Claude と Codex は updatedInput を使ってその場で書き換えを適用するため、通常の許可プロンプトには生のインストールコマンドではなく、SafeInstall 経由のコマンドが表示され、ユーザーはそれを承認できます。Cursor は書き換え後のコマンドをブロックメッセージにそのまま含めるため、適切に動作するエージェントなら一度の処理で自己修正できます。ガードにネットワークアクセスは不要で、応答は数ミリ秒です。
ガードの制限事項
safeinstallバイナリがエージェントのPATHに含まれている必要があります(npm install -g safeinstall-cli)。- Codex では、新しいフックや変更されたフックをユーザーが
/hooksで確認して信頼する必要があります。それまでは Codex はフックをスキップします。現在の Codex がインターセプトするのは、サポートされている単純なシェル呼び出しのみで、すべてのunified_exec経路ではないため、このフックは引き続き多層防御のガードレールであり、完全な境界ではありません。 npxなどはポリシーチェックされません。SafeInstall のエンジンが評価するのはインストールであり、単発の実行ではありません。Claude/Cursor は承認を求めます。Codex はPreToolUseフックが現在askに対応していないため、フェイルクローズします。ローカルバイナリの高速経路はランナー自体の解決方法(最も近いnode_modules/.bin)を反映しているため、承認済みのプロジェクトツールではリモートランナーのゲートは作動しません。- 対策を講じた攻撃者はシェルレベルの解析を回避できます。インストールはシェル外で実行でき(先に書き込んだスクリプトファイルや
node -eなど)、コマンドライン解析自体も網羅的ではありません。シェルレイヤーだけに頼らないでください。多層防御の一層としてハードルを上げるものであり、MCP ツールおよび CI チェックと組み合わせてください。
エージェントの信頼領域 — 自己防御型ポリシー
ガードは未加工のインストールを阻止します。しかし、プロンプトインジェクションを受けたエージェントはガードと争う必要はありません。単にルールを書き換えるだけです。safeinstall.config.json を弱めたり、エージェントフックを削除したり、.codex/config.toml で Codex フックを無効化したり、AGENTS.md に不可視 Unicode の指示を仕込んだり、悪意のある MCP サーバーを登録したりできます。これらのファイルは次のエージェントセッションをプログラムします。エージェント時代において、これらは永続化の仕組み、つまり新しい crontab です。
safeinstall trust lock は、この領域のハッシュベースラインを記録します。その後、SafeInstall はガードの判断前と、すべてのインストール/チェックの前に実際の状態をベースラインと照合し、CI でも再検証できます。
safeinstall guard install # register the hooks
safeinstall trust lock --ci github # baseline the surface AND scaffold CI re-verification
safeinstall trust status # reconcile — exit 2 on drift (use in CI); read-only
safeinstall trust approve # review drift and re-baseline (interactive only)
safeinstall trust unlock # remove the baseline (lock, ledger, head mirror)
--ci github は .github/workflows/safeinstall-trust.yml を書き込みます。このワークフローは、CLI を正確なバージョン およびその sha512 コンテンツハッシュに固定して safeinstall trust status --require-lock を実行することで、すべてのプルリクエストでコミット済みのベースラインを再検証します。これらはスキャフォールド時にレジストリから記録されます(初回使用時の信頼)。後になってレジストリがそのバージョンに対して異なるバイト列を配信した場合、検証ツールをひそかに差し替えるのではなく、チェックは失敗します。このワークフローは pull_request_target を使用するため、GitHub は保護されたベースブランチからその定義を読み込みます。提案されたリビジョンを認証情報なしでチェックアウトし、データとしてのみ扱い、PR コードを実行することはありません。.safeinstall/ とこのワークフローは一緒にコミットしてください。既存のワークフローファイルが上書きされることはありません。そのため、PR が自らを審査する検証ツールを無効化することはできません。ただし、ポリシーとベースラインを完全に整合した形で書き換えた場合は、差分の人間によるレビューが必要です(下記の CODEOWNERS に関する注記を参照してください)。
チェックを実際に強制するには、CLI では設定できない次の 2 つを行う必要があります。
- ブランチ保護で、このワークフローを必須ステータスチェックにします。そうしないと、チェックが失敗してもマージはブロックされません。
.safeinstall/と.github/workflows/への変更にレビューを必須にします(たとえばCODEOWNERSを使用します)。自動チェックで検出できるのは整合性のない改ざんです。PR 1 件でベースライン全体を完全に整合した形で書き換えた場合は、.safeinstall/の差分を人間がレビューしなければ検出できません。
3 つのゾーン
| ゾーン | ファイル | ドリフト時の動作 |
|---|---|---|
| 強制 | safeinstall.config.json、.claude/settings.json、.codex/hooks.json、.codex/config.toml、.cursor/hooks.json、.github/workflows/safeinstall-trust.yml、.safeinstall/ | 人間が承認するまで、すべてのエージェントコマンドが拒否されます |
| 指示 | AGENTS.md、CLAUDE.md、.cursorrules、.cursor/rules/**、.github/copilot-instructions.md | 不可視 Unicode は常にブロックされます。内容のドリフトは警告されます(--mode strict ではブロックされます) |
| ツール | .mcp.json、.cursor/mcp.json、.claude/settings.json 内の MCP ブロック | 人間が承認するまで、インストールとランナーが拒否されます。ピン留めされていない MCP サーバーには警告が表示されます |
指示内容のドリフトは、Claude Code が CLAUDE.md に自ら書き込む(メモリー機能)ため、デフォルトでは警告のみです。これをブロックすると、通常のワークフローが機能しなくなります。一方、不可視 Unicode にはこれらのファイル内で正当な用途がないため、常にブロックされます。
どのように防御するか
- 検証器は保護されたベースブランチから取得されます。意図的なベースラインの再設定は、引き続き人間によるレビューが必要です。
safeinstall trust lock --ci githubを実行すると、プルリクエストごとに、エージェントが制御できないマシン上で、候補の信頼対象をコミット済みのロックと照合して再ハッシュするワークフローを生成できます。CLI は正確なバージョンとその sha512 コンテンツハッシュに固定されます。pull_request_targetにより、検証器の定義は PR の制御外に置かれ、候補のチェックアウトは認証情報を持たない不活性データとして扱われます。これにより、PR がワークフローを編集して自身の失敗を無効にすることを防ぎます。ただし、正直なところ、PR はポリシーとベースラインを一貫性を保って書き換えることはできます。そのため、これらの差分は独立したレビューを必須にしてください。(Action を直接設定する方法もありますが、version:入力を固定してください。デフォルトのlatestは変動します。) - 傍受に加えて照合も行います。 ガードは迅速に動作する層です。すべての
safeinstallのインストール/チェックでも、ベースラインとの照合が行われます。ガードを黙らせるためにフックを削除したり、保護対象のファイルを編集したりすると、次回の SafeInstall のローカル実行時にドリフトとして検出されます。また、いずれにせよ、CI の再検証にも失敗します。 - 人間の承認が必要な変更。 適用を緩和する 2 つのコマンドはいずれも、人間による操作が必要です。
safeinstall trust approveは確認入力を制御端末(/dev/tty)から読み取り、stdin からは読み取りません。またtrust unlockも制御端末を必要とします。どちらも CI または既知のエージェントフックのコンテキストでは実行を拒否するため、エージェントがベースラインをひそかに再設定したり、信頼対象を削除したりすることはできません。trust statusは読み取り専用です(CI で安全に実行でき、リポジトリを変更しません)。 - ハッシュチェーン付き台帳。 ベースラインに関する判断は
.safeinstall/ledger.jsonlでチェーン化されます。ロックは適用のmodeを含む台帳エントリに紐付けられているため、コミット済みロックを編集してファイルを削除したり、strict から warn に格下げしたりすると、紐付けが壊れます。~/.safeinstall/にあるローカルのヘッドミラーは、単純な/偶発的な履歴の書き換えを検出します。ミラーが消えても、次のクリーンな実行時に検証済みのヘッドから自動修復されるため、新しいクローンでも自動的に作成され、余計な通知は発生しません。
信頼対象の制限 — 正しく理解してください
- 最も強力な層は、PR でレビューされるコミット済みロックであり、ローカルミラーではありません。 ローカルでは、これはミスや標的を定めていない改ざんを検出できるものであり、改ざんを防止するものではありません。 自分のユーザーアカウントで動作する、仕組みを理解したエージェントは傍受を回避し(たとえば
node -eからインストールを実行するなど)、リポジトリ内のロックと台帳を一貫性のある状態に書き換え、ローカルのヘッドミラーを削除できます。エージェントはあなたが読んだり削除したりできるものを何でも読み書きできるため、ユーザー空間ではそれを防げません。CI の再検証は、ベースブランチが所有するワークフローによって別のマシン上で実行されるため、PR が自身の検証器を無効にすることはできません。ただし、ポリシーとベースラインを一貫性を保って書き換えれば、自動チェックを通過することは可能です。高い能力を持つ攻撃者に対して残る保証は、すべての依存関係に関する PR で、信頼対象の差分(ワークフロー、ロック、設定)を独立した人間がレビューすることです。2 人目の信頼できるレビュアーを確保できた時点で、ルールセットによってこれを必須にしてください。CI チェックを実行し、そのレビューを必須にしてください。両者は異なる失敗モードに対応します。 - エージェントの意図ではなく、シェルコマンドとファイルを監視します。エージェントが作成して実行するプログラムによるインストールは、呼び出し時点では防止されず、次回の SafeInstall/CI 実行時の照合で検出されます。
- ローカルのヘッドミラーがない状態は、新しいクローンにもミラーがないため、どちらとも判断できません。そのため、クリーンな検証時には警告やブロックではなく、コミット済みの台帳ヘッドから自動修復されます。ミラーはローカルでの利便性を高めるための最善努力による仕組みであり、保証そのものではありません。
設定
任意の safeinstall.config.json。プロジェクトディレクトリから上位へたどって検出されるか、--config <path> で明示的に指定します。明示的に指定したパスを読み取れない場合はエラー(終了コード 1)となり、デフォルト設定に黙ってフォールバックすることはありません。
{
"minimumCliVersion": "0.12.0",
"minimumReleaseAgeHours": 72,
"registryUrl": "https://registry.npmjs.org",
"allowedScripts": {
"esbuild": ["postinstall"]
},
"allowedSources": ["registry", "workspace", "file", "directory"],
"allowedPackages": [],
"packageManagerDefaults": {
"npm": { "ignoreScripts": true },
"pnpm": { "ignoreScripts": true },
"bun": { "ignoreScripts": true }
},
"typoSquat": {
"mode": "warn",
"minNameLength": 4,
"ignore": []
},
"provenance": {
"mode": "warn",
"requireFor": [],
"trustedPublishers": {
"axios": "axios/axios"
},
"offlineBehavior": "fail-closed",
"toolingUnavailable": "warn"
},
"transitive": {
"mode": "warn",
"checks": ["install-script", "untrusted-source"]
},
"continuity": {
"mode": "warn",
"baselineSize": 5
}
}
| フィールド | 用途 |
|---|---|
minimumCliVersion | 任意。プロジェクトの保護機能が想定する safeinstall-cli の最低バージョン(正確な semver)。実行中の CLI がこれより古い場合、ガード、install/check、trust status で警告しますが、ハードエラーにはなりません |
minimumReleaseAgeHours | レジストリのバージョンの最低経過時間(時間単位) |
registryUrl | メタデータとインストールに使用する npm 互換のレジストリ URL(ミラー、Artifactory、Verdaccio) |
allowedScripts | パッケージごとのライフサイクルスクリプトの例外 |
allowedSources | 許可するソースの種類 |
allowedPackages | リリース経過時間、インストールスクリプト、タイポスクワットの各チェックをスキップする名前(警告を表示)。ソース、信頼性の低下、来歴のチェックは引き続き適用されます |
packageManagerDefaults | レガシー設定。ignoreScripts が false の場合でも、ライフサイクルスクリプトは無効のままです |
typoSquat.mode | "off"/"warn"/"block" — タイポスクワットの疑いがある場合の処理方法 |
typoSquat.minNameLength | チェック対象とするパッケージ名の最小文字数(これより短い名前はスキップされます) |
typoSquat.ignore | スキップする、正当な類似名として確認済みの名前。読み込み時に小文字に変換されます |
provenance.mode | "off"/"warn"/"require" — Sigstore 証明書を検証するかどうか |
provenance.requireFor | "warn" モードでも来歴を必須とするパッケージ名(glob に対応) |
provenance.trustedPublishers | パッケージ名のパターン → 期待する owner/repo スラッグのマップ。不一致は常にブロックされます |
provenance.offlineBehavior | "fail-closed" は取得に失敗した場合にブロックし、"allow-cached" はキャッシュ済みの証明書を使用します |
provenance.toolingUnavailable | "warn"(デフォルト)は sigstore 検証ツールがインストールされていない場合に明確な警告を表示して処理を続行します。"fail-closed" は検証ツールがないことを疑わしい状態として扱い、インストールされるまでのすべてのインストールをブロックします(sigstore 自体のインストールは例外となるため、デッドロックすることはありません) |
transitive.mode | "off"/"warn"/"block" — 直接依存関係だけでなく、ロックファイル内の依存関係ツリー全体を評価します |
transitive.checks | 推移的に実行するチェック:"install-script" および/または "untrusted-source" |
continuity.mode | "off"/"warn"/"block" — パッケージごとに学習したベースラインと照合し、来歴の格下げやソースリポジトリの変更を検出します |
continuity.baselineSize | ベースラインの学習時にサンプルとする直近のバージョン数(デフォルトは 5) |
最低 CLI バージョンの指定
ガードの判定はリリースごとに変わります(誤検出の修正、新しいチェックの追加など)が、CLI は通常グローバルにインストールされます。そのため、プロジェクトが 0.12.0 の動作を想定していても、エージェントのマシンでは 0.11.0 が動作している場合があります。minimumCliVersion にポリシーが想定する最低バージョンを設定すると、それより古い CLI はすべて不一致を明確に通知します。
Warning: This project's safeinstall.config.json expects safeinstall-cli >= 0.12.0, but version 0.11.0 is running — protections this project relies on may be missing or behave differently. Update with `npm install -g safeinstall-cli@latest`.
このチェックは完全にオフラインで行われ(実行中のバージョンと semver を比較)、意図的に警告にとどまり、ハードエラーにはなりません。ハードエラーにすると、グローバル CLI が更新されるまで、リリースのたびにすべてのエージェントセッションが中断されてしまいます。知っておくべき注意点は 2 つあります。
- このフィールドには正確なバージョン(
"0.12.0")を指定する必要があり、範囲指定はできません。これは制約ではなく下限です。それ以外を指定すると、設定の解析は fail-closed で失敗します。 - このフィールドが追加される前にリリースされた CLI は、未知の設定キーを拒否するため、警告を出すのではなく設定全体を拒否します(fail-closed)。このフィールドを設定すると、共同作業者がこのフィールドに対応した CLI を実行することが実質的に必要になります。
safeinstall init を実行して、設定のひな形を生成します。
終了コード
| コード | 意味 |
|---|---|
0 | 許可/チェック合格 |
1 | 実行時または設定のエラー |
2 | ポリシーによるブロック |
CI パイプラインでは、ほかの失敗したステップと同様に終了コード 2 を扱います。
JSON 出力
コマンド内の任意の場所に --json を渡します。構造化された出力は stdout に出力されます。
safeinstall --json pnpm add axios
フィールド:command、commandString、packageManager、decision、summary、reasons、warnings、affectedPackages、exitCode、exitCodeMeaning。許可されたインストールには execution.stdout と execution.stderr が含まれます。
例
すべてのチェックの動作を確認しますか?
bash demo/run.shを実行してください。実際のパッケージに対して、各ポリシーチェックで1つずつシナリオをブロックする、再現可能なスクリプトです。手順については demo/README.md を参照してください。実際の攻撃に対する動作を確認しますか?
pnpm replay mastraを実行してください。2026年6月の Mastra 侵害時の記録済み状態を SafeInstall の実際のポリシーエンジンに入力し、どのチェックが攻撃をブロックできたかを表示します。demo/replay/README.md を参照してください。
新しいリリースをブロック
$ safeinstall pnpm add axios
Using config: built-in defaults
Install blocked.
- [email protected]
Blocked: release too new ([email protected] is 6 hours old; minimum is 72 hours).
Suggestion: Retry later or lower minimumReleaseAgeHours if this package is intentionally urgent.
Git ソースをブロック
$ safeinstall npm install github:axios/axios
Using config: built-in defaults
Install blocked.
- github:axios/axios
Blocked: untrusted source (git).
Suggestion: Use a registry release or allow this source intentionally.
パッケージマネージャーの不一致
$ safeinstall npm install
Using config: built-in defaults
Install blocked.
- Project install blocked: package.json declares pnpm as packageManager, but this command uses npm.
ロックファイルが古い
$ safeinstall pnpm install
Using config: built-in defaults
Install blocked.
- Project install blocked: axios is declared in package.json but missing from pnpm-lock.yaml.
タイポスクワッティングを検出
$ safeinstall pnpm add raect
Using config: ./safeinstall.config.json
Install blocked.
- raect
Blocked: Suspected typo-squat: "raect" is 1 edit(s) away from popular package "react".
Suggestion: Verify you meant to install "react". If this package is intentional, add "raect" to typoSquat.ignore.
公開者の不一致(メンテナーの侵害に対する防御)
$ safeinstall pnpm add [email protected]
Using config: ./safeinstall.config.json
Install blocked.
- [email protected]
Blocked: publisher mismatch for axios (expected axios/axios, got evil-org/axios).
Suggestion: Verify the package source. Update provenance.trustedPublishers only if the change is intentional.
GitHub Action
すべてのプルリクエストで SafeInstall のポリシーチェックを自動実行します。YAML は5行で、設定は不要です。デフォルトがすぐに適用されます。
# .github/workflows/safeinstall.yml
name: SafeInstall Policy Check
on: [pull_request]
jobs:
policy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- uses: Mickdownunder/SafeInstall@v1
このアクションは、直接依存関係に対して safeinstall check を実行し、ジョブのステータスを成功または失敗に設定します。ブロックされた依存関係は、正確なブロック理由と提案とともに GitHub Actions のジョブサマリーに表示されます。
インストールモード
チェックだけでなく、実際のインストール手順でポリシーを適用するには:
- uses: Mickdownunder/SafeInstall@v1
with:
mode: install
package-manager: pnpm
args: "--frozen-lockfile"
入力
| 入力 | デフォルト | 説明 |
|---|---|---|
mode | check | check は依存関係を監査し、install はパッケージマネージャーを SafeInstall 経由で実行します |
package-manager | pnpm | インストール時は npm または pnpm を指定します。bun はフェイルクローズします |
args | パッケージマネージャーに渡す追加の引数 | |
config-path | safeinstall.config.json の明示的なパス(省略時は自動検出されます) | |
version | latest | インストールする SafeInstall CLI のバージョン |
出力
| 出力 | 説明 |
|---|---|
decision | allow または block |
summary | 人が読める1行のサマリー |
exit-code | 0(許可)、2(ブロック)、または 1(エラー) |
json | SafeInstall の JSON 結果全体 |
制限事項
- CVE スキャナーではありません — 脆弱性データについては、
npm auditまたは Snyk と併用してください - 推移的な依存関係は、
transitive.modeが有効な場合、インストールスクリプトと信頼できないソースについて評価されます。リリースからの経過期間、タイポスクワッティング、来歴の確認は、引き続き直接依存関係のみが対象です。 - 推移的なインストールスクリプトの検出は npm のみ対応しています — pnpm のロックファイルにはインストールスクリプトの有無が記録されません。推移的な信頼できないソースの検出は、どちらにも対応しています。
- **ネイティブビルド(
binding.gyp)**は、インストールスクリプトのチェックで検出されます。npm は公開時にbinding.gypをnode-gyp rebuildのインストールスクリプトに正規化するため、SafeInstall がすでに読み取るレジストリメタデータに含まれており、tarball のダウンロードは不要です。残る例外は、非標準クライアントを通じて公開されたパッケージが、binding.gypを含みながらこの正規化を省略している場合です。これを検出するには tarball の内容を調査する必要がありますが、対象外です(実施しないことを参照)。 - **
peerDependencies**は、直接依存関係としても宣言されていない限り評価されません - 信頼度の低下の検出には、
node_modules内の以前のインストール状態が必要です - Bun でのインストールはフェイルクローズします。アーティファクトバインディングアダプターは実装されていません
- 信頼できる実行境界 — これは OS サンドボックスではありません。信頼できる npm/pnpm バイナリがロックファイルの整合性を凍結状態で強制し、選択されたレジストリメタデータが信頼でき、ローカルファイルシステムが同時に攻撃者によって制御されていないことを前提としています。パッケージコードが無害であることを証明したり、すべての推移的アーティファクトがレジストリポリシーに準拠しているかを調査したり、実行時の実行を隔離したりするものではありません
- タイポスクワッティング対象リストは厳選され、リリース間に手動で更新されます。直近 1 日に公開された新しいパッケージは、まだ掲載されていない場合があります
- 来歴の検証は、公開 Sigstore ルート上の GitHub Actions 信頼できるパブリッシャーにのみ対応しています(GitLab CI、セルフホストの Sigstore は現在対象外です)
- Git ソースは、推測したパッケージ名ではなく、許可リストの判定に URL を使用します。レジストリの
axiosとgithub:any-fork/axiosを同一視するのは危険です - 曖昧なメタデータは推測せず、ブロックします — これは意図的な設計です
実施しないこと
- 脆弱性スキャンや CVE データベースへの対応
- レジストリのプロキシや tarball の書き換え
- マルウェアの検出やパッケージ内容の分析
- ライフサイクルスクリプトの選択的な実行(常に
--ignore-scriptsを強制します)
対応ツール
SafeInstall は、パッケージマネージャーのコマンドを実行するあらゆるツールで利用できます。AI コーディングアシスタントも含まれます。
Cursor · Codex · GitHub Copilot · Cline · Claude Code · Windsurf · Aider · Devin · Continue
インストールコマンドの先頭に safeinstall を付けるだけです。同じワークフローに、安全レイヤーを 1 つ追加できます。
貢献
pnpm install
pnpm typecheck
pnpm test
pnpm build
Issue や PR を歓迎します。マージは作者の裁量で行います — 個人でメンテナンスしているプロジェクトです。
ライセンス
MIT — LICENSE を参照してください。
免責事項
SafeInstall は MIT ライセンスのもと、現状有姿で提供されます。パッケージのインストールに対して、設定可能なルールを適用するポリシーツールです。パッケージの安全性を保証するものではなく、すべてのサプライチェーン攻撃を検出するものでも、専門家によるセキュリティレビューに代わるものでもありません。ご自身の責任でご利用ください。本ソフトウェアの使用に起因する損害について、作者は一切責任を負いません。
最終確認日:2026-10-01
safeinstall.dev · npm · GitHub
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。