# Cursorのセキュリティ実践 — Project Rules・秘密情報・Auto-run権限・生成diffレビュー

> AIエディタCursorを本番で安全に使うガイド。Project Rulesにセキュリティ規約をコード化し、.cursorignoreとenvで秘密を載せず、Auto-run（YOLO）の権限境界を絞り、生成diffを認可観点で見て、CIにaegis ciで機械ゲートを敷く——Cursor固有の統制を体系化します。

- 公開日: 2026-07-07
- 著者: 友田 陽大
- タグ: セキュリティ, バイブコーディング, AI駆動開発, Next.js, Supabase
- URL: https://tomodahinata.com/blog/cursor-security-best-practices-rules-review-guide
- カテゴリ: バイブコーディング
- 総合ガイド: https://tomodahinata.com/blog/vibe-coding-what-is-tools-risks-production-guide

## 要点

- Cursorは速い『生成機』であって、セキュアな設計を保証する仕組みではない。安全に速く出すには、Cursor固有の統制を意図的に敷く必要がある
- Project Rules（.cursor/rules/*.mdc）にセキュリティ規約をコード化する。ただしルールは確率モデルへの誘導であって強制ではない——床を上げるが保証はしない
- .cursorignoreとenv衛生で秘密をコンテキストに載せない。ただし公式が『LLMの予測不能性ゆえ完全な保護は保証されない』と明言し、ターミナル/MCPは回避しうる——本当の境界は鍵の置き場所
- Auto-run（YOLO）の権限境界を絞る。既定は承認制で、ガードは『ベストエフォートであってハードな境界ではない』。破壊的・不可逆な操作は必ず人間ゲートに残す
- 生成diffは認可（縦のリスク）の観点でレビューし、最後にCIへ機械ゲート（aegis ci）を敷く。ルールとレビューは確率的、CIは決定的——この二段で速度と本番品質を両立する

---

最初に結論を述べます。**Cursorは驚くほど速い「生成機」であって、セキュアな設計を保証する仕組みではありません。** Cursorで安全に、かつ速く本番へ出すための鍵は、Cursor固有の統制を4つ意図的に敷き、その上に決定的なCIゲートを重ねることです——(1) **Project Rules**にセキュリティ規約をコード化する、(2) **.cursorignore と env 衛生**で秘密をコンテキストに載せない、(3) **Auto-run（YOLO）の権限境界**を絞る、(4) **生成diff を認可（縦のリスク）観点でレビュー**する。そして最後に、確率的な誘導であるこの4つを、**CIの機械ゲート（`aegis ci`）**で決定的に裏取りします。

この記事は、私が**一人 × 生成AI（Cursor / Claude Code）で、経済産業大臣賞を受賞したB2B SaaSや本番二重課金0件の決済基盤を作ってきた**実運用から、Cursor固有の設定と運用に絞って体系化したものです。抽象論ではなく、`.cursor/rules` に何を書くか、`.cursorignore` は何を守り**何を守らないか**、Auto-run の許可リストに何を入れ何を外すか、生成diff の何を最初に見るか——という具体に踏み込みます。

なお、AI生成コードの脆弱性を「買い手目線」で診断・ハードニングする体系は[AI生成コードの脆弱性診断（4層診断）](/blog/ai-generated-code-vulnerability-assessment-vibe-coding-security-guide)と[AIで作ったコードの本番化ハードニング](/blog/vibe-coding-ai-generated-code-production-hardening-guide)にまとめています。本記事はその「作り手が使うツール（Cursor）側」の実践編です。

---

## 1. 前提：Cursorは「生成機」であって「セキュリティの保証」ではない

まず、なぜCursor固有の統制が要るのかを明確にします。理由は**速度の非対称性**です。Cursorのエージェントは人間の数倍の速度でコードを書きますが、人間のレビューはその速度に追いつけません。レビューがボトルネックになるか、形骸化するかのどちらかです。だから「速く生成する」と「本番で漏れない」を両立させるには、生成のスピードを落とさずに、**機械的・構造的な統制**を生成ループの中に挟むしかありません。

ここで、セキュリティ対策を2種類に分けて考えると設計が澄みます。私が[Aegis](/aegis)で一貫して使っている区分です。

| 区分 | 中身 | 誰が持てるか |
|---|---|---|
| **水平の統制** | ヘッダー/CSP・レート制限・入力検証・CSRF・秘密情報衛生 | ライブラリ・設定が肩代わりできる（アプリ横断で一律に効く） |
| **縦のリスク** | 認可/IDOR・RLS設計・業務ロジック・テナント越境 | ライブラリには直せない（アプリ固有の「誰が何を所有するか」に依存） |

Cursorの設定でできることの多くは**水平**側です。Project Rules で規約を渡し、`.cursorignore` で秘密を隠し、Auto-run の権限を絞る——これらは「よくある罠」を踏む確率を下げます。しかし**縦のリスク**、とりわけ「認証はするが認可しない」という穴は、Cursorの設定では閉じられません。ここは生成diffのレビューと設計判断で閉じる領域です。この境界を最初に握っておくと、「Rulesを書いたから安全」という最悪の油断を避けられます。

---

## 2. Project Rules にセキュリティ規約をコード化する

Cursorの**Project Rules**は、`.cursor/rules/` に置く `.mdc` ファイルで、バージョン管理されるプロジェクト規約です（公式ドキュメントより）。ここにセキュリティ規約を書いておくと、エージェントが生成のたびにそれを文脈として参照します。会話に毎回書く必要がなくなり、規約が**永続化**されるのが本質的な価値です。

### 2.1 4つの適用方式を使い分ける

公式が定義する適用方式は4つです。セキュリティ規約は「常時適用」、SQL規約は「特定ファイルにだけ」——のように使い分けます。

| 適用方式 | 挙動 | セキュリティでの使いどころ |
|---|---|---|
| **Always Apply（常時）** | すべてのチャットに適用 | 秘密の扱い・認可の原則など、全体に効く憲法 |
| **Apply Intelligently（賢く）** | ルールのdescriptionを見てエージェントが関連性を判断 | 「認証を扱うとき」など文脈依存の規約 |
| **Apply to Specific Files（globで）** | globに一致するファイルで自動適用 | `supabase/migrations/**` にRLS規約、`app/api/**` にZod検証規約 |
| **Apply Manually（手動）** | `@`メンションした時だけ | 監査観点チェックリストなど、明示的に呼ぶもの |

`.md` ではなく `.mdc` 拡張子＋frontmatterが必要です（`.md` はルールとして認識されません）。

### 2.2 実際に書くセキュリティ規約（Next.js × Supabaseの例）

私が Next.js × Supabase 構成で置いている規約の骨子を、そのまま `.mdc` の形で示します。glob で `supabase/migrations/**` に効かせる例です。

```text
---
description: Supabase migration security rules — RLS ownership scope
globs: supabase/migrations/**/*.sql
alwaysApply: false
---

