Files
msd-core/docs/ja-JP/explanation/security-model.md
Tom Boucher de78f2eef2 docs(#2775): align package-legitimacy docs to the ADR-0656 registry-API gate (#3010)
* docs(#2775): align package-legitimacy docs to the ADR-0656 registry-API gate

security-model.md, USER-GUIDE.md, ARCHITECTURE.md, COMMANDS.md,
FEATURES.md, and gsd-planner.md's STRIDE template (+ ja-JP mirrors)
described the pre-ADR-0656 design: slopcheck as the install-or-degrade
gate, with unavailability degrading every package to [ASSUMED].
ADR-0656 inverted this months ago — registry-API verdicts (npm/PyPI/
crates.io) are the gate; slopcheck is an optional escalate-only adapter
that no shipped configuration wires. Verified every replacement claim
against src/package-legitimacy.cts (checkPackages, classifyPackage,
lookupNpm/lookupPypi/lookupCrates) via Memtrace before writing it, so
the corrected prose matches the live implementation rather than
restating the ADR from memory.

Restored docs/explanation/security-model.md:79-84 (and its ja-JP
mirror) to original wording after an orthogonal spec review caught
that an earlier draft had edited the "Why WebSearch packages are
always [ASSUMED]" paragraph — inside the range issue #2775 explicitly
named as correct and to leave alone.

The ja-JP mirror was missing the closing clause present in the
corrected English original ("its absence leaves registry-API verdicts
intact rather than downgrading everything to [ASSUMED]") — added for
parity. This completes the ja-JP mirror the issue's acceptance
criteria named explicitly.

zh-CN/ko-KR/pt-BR (not named by #2775, but carrying the same stale
design) get the mechanical portion of the same fix: command-string
swaps, table headers, ARCHITECTURE.md diagram labels, and technical-
term swaps that reuse a word already attested elsewhere in the same
file (合法性/적법성/legitimidade for "legitimacy") — surrounding prose
untouched. The remainder in those three locales — full-paragraph
rewrites of the corrected degrade-path mechanism, deleted "External
dependency" bullets, and "manually install slopcheck" code blocks —
needs prose composed by a fluent speaker of each language and is filed
as open-gsd/gsd-core#3002 with an exact file:line inventory.

* test(#2775): acknowledge gsd-planner.md byte growth from the STRIDE-row fix

agents/gsd-planner.md grew 14 bytes (49309 -> 49323) from the STRIDE
supply-chain row correction (slopcheck -> package-legitimacy gate).
Emitted agent/workflow files are byte-tracked; this fragment
acknowledges the growth per tests/emitted-attribution.test.cjs's
"differential attribution over the real tree" check.

* docs(#2775): close ja-JP FEATURES.md gap; fix a ko-KR transliterated heading

docs/ja-JP/FEATURES.md:2808 still read the katakana transliteration
"スロップチェック verdict" in REQ-PKG-GATE-01 — invisible to a literal
"slopcheck" grep, so it was missed when ja-JP parity was checked and
declared complete. Corrected to "正当性判定" (legitimacy verdict),
matching the term already established in ja-JP/explanation/
security-model.md and ja-JP/USER-GUIDE.md. This was the only
remaining ja-JP gap; a full sweep for the transliterated form across
docs/ja-JP/ now returns zero hits, and the ja-JP mirror is genuinely
at parity.

docs/ko-KR/USER-GUIDE.md:398's heading "슬롭체크 판정:" had the same
transliteration problem. Fixed inline to "적법성 판정:", reusing the
적법성/legitimacy word already attested two lines below in the same
table. A parallel sweep of zh-CN and pt-BR found no transliterated
forms of "slopcheck" in either locale. The remaining transliterated
occurrence in ko-KR (USER-GUIDE.md:406, the lead-in to the
pip-install code block) needs prose composition like the rest of that
block and is added to open-gsd/gsd-core#3002's inventory.

* chore(#2775): backfill changeset PR number to 3010

---------

Co-authored-by: sim <sim@local>
2026-08-02 20:24:42 -04:00

118 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# GSD Core セキュリティモデル
> **解説** — このドキュメントは、GSD Core がなぜこのようなセキュリティ姿勢を持っているか、そして *各レイヤーがどのように組み合わさるか* を説明します。すべてのフックパラメーターのリファレンスではありません。`/gsd-secure-phase` コマンドとそのオプションについては、[コマンド](../COMMANDS.md) を参照してください。実装レベルのフックアーキテクチャについては、[アーキテクチャ § フックシステム](../ARCHITECTURE.md#hook-system) を参照してください。組織全体のセキュリティベースライン(スキャナー制御、インシデントチェックリスト、所有権モデル)については、[SECURITY.md](../../../SECURITY.md) を参照してください。
---
## AI 駆動開発が専用のセキュリティ姿勢を必要とする理由
従来のコードエディターはあなたに代わって任意のパッケージを実行しません。GSD Core は実行します。調査 → 計画 → 実行パイプラインは「パッケージ名を指定する」から「`npm install <package>` を実行する」まで、「計画アーティファクトを書く」から「そのアーティファクトを LLM システムプロンプトとして使う」までの完全なパスを自動化します。各自動化ステップは人間をループから外します——そして各除去は潜在的な攻撃面です。
GSD Core のセキュリティモデルは一つの組織原則の上に構築されています:**多層防御**。単一の制御が完璧だとは想定しません。複数の重複したレイヤーがそれぞれ異なるクラスのリスクを軽減し、合わせて全体を完全に排除することなく攻撃面を実質的に悪用しにくくします。このドキュメントの末尾にある正直な要約は、システムが何に対して保護できないかを説明します。
---
## レイヤー 1 — サプライチェーン保護:パッケージ正当性ゲート
### 脅威
AI モデルはパッケージ名を幻覚します。これはまれな失敗モードではありません:2025 年の研究では、AI が生成するパッケージ参照のおよそ 20% が正規のパッケージに対応しない幻覚された名前であることが記録されています。これらの幻覚された名前のサブセット——同じ研究でおよそ 43%——はプロンプトをまたいで一貫して繰り返され、攻撃者は AI ツールが一般的に生成する名前を観察し、npm、PyPI、または crates.io でそれらの名前を悪意のあるポストインストールスクリプト付きで事前登録できます。この技術は *スロップスクワッティング* と呼ばれます。
スロップスクワッティングの陰湿な点は、`npm view` を通過する幻覚された名前が *正当に見える* ことです。レジストリエントリは誰かがその名前を登録したことを証明するだけです——パッケージが AI の言う通りのことをするとも、正規のユーザーがいるとも、インストールスクリプトが安全だとも証明しません。ゲートがなければ、幻覚された名前は GSD の調査者 → プランナー → エグゼキューターパイプラインを検出されずに流れ、最終的にあなたのマシンで `npm install <attacker-package>` として実行されるでしょう。
### ゲートの仕組み
ゲートは 3 つのパイプラインステージにわたって動作します:
**調査ステージ。** `gsd-phase-researcher` が外部パッケージを推奨するとき、それぞれに対して `gsd-tools query package-legitimacy check --ecosystem <npm|pypi|crates> <pkgs>` を実行します。評決(`OK|SUS|SLOP`)はライブのレジストリ API から、しきい値 `{ minAgeDays: 30, minWeeklyDownloads: 1000, requireRepo: true }` に基づいて計算され、非存在および疑わしい `postinstall` スクリプトに対する終端ショートサーキットも含まれます。結果は `RESEARCH.md` の `## Package Legitimacy Audit` テーブルに書き込まれます。`[SLOP]`(高信頼度の幻覚または攻撃者登録済み)とタグ付けされたパッケージは、ファイルが保存される前に **`RESEARCH.md` から完全に除去されます**。それらはプランナーに届きません。
**計画ステージ。** `gsd-planner` は監査テーブルを読み取ります。`[SUS]`(疑わしい:新規登録、低ダウンロード数、ソースリポジトリなし、または人気パッケージに近い命名パターン)または `[ASSUMED]`(直接レジストリ検証ではなく WebSearch から取得)とタグ付けされたパッケージについて、プランナーはインストールステップの前に **`checkpoint:human-verify` タスクを挿入します**。チェックポイントにはレジストリページへの直接リンクと、確認すべき具体的な事項が含まれます:メンテナー履歴、イシュートラッカーの活動、疑わしいインストールスクリプトがないこと。
**実行ステージ。** インストールが失敗した場合、`gsd-executor` は**チェックポイントを表示して停止します**。それ自体が悪意のある可能性のある代替パッケージ名をサイレントに試みません。これはエグゼキューターの動作における明示的なルールです(エグゼキュータエージェント定義の RULE 3)。
### WebSearch パッケージが常に `[ASSUMED]` である理由
WebSearch を通じて発見されたパッケージ名は、`npm view` が成功するかどうかに関わらず `[ASSUMED]` とタグ付けされます。レジストリに存在するパッケージは、インストールしても安全なパッケージと同じではありません。`npm view` は登録を証明するだけで、正当性を証明しません。`[ASSUMED]` タグは `[SUS]` と同じ人間検証チェックポイントをトリガーし、未検証のウェブ検出推奨は常にインストール前に人間のレビューを受けることを保証します。
### エコシステムカバレッジ
ゲートは単一の汎用チェックではなく、各エコシステムのレジストリ API から直接シグナルを解決します:
- Node.js:`registry.npmjs.org`(登録日、リポジトリ URL、`postinstall` スクリプト)と `api.npmjs.org/downloads`(週間ダウンロード数)
- Python:`pypi.org/pypi/<pkg>/json`(登録日、リポジトリ URL)
- Rust:crates.io API(登録日、週間ダウンロード数、リポジトリ URL)
これは 2025 年の USENIX 研究によると約 9% の割合で発生するクロスエコシステム幻覚をカバーします——AI が実際に使用しているエコシステムには存在しない別のエコシステムのパッケージを推奨するケース。
### グレースフルデグレデーション
各レジストリアダプターには 5 秒のタイムアウトがあり、失敗したルックアップに対しては例外をスローせずデグレードされた(すべて null の)シグナルを返します。欠落したシグナルは `unknown-age` / `unknown-downloads` の理由として現れ、パッケージを `[SUS]` に押し上げます——そして `[SUS]` は `[ASSUMED]` と同じ `checkpoint:human-verify` タスクでゲートされます。ゲートはサイレントにではなく人間のレビューに向かって失敗し、調査と計画は通常どおり進行します:ネットワークやツールの障害でハードフェイルすることはありません。
`slopcheck` はオプションのアダプターであり、評決をエスカレートすることしかできず(引き下げることはできません)、インストールまたはデグレードのゲートではありません。出荷される設定はこれを配線しません。その不在は、すべてを `[ASSUMED]` に格下げするのではなく、レジストリ API の評決をそのまま維持します。
---
## レイヤー 2 — プロンプトインジェクション防御
### 脅威
GSD Core は LLM システムプロンプトになる Markdown ファイルを生成します。調査パイプラインは外部ウェブコンテンツを読み取ります;計画パイプラインはユーザー提供のテキスト(`--text-file`、`--prd`)を組み込みます;実行パイプラインは後でエージェントコンテキストとして再読み取りされる計画アーティファクトを書きます。これらのアーティファクトに流れ込む任意のユーザー制御テキストは、潜在的な **間接プロンプトインジェクション** ベクターです——一度システムプロンプトの中に入ると、エージェントの指示を上書きしたり情報を窃取しようとする攻撃者制御の文字列。
### 防御の仕組み
GSD Core はプロンプトインジェクションを 3 つのレベルで対処します。
**入力検証(`security.cjs`)。** `gsd-core/bin/lib/security.cjs` モジュールは中心的なセキュリティユーティリティです。以下を提供します:
- パストラバーサル防止:ユーザー提供のファイルパス(`--text-file`、`--prd`)はプロジェクトディレクトリ内で解決されることを検証し、macOS の `/var` → `/private/var` シンリンク解決を明示的に処理
- プロンプトインジェクション検出:既知のインジェクションパターン(ロールオーバーライド、指示バイパス、システムタグインジェクション)が計画アーティファクトに入る前にユーザー提供テキストをスキャン
- 安全な JSON パース:クラフトされた JSON ペイロードによるプロトタイプ汚染攻撃を防ぐラッパー
- シェル引数検証:サブシェルコマンドに渡される引数の使用前検証
**ランタイムフック:`gsd-prompt-guard.js`。** このフックは `.planning/` ファイルを対象とするすべての Write または Edit 呼び出しで発火します。書き込まれるコンテンツを `security.cjs` と同じインジェクションパターンでスキャンします(サブセットがフックの独立性のために直接インライン化されています——フックはモジュールを `require()` しないため、モジュールパスが変わっても実行されます)。検出は **アドバイザリーのみ**:フックは発見をログに記録しますが書き込みをブロックしません。理由は、正当な計画書き込みでの偽陽性ブロックは、セカンダリスキャンレイヤーで見逃したインジェクションより破壊的だからです。
**ランタイムフック:`gsd-read-injection-scanner.js`。** このフックはすべての Read ツール呼び出しの出力で発火します。GSD がエージェントのコンテキストに組み込もうとしているファイルの *読み取ったばかりのコンテンツ* をスキャンし、攻撃者が命令を埋め込んでいるケースをキャッチします。
**CI スキャナー。** `prompt-injection-scan.security.test.cjs` はテストスイートの一部として、すべてのエージェント、ワークフロー、コマンドファイルに埋め込まれたインジェクションベクターをスキャンします。これは GSD ソース自体でのインジェクション試みをキャッチします——たとえば、ワークフローファイルにロールオーバーライド命令を追加するよう変更したサプライチェーン攻撃。
### Read Injection Scanner vs Prompt Guard
2 つのフックは補完的な面をカバーします。`gsd-prompt-guard.js` は *計画アーティファクトへの書き込み* を監視します——植え付けられているインジェクションをキャッチします。`gsd-read-injection-scanner.js` は *任意のファイルの読み取り* を監視します——外部コンテンツ(依存関係の README、サードパーティの設定ファイル、ユーザー提供のドキュメント)から取り込まれるインジェクションをキャッチします。合わせて、取り込み → 保存 → 再読み取りのライフサイクルを括ります。
---
## レイヤー 3 — リポジトリおよび依存関係の整合性
GSD のランタイム動作の上流で、`open-gsd` 組織はリポジトリおよびパッケージレベルで制御を強制しています。これらは [`docs/security/baseline.md`](../../security/baseline.md) に完全に記録されており、ここでは完全性のために要約します。
**依存関係の整合性。** すべてのサードパーティ依存関係は `package-lock.json` でピン留めされ、インストール前に公開されたチェックサムに対して検証されます。`scripts/check-npm-integrity.cjs` ゲートは CI 時に無効なバージョン、欠落パッケージ、余分なパッケージを検出します。これにより GSD 自身の依存関係に対する依存関係混同とタイポスクワッティング攻撃を軽減します。
**シークレットスキャン。** すべてのコミットと PR にはハードコードされたシークレットのスキャンが実施されます。意図的なテストフィクスチャは、プロジェクト標準の除外文法でアノテーションが必要です(アノテーション形式については `SECURITY.md` を参照)。アノテーションなしの抑制は CI を失敗させます。
**ロケールセーフなテキストスキャン。** 出力とユーザー向け文字列は、Unicode ホモグリフ、双方向オーバーライド文字、不可視の Unicode についてスキャンされます——CVE-2021-42574(「トロイの木馬ソース」)で記録された、差分に悪意のあるコンテンツを隠すことができる攻撃クラス。
---
## トレードオフと限界
ここで説明するセキュリティモデルは、AI 駆動開発の攻撃面を意味のある程度低減します。サプライチェーンリスクを排除するものではありません。
**パッケージ正当性ゲートが低減するもの:** 幻覚されたまたは攻撃者登録済みのパッケージが人間のチェックポイントなしに `npm install` に届く確率。`[SLOP]` ゲートは高信頼度の悪質なパッケージを完全に除去します;`[SUS]`/`[ASSUMED]` ゲートは実行前に人間のレビューを要求します。これによりスロップスクワッティング攻撃の成功コストが実質的に引き上げられます。
**パッケージ正当性ゲートが排除しないもの:** 後で侵害された正規パッケージ(アカウント乗っ取り、そのパッケージ自体のツリーでの依存関係混同)は、調査時に登録シグナルを確認するレジストリ API ゲートではキャッチされません。その種の攻撃に対するコントロールは、依存関係整合性レイヤーのロックファイルと `npm audit` です。
**プロンプトインジェクション防御が低減するもの:** 計画アーティファクト内のユーザー制御テキストがエージェントの指示を正常に上書きする確率。既知のインジェクション形式のパターンマッチングは一般的なケースをキャッチします;新しいジェイルブレイクや低シグナルのインジェクションは検出されない可能性があります。アドバイザリーのみの姿勢は、検出がログに記録されるがブロックされないことを意味します——検出でハード停止するコストではなく、ワークフロー継続性を保持する意図的な選択。
**プロンプトインジェクション防御が排除しないもの:** 既知のパターンにマッチしない十分に創造的なインジェクション、またはフックがカバーしないチャンネルを通じて届くインジェクション(たとえば、サブエージェントがドキュメントをブラウズする際に読み取る依存関係の公開 README にインジェクトされたコンテンツ)。多層防御は各レイヤーが攻撃を困難にすることを意味し、単一のレイヤーが不可能にすることを意味しません。
**脆弱性の報告。** `https://github.com/open-gsd/gsd-core/security/advisories/new` でプライベートな GitHub セキュリティアドバイザリを通じて報告してください。パブリックなイシューを開かないでください。対応タイムラインと開示ポリシーについては [SECURITY.md](../../../SECURITY.md) を参照してください。
---
## Related
- [コマンド](../COMMANDS.md) — セキュリティ関連フラグを含む `/gsd-secure-phase` と `/gsd-code-review`
- [アーキテクチャ § フックシステム](../ARCHITECTURE.md#hook-system) — すべてのフック、そのイベントトリガー、安全性プロパティの実装詳細
- [SECURITY.md](../../../SECURITY.md) — 脆弱性報告、組織全体のセキュリティベースライン、シークレットスキャン除外ガバナンス、依存関係整合性検証
- [ドキュメント索引](../README.md)