- すべてのユーザーデータテーブルに RLS を有効化する。migration に RLS を書かないテーブルを新設しない。
- SELECT/UPDATE/DELETE の USING は必ず所有者スコープ（例: auth.uid() = user_id）にする。
- USING (true) は「意図的に全員に公開するテーブル」でだけ許可し、コメントで意図を明記する。
- INSERT/UPDATE には WITH CHECK を必ず付け、書き込み先の所有者を強制する。
- SECURITY DEFINER 関数は必ず `SET search_path = ''`（または明示スキーマ）を付ける。
- anon ロールへの grant は最小化する。認証必須のテーブルに anon の権限を残さない。
```

アプリ側（`app/**`）には別ファイルで、こう置きます。

```text
---
description: App-layer security rules for AI-generated code
alwaysApply: true
---

- service_role キー / Service クライアントは server-only 境界の外で import しない。
  クライアントコンポーネントや共有ユーティリティから触らせない。
- ルートハンドラの入力は境界で Zod 検証する。未検証の req.body/searchParams を下流へ流さない。
- process.env を直接参照せず、型付き env モジュール経由でのみ読む。
- 秘密（API キー・トークン）をコードにハードコードしない。ログにも出さない。
- 認証済み ≠ 認可済み。行の取得・更新には必ず所有者スコープの WHERE / RLS を効かせる。
```

### 2.3 正直な限界：ルールは「強制」ではなく「誘導」

ここが最重要かつ、多くの記事が省く点です。**Project Rules は、確率的な言語モデルへの強い誘導であって、コンパイラのような強制ではありません。** 規約を書けば守られる「確率」は上がりますが、守られる「保証」はありません。エージェントはルールを無視することがあり、特に長い会話やコンテキストが逼迫した局面で無視率は上がります。

だから Rules は**床を上げる**ために使い、天井（本番に出せる保証）は別の仕組みで担保します。それが後述するCIの決定的ゲートです。この「確率的な誘導」と「決定的な強制」を分けて設計する思想は、[AI駆動開発の品質ゲート設計](/blog/ai-driven-development-quality-gates-ci-type-safety-test-security)で詳述しています。

---

## 3. 秘密情報をコンテキストに載せない（.cursorignore / env）

生成AIツールの最大の事故クラスのひとつが、**秘密情報のコンテキスト混入**です。`.env`・秘密鍵・顧客データがモデルへ送られる、あるいは生成コードにハードコードされて漏れる。Cursorには `.cursorignore` がありますが、**その効果と限界を正確に理解して使う**ことが肝心です。

### 3.1 .cursorignore と .cursorindexingignore の違い

| ファイル | 効果 | 用途 |
|---|---|---|
| **.cursorignore** | セマンティック検索・Tab補完・Agent・Inline Edit・`@`メンションからアクセスを**ブロック** | 秘密・認証情報・機微データを文脈から外す |
| **.cursorindexingignore** | インデックス（検索）から除外するだけ。AIからは依然アクセス可能 | 巨大な生成物やベンダーコードで検索結果を汚さない |

秘密を守る目的なら **`.cursorignore`** を使います（indexing の方は「アクセス遮断」ではありません）。最低限、以下を並べます。

```text
# .cursorignore — 秘密と機微データをコンテキストから外す
.env
.env.*
*.pem
*.key
*.p8
*.p12
**/credentials*
**/*secret*
supabase/.branches
.aws/
.ssh/
```

### 3.2 正直な限界：.cursorignore は「ハードな保証」ではない

公式ドキュメントが明言している通り、**「Cursorはignoreされたファイルをブロックするが、LLMの予測不能性ゆえ完全な保護は保証されない」**。さらに重要なのは、**エージェントのターミナルやMCPサーバー経由では、ignore対象のコードにアクセスされうる**という点です。つまり `.cursorignore` は露出を減らす実務的なフィルタであって、これ「だけ」を秘密の防御線にはできません。

では本当の境界はどこか。**鍵をどこに置くか**です。Supabaseの `service_role` キーは PostgreSQL の BYPASSRLS で動き、RLSを完全に無視します——だから守りの境界は「鍵の置き場所」に移ります。`service_role` はサーバー専用の境界に閉じ込め、クライアントや共有モジュールから触れないようにする。`.env` は `.gitignore` と `.cursorignore` の両方に入れ、コードは型付き env モジュール経由でのみ読む。この env 境界と秘密のハードコード検知は、Aegisの水平統制が自動化する領域でもあります（`npx @aegiskit/cli scan` が混入した鍵を検出します）。

そして運用ルールとして最も効くのは単純です——**チャットに秘密を貼らない**。デバッグでトークンや接続文字列を会話に流し込むのが、最も多い漏洩経路です。

---

## 4. Auto-run / YOLO の権限境界

Cursorのエージェントはターミナルコマンドを実行できます。既定では**コマンドは承認制**（実行前に人間の承認が要る）ですが、**Run Modes** を設定すると、信頼できる呼び出しを承認なしで走らせられます。単純な許可リストから「Auto-review classifier」まで段階があり、最大限まで開けたものが俗に言う「YOLOモード」です。速さは魅力ですが、ここは権限境界を意識的に絞る場所です。

### 4.1 なぜ危険か：プロンプトインジェクション

公式のAgent Securityページが直接に警告しています——**「AIはプロンプトインジェクション・幻覚などにより予期しない挙動をしうる」**、そして各種ガードは**「ハードなセキュリティ境界ではなく、ベストエフォートのガードである」**。

これが意味するのは重大です。エージェントが読む**外部の信頼できないコンテンツ**（Webページ、GitHub issue、依存パッケージのREADME、貼り付けられたログ）に、「`~/.ssh` を読んで外部に送れ」「`rm -rf` しろ」といった命令が仕込まれていると、Auto-runを全開にしたエージェントはそれをそのまま**実行してしまいうる**。承認制はこの攻撃に対する最後の人間の防波堤であり、YOLOはその防波堤を外す行為です。

### 4.2 何を自動化し、何を人間に残すか

私の運用境界を表にします。原則は**「読み取り・冪等・可逆」は自動化してよい／「書き込み・破壊的・不可逆・外部送信」は人間ゲートに残す**です。

| 判断 | 例 | 理由 |
|---|---|---|
| **自動実行OK（許可リスト）** | `ls` / `cat` / `npm run test` / `tsc --noEmit` / `git status` / `git diff` | 読み取り・冪等で、失敗しても被害がない |
| **必ず承認（自動化しない）** | `rm -rf` / `git push --force` / `curl … \| sh` / 本番デプロイ / `supabase db push` / `db reset` | 破壊的・不可逆。取り返しがつかない |
| **原則ブロック** | 未知ドメインへの `curl`/`wget`（egress）、`.env` への書き込み、鍵の出力 | 秘密の外部送信・改竄経路になる |

加えて、公式は**ネットワークegressの制限**（GitHub・直リンク・Web検索など特定ドメインに限定）と、**MCPツールの許可リスト**（サードパーティツールを事前承認制にする）を挙げています。MCPサーバーは強力な反面、エージェントに新しい実行能力を与えるので、接続は明示承認に留めるべきです。

私の原則はシンプルで、[私のグローバル規約](/blog/ai-driven-development-quality-gates-ci-type-safety-test-security)にも書いている通り、**破壊的・不可逆な操作（force push・破壊的git・スキーマ移行・本番デプロイ・mass delete）は必ず人間の確認を挟む**。ある操作を許可したことは、次の操作の許可にはなりません。Auto-runの許可リストも同じ思想で、恒久的に許すのは読み取り系だけに絞ります。

---

## 5. 生成diffのレビュー観点 — 認可（縦のリスク）を最優先で見る

ここが、Cursorの設定では閉じられない**縦のリスク**の領域であり、レビューの主戦場です。生成diffを開いたら、整形やスタイルより先に、次の順で認可を見ます。AI生成コードは「ハッピーパスは書けるが、他人のIDを指す正規リクエストを弾かない」——つまり**「認証はするが認可しない」**穴を作り込みやすいからです。

これは観測された事実でもあります。[Aegisの一次調査（フィールドスタディ）](/blog/supabase-rls-security-field-study)では、**公開Supabaseアプリ1,000件の一次調査で、RLSを持つアプリのうち約9.2%が『認証はするが行を所有者に絞らない』ポリシを持っていた（公開リポジトリ標本ゆえ下限値。所有者非スコープ＝即脆弱ではなく要確認）**。「認証済み」と「認可済み」がなぜ別物なのかは[Supabase RLS：authenticated と authorized の違い](/blog/supabase-rls-authenticated-vs-authorized-owner-scope-guide)で深掘りしています。

### 5.1 生成diffレビュー・チェックリスト

| 観点 | 見るもの | 危険なパターン |
|---|---|---|
| **所有者スコープ** | データ取得/更新に所有者の絞り込みがあるか | `.eq('id', params.id)` だけで `user_id` を見ていない → IDOR |
| **service_role境界** | 管理クライアントがサーバー境界の外へ漏れていないか | クライアント/共有モジュールでの `createClient(SERVICE_ROLE_KEY)` |
| **RLSのUSING** | `USING (true)` が意図した公開テーブルか | 個人データテーブルの無条件 `true` |
| **WITH CHECK** | INSERT/UPDATE に書き込み先の所有者強制があるか | `WITH CHECK` 欠落 → 他人名義での書き込み |
| **SECURITY DEFINER** | `search_path` が固定されているか | 未固定 → search_path 乗っ取り |
| **入力検証** | 境界でZod等の検証があるか | 未検証の `req.body` を下流やSQLへ流す |
| **秘密の混入** | 鍵/トークンのハードコード・ログ出力がないか | `const key = "sk_live_..."` |

上の3行（所有者スコープ・service_role境界・RLS）は、**ライブラリでは直せない設計判断**です。オブジェクト単位の認可欠陥（IDOR/BOLA）は[OWASP API Security Top 10で2019年以来ずっと第1位](https://owasp.org/API-Security/editions/2023/en/0xa1-broken-object-level-authorization/)の最頻出リスクであり、AIビルダー製アプリのRLS未設定が実際に**CVE-2025-48757（CVSS 9.3 CRITICAL）**として登録された事例もあります。「AIが書いたから大丈夫」は成立しません。ここは人間が設計として閉じる領域です。

---

## 6. CIに機械ゲートを敷く — aegis ci で決定的に裏取りする

これまでの4つ——Rules・ignore・Auto-run境界・diffレビュー——は、どれも**確率的**か**人間依存**です。Rulesはモデルが無視しうるし、レビューは見落とす。だから最後に、**決定的なゲート**を生成ループの外側（CI）に置いて、確率を保証に変えます。

流れはこうです。Cursorでいつも通り生成し、出荷前に静的スキャンを1枚挟み、CIで高信頼の検出だけをビルドブロックにします。

```bash
# 生成ループの中で（手元で）
npx @aegiskit/cli scan          # 統制の欠落と縦のリスクの疑いを洗い出す
npx @aegiskit/cli fix --format json   # 機械可読な修正計画をCursorに貼って直させる

# CI で（決定的ゲート）
npx @aegiskit/cli ci            # 高信頼の検出だけがビルドを失敗させ、SARIFをGitHubへ
```

`aegis` は**水平の統制（ヘッダー/CSP・レート制限・CSRF・型付きenv境界・秘密情報衛生）を自動化し**、ライブラリには直せない**縦のリスク（認可/IDOR・Supabase RLS設計）を検出して警告**します。特にSQLで書かれた認可境界——RLS未設定・`WITH CHECK`欠落・無条件`true`・anonへの過剰付与・`search_path`未固定の`SECURITY DEFINER`——をTypeScriptスキャナが構造的に見えない領域まで検証するのが要点です。

ただし、正直なスコープを最初に明記します。**Aegisは「完全に守る」とは言いません。** クリーンな結果は「よくある罠は踏んでいない」であって「このコードは安全だ」ではない。認可が「正しい」ことは証明しません。だから縦のリスクは検出・警告に留め、閉じるのは第5節のレビューと設計判断に返します。この二段——**確率的なRules/レビューで床を上げ、決定的なCIゲートで天井を担保する**——が、Cursorの速度を本番品質と両立させる背骨です。この検証ゲートの全体設計は[Spec駆動開発の本番ワークフロー](/blog/spec-driven-development-claude-code-ai-agent-production-workflow)にまとめています。

---

## 7. まとめ — Cursorを「速いまま安全に」する5層

最後に、この記事の統制を1枚に畳みます。上4層は確率的・人間依存で「床を上げ」、最下層のCIが決定的に「天井を担保する」——この非対称を理解して設計するのが肝心です。

| 層 | 手段 | 性質 | 閉じるリスク |
|---|---|---|---|
| 1. 規約のコード化 | `.cursor/rules/*.mdc` | 確率的（誘導） | 水平の統制・原則の徹底 |
| 2. 秘密の隔離 | `.cursorignore` + env境界 + 鍵の置き場所 | ベストエフォート＋境界設計 | 秘密の混入・漏洩 |
| 3. 権限境界 | Auto-run許可リスト（読み取りのみ自動化） | 人間ゲート | 破壊的操作・プロンプトインジェクション |
| 4. 生成diffレビュー | 認可チェックリスト | 人間判断 | 縦のリスク（IDOR・RLS設計） |
| 5. CIの機械ゲート | `aegis ci`（+型・テスト・静的解析） | 決定的（強制） | 再発防止・高信頼の実害 |

Cursorは強力なツールです。しかし「入れたから安全」なツールなど存在せず、そう謳うものはむしろ危険です。速度を落とさずに安全に出す唯一の道は、生成のスピードはそのままに、**この5層を意図的に敷く**こと。まずは手元のプロジェクトで `npx @aegiskit/cli scan`（[Aegis](/aegis)・無料・MIT）を走らせ、いま何が空いているかを可視化するところから始めてください。そして検出された「縦のリスク」を実際に塞ぐ設計レビューが必要なら、私が承ります。
