laravel-security-agent 1.2.1 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  > *"Your friendly capybara keeping your Laravel app safe."*
6
6
 
7
- A one-command security toolkit for Laravel projects. Capi Guard installs AI-powered security audit agents, hardens your `.gitignore`, adds a pre-commit hook, and provides an **autonomous Antigravity PHP Agent** compatible with GitHub Copilot Skills.
7
+ A one-command security toolkit for Laravel projects. Run it once and Capi Guard automatically deploys AI-powered security agents into **Claude Code**, **GitHub Copilot**, and **Google Gemini/Antigravity** plus hardens your project with a pre-commit hook and `.gitignore` rules.
8
8
 
9
9
  ## Usage
10
10
 
@@ -14,46 +14,55 @@ Run at the root of your Laravel project:
14
14
  npx laravel-security-agent
15
15
  ```
16
16
 
17
- Capi Guard will ask what you want to install and handle everything interactively.
17
+ No prompts. Everything installs automatically.
18
18
 
19
- ## Installation Options
19
+ ## What Gets Installed
20
20
 
21
- You can install any combination of the following:
21
+ ### Global AI Agents (user-level, one-time)
22
22
 
23
- | Option | What it installs | Best for |
24
- |--------|-----------------|----------|
25
- | **Claude Code rules** | `SECURITY.md` | Claude Code CLI users |
26
- | **Copilot rules** | `.github/copilot-instructions.md` | Copilot Editor users |
27
- | **Update .gitignore** | Enforces Laravel security patterns | Preventing secret leaks |
28
- | **Pre-commit hook** | Blocks commits of sensitive keys | CI/CD discipline |
29
- | **Antigravity Agent** | Complete PHP 8.3 Agent + Copilot Skills | **Advanced Autonomous Security** |
23
+ | Platform | What installs | Where |
24
+ |---|---|---|
25
+ | **Claude Code** | `capi-guard` skill | `~/.claude/skills/capi-guard/SKILL.md` |
26
+ | **GitHub Copilot** | `.agent.md` sub-agents | `.github/agents/` |
27
+ | **Gemini / Google Antigravity** | Capi Guard instruction block | `~/.gemini/GEMINI.md` |
28
+
29
+ After install, just ask your AI to "audit security" it knows the full workflow and all 4 callable skills.
30
+
31
+ ### Project Files
32
+
33
+ | File | Purpose |
34
+ |---|---|
35
+ | `SECURITY.md` | Claude Code security agent rules |
36
+ | `.github/copilot-instructions.md` | Copilot security agent rules |
37
+ | `.gitignore` entries | Blocks `deploy.php`, `.env`, SSH keys |
38
+ | `.git/hooks/pre-commit` | Blocks commits of sensitive files |
39
+ | **Antigravity PHP Agent** | Full autonomous agent in `app/Agents/` |
30
40
 
31
41
  ---
32
42
 
33
43
  ## 🤖 The Antigravity Agent (PHP)
34
44
 
35
- This is the flagship feature. When you select the **Antigravity Agent**, Capi Guard scaffolds a production-ready, zero-trust AI agent directly into your Laravel `app/` directory.
36
-
37
- It exposes an API endpoint (`/api/agent/invoke`) that GitHub Copilot can call to perform **deterministic, local code analysis** natively in PHP.
45
+ The flagship feature. Capi Guard scaffolds a production-ready, zero-trust AI agent directly into your Laravel `app/` directory. It exposes `/api/agent/invoke` — an endpoint that any AI can call to run **deterministic, local PHP analysis** without sending your codebase to the cloud.
38
46
 
39
47
  ### Available Skills
40
48
 
41
- Copilot uses these skills to analyze your code instantly without sending your entire codebase to the LLM:
49
+ | Skill | What it does |
50
+ |---|---|
51
+ | 🔍 **vulnerabilityScan** | Regex scan across 13 security categories in any path |
52
+ | 🛡️ **analyzeAuthFlow** | PHP Reflection traces controllers, finds missing `authorize()` calls |
53
+ | 🩹 **applySecurityPatch** | Applies CVE patches with backup + runs Artisan commands post-patch |
54
+ | 🧹 **sanitizeGitHistory** | Generates a `git filter-repo` script to purge secrets from full git history |
42
55
 
43
- 1. 🔍 **vulnerabilityScan**: Uses Regex to scan 13 security categories across any directory.
44
- 2. 🛡️ **analyzeAuthFlow**: Uses PHP Reflection to trace controllers and detect missing `$this->authorize()` calls.
45
- 3. 🩹 **applySecurityPatch**: Applies surgical CVE patches and automatically runs Artisan commands afterwards (`optimize:clear`, `test`, etc).
46
- 4. 🧹 **sanitizeGitHistory**: Generates a `git filter-repo` script with a blob-callback to purge old `.env` files and redact naked passwords/IPs from your *entire* Git history commits.
56
+ ### Copilot Sub-Agents
47
57
 
48
- ### Copilot Sub-Agents Included
58
+ Four specialised agents are installed into `.github/agents/`:
49
59
 
50
- The installer also copies 3 specialised Copilot Agents into `.github/agents/`. You can invoke them in the Copilot Chat:
60
+ - `@capi-guard` Full-stack auditor. Runs scans, analyzes auth, patches files.
61
+ - `@patch-aplicado` — Surgical CVE patcher with backup and Artisan validation.
62
+ - `@auth-guard` — Read-only analyst. Finds authorization gaps and suggests Policies.
63
+ - `@git-sanitizer` — Git history auditor and scrubber.
51
64
 
52
- - `@capi-guard` — Full stack auditor. Runs scans, analyzes auth, and patches files following a strict 6-step workflow.
53
- - `@patch-aplicado` — Surgical CVE patcher. Always creates a backup, runs the patch, and validates with Artisan.
54
- - `@auth-guard` — Read-only analyst. Only reads code to find authorization gaps and suggest Policies.
55
-
56
- ### How to configure the Agent
65
+ ### Agent Setup
57
66
 
58
67
  1. Add the route to `routes/api.php`:
59
68
  ```php
@@ -63,40 +72,38 @@ The installer also copies 3 specialised Copilot Agents into `.github/agents/`. Y
63
72
  Route::post("/api/agent/invoke", AgentController::class)
64
73
  ->middleware(["auth:sanctum", ZeroTrustMiddleware::class]);
65
74
  ```
66
- 2. Issue a Sanctum token with the `agent:invoke` ability for Copilot.
75
+ 2. Issue a Sanctum token with the `agent:invoke` ability.
67
76
  3. Register `.github/manifest.json` in your GitHub Copilot Extension settings.
68
- 4. *(Optional)* Publish the config file to edit CVE patches and rate limits:
77
+ 4. *(Optional)* Publish the config to customize CVE patches and rate limits:
69
78
  ```bash
70
79
  php artisan vendor:publish --tag=security-agent-config
71
80
  ```
72
81
 
73
82
  ---
74
83
 
75
- ## The Passive Rules (Claude & Copilot)
76
-
77
- If you just want instructions for your AI without the full PHP agent, install `SECURITY.md` or `.github/copilot-instructions.md`.
84
+ ## Security Categories Audited
78
85
 
79
- When you ask the AI to "audit security", it will check for 13 categories including:
86
+ When you ask any AI to "audit security", it checks 13 categories:
80
87
 
81
88
  | Category | What gets checked |
82
- |----------|---------------|
89
+ |---|---|
83
90
  | **IDOR** | Policies, `authorize()`, ownership scoping |
84
91
  | **SQL Injection** | Raw queries, dynamic `orderBy` whitelisting |
85
92
  | **Mass Assignment** | Empty `$guarded`, role escalation via `$request->all()` |
93
+ | **XSS** | `{!! !!}` in Blade, `v-html` in Vue |
94
+ | **CSRF** | Exclusions in `VerifyCsrfToken`, unprotected POST routes |
95
+ | **Authorization** | Missing `Gate::authorize()` in controllers |
86
96
  | **File Uploads** | `mimetypes:` vs `mimes:`, private storage, server-side naming |
87
- | **CSRF & XSS** | Exclusions in `VerifyCsrfToken`, `v-html` usage |
88
- | **Git secrets** | `APP_DEBUG`, `.env` in history, hardcoded credentials |
89
-
90
- ## Pre-commit hook & .gitignore
91
-
92
- The `.gitignore` updater enforces patterns for `deploy.php`, `auth.json`, e `.phpunit.result.cache`.
93
- The pre-commit hook automatically blocks attempts to `git commit` any `.env` file, `.pem`, `.p12`, or `.key` file.
97
+ | **Rate Limiting** | Public endpoints without throttle middleware |
98
+ | **Security Headers** | Missing CSP, X-Frame-Options, HSTS |
99
+ | **Credentials in Code** | Hardcoded secrets and API keys |
100
+ | **Git Secrets** | `.env`, `deploy.php`, SSH keys in git history |
94
101
 
95
102
  ## Requirements
96
103
 
97
- - Node.js 18+ (to run the npx command)
104
+ - Node.js 18+
98
105
  - Laravel project (`composer.json` at the root)
99
- - *For the Agent:* PHP 8.2+ and Laravel Sanctum
106
+ - *For the PHP Agent:* PHP 8.2+ and Laravel Sanctum
100
107
 
101
108
  ## License
102
109
 
package/bin/index.js CHANGED
@@ -1,15 +1,18 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- intro, outro, multiselect, confirm,
3
+ intro, outro, confirm,
4
4
  spinner, note, cancel, isCancel
5
5
  } from '@clack/prompts';
6
- import { existsSync } from 'node:fs';
6
+ import { existsSync, readFileSync } from 'node:fs';
7
7
  import { join } from 'node:path';
8
+ import { homedir } from 'node:os';
8
9
  import { copySecurity } from '../src/copy-security.js';
9
10
  import { copyCopilot } from '../src/copy-copilot.js';
10
11
  import { applyGitignore } from '../src/update-gitignore.js';
11
12
  import { installHook } from '../src/install-hook.js';
12
13
  import { copyAgent } from '../src/copy-agent.js';
14
+ import { deployClaudeSkill } from '../src/deploy-claude-skill.js';
15
+ import { deployGemini } from '../src/deploy-gemini.js';
13
16
 
14
17
  const cwd = process.cwd();
15
18
 
@@ -23,22 +26,7 @@ if (!existsSync(join(cwd, 'composer.json'))) {
23
26
  );
24
27
  }
25
28
 
26
- const options = await multiselect({
27
- message: 'What would you like to install?',
28
- initialValues: ['claude', 'copilot', 'gitignore', 'hook'],
29
- options: [
30
- { value: 'claude', label: 'SECURITY.md', hint: 'Claude Code security agent' },
31
- { value: 'copilot', label: '.github/copilot-instructions.md', hint: 'GitHub Copilot security agent' },
32
- { value: 'gitignore',label: 'Update .gitignore', hint: 'protects deploy.php, .env, SSH keys' },
33
- { value: 'hook', label: 'Pre-commit hook', hint: 'blocks commits of sensitive files' },
34
- { value: 'agent', label: 'Antigravity Agent (PHP)', hint: 'Copilot Skills + PHP 8.3 agent classes' },
35
- ],
36
- });
37
-
38
- if (isCancel(options)) {
39
- cancel('Installation cancelled.');
40
- process.exit(0);
41
- }
29
+ const options = ['claude', 'copilot', 'gitignore', 'hook', 'agent'];
42
30
 
43
31
  const s = spinner();
44
32
 
@@ -102,6 +90,48 @@ if (options.includes('hook')) {
102
90
  : '✔ pre-commit hook installed at .git/hooks/pre-commit');
103
91
  }
104
92
 
93
+ // --- Claude Code skill ---
94
+ {
95
+ const dest = join(homedir(), '.claude', 'skills', 'capi-guard', 'SKILL.md');
96
+ let overwrite = false;
97
+
98
+ if (existsSync(dest)) {
99
+ const answer = await confirm({
100
+ message: '~/.claude/skills/capi-guard/SKILL.md already exists. Overwrite?',
101
+ initialValue: false,
102
+ });
103
+ if (isCancel(answer)) { cancel('Cancelled.'); process.exit(0); }
104
+ overwrite = answer;
105
+ }
106
+
107
+ s.start('Deploying Capi Guard skill to Claude Code...');
108
+ const result = deployClaudeSkill(undefined, overwrite);
109
+ s.stop(result.skipped
110
+ ? '~/.claude/skills/capi-guard/SKILL.md kept (not overwritten)'
111
+ : '✔ Capi Guard skill installed at ~/.claude/skills/capi-guard/SKILL.md');
112
+ }
113
+
114
+ // --- Gemini / Google Antigravity ---
115
+ {
116
+ const dest = join(homedir(), '.gemini', 'GEMINI.md');
117
+ let overwrite = false;
118
+
119
+ if (existsSync(dest) && readFileSync(dest, 'utf8').includes('<!-- capi-guard -->')) {
120
+ const answer = await confirm({
121
+ message: '~/.gemini/GEMINI.md already has Capi Guard block. Overwrite?',
122
+ initialValue: false,
123
+ });
124
+ if (isCancel(answer)) { cancel('Cancelled.'); process.exit(0); }
125
+ overwrite = answer;
126
+ }
127
+
128
+ s.start('Deploying Capi Guard to Gemini / Google Antigravity...');
129
+ const result = deployGemini(undefined, overwrite);
130
+ s.stop(result.skipped
131
+ ? '~/.gemini/GEMINI.md kept (not overwritten)'
132
+ : '✔ Capi Guard block appended to ~/.gemini/GEMINI.md');
133
+ }
134
+
105
135
  // --- Antigravity Agent (PHP) ---
106
136
  if (options.includes('agent')) {
107
137
  let overwrite = false;
@@ -123,19 +153,24 @@ if (options.includes('agent')) {
123
153
  : `✔ Antigravity agent installed (${result.copied.length} files → app/Agents/, app/Skills/, app/Http/, config/, .github/)`);
124
154
  }
125
155
 
126
- const nextSteps = [];
127
- if (options.includes('claude')) nextSteps.push('Claude Code: say "audit security" or "run SECURITY.md"');
128
- if (options.includes('copilot')) nextSteps.push('Copilot: .github/copilot-instructions.md is loaded automatically');
129
- if (options.includes('agent')) nextSteps.push(
130
- 'Antigravity Agent:\n' +
131
- ' 1. Add route: Route::post("/api/agent/invoke", AgentController::class)->middleware(["auth:sanctum", ZeroTrustMiddleware::class]);\n' +
132
- ' 2. Issue a Sanctum token with ability "agent:invoke"\n' +
133
- ' 3. Register .github/manifest.json in your Copilot Extension settings\n' +
134
- ' 4. Optionally run: php artisan vendor:publish --tag=security-agent-config'
135
- );
156
+ const nextSteps = [
157
+ 'Claude Code: the "capi-guard" skill is now available — just ask Claude to audit security',
158
+ 'Gemini CLI: Capi Guard instructions are active in ~/.gemini/GEMINI.md',
159
+ 'Copilot: .github/copilot-instructions.md and .github/agents/ are installed automatically',
160
+ ];
161
+
162
+ if (options.includes('agent')) {
163
+ nextSteps.push(
164
+ 'Antigravity Agent (PHP backend):\n' +
165
+ ' 1. Add route: Route::post("/api/agent/invoke", AgentController::class)->middleware(["auth:sanctum", ZeroTrustMiddleware::class]);\n' +
166
+ ' 2. Issue a Sanctum token with ability "agent:invoke"\n' +
167
+ ' 3. Register .github/manifest.json in your Copilot Extension settings\n' +
168
+ ' 4. Optionally run: php artisan vendor:publish --tag=security-agent-config'
169
+ );
170
+ }
136
171
 
137
172
  if (nextSteps.length > 0) {
138
- note(nextSteps.join('\n'), 'Next step');
173
+ note(nextSteps.join('\n'), 'Next steps');
139
174
  }
140
175
 
141
176
  const capybara = `
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "laravel-security-agent",
3
- "version": "1.2.1",
3
+ "version": "1.3.0",
4
4
  "description": "Capi Guard — a security audit agent for Laravel projects",
5
5
  "type": "module",
6
6
  "bin": {
@@ -13,9 +13,9 @@
13
13
  "public"
14
14
  ],
15
15
  "scripts": {
16
- "test": "node --test test/copy-security.test.js test/update-gitignore.test.js test/install-hook.test.js test/copy-copilot.test.js test/copy-agent.test.js",
16
+ "test": "node --test test/copy-security.test.js test/update-gitignore.test.js test/install-hook.test.js test/copy-copilot.test.js test/copy-agent.test.js test/deploy-claude-skill.test.js test/deploy-gemini.test.js",
17
17
  "start": "node bin/index.js",
18
- "prepublishOnly": "node --test test/copy-security.test.js test/update-gitignore.test.js test/install-hook.test.js test/copy-copilot.test.js test/copy-agent.test.js"
18
+ "prepublishOnly": "node --test test/copy-security.test.js test/update-gitignore.test.js test/install-hook.test.js test/copy-copilot.test.js test/copy-agent.test.js test/deploy-claude-skill.test.js test/deploy-gemini.test.js"
19
19
  },
20
20
  "dependencies": {
21
21
  "@clack/prompts": "^0.9.1"
@@ -0,0 +1,28 @@
1
+ // src/deploy-claude-skill.js
2
+ import { existsSync, copyFileSync, mkdirSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { homedir } from 'node:os';
6
+
7
+ const __dirname = fileURLToPath(new URL('.', import.meta.url));
8
+ const SKILL_TEMPLATE = join(__dirname, '../templates/claude-skill/SKILL.md');
9
+
10
+ /**
11
+ * Deploy the Capi Guard skill to the user's Claude Code skills directory.
12
+ *
13
+ * @param {string} [homeDir] Override home directory (for testing).
14
+ * @param {boolean} [overwrite] Whether to overwrite an existing skill file.
15
+ * @returns {{ skipped: boolean, path: string }}
16
+ */
17
+ export function deployClaudeSkill(homeDir = homedir(), overwrite = false) {
18
+ const skillDir = join(homeDir, '.claude', 'skills', 'capi-guard');
19
+ const dest = join(skillDir, 'SKILL.md');
20
+
21
+ if (existsSync(dest) && !overwrite) {
22
+ return { skipped: true, path: dest };
23
+ }
24
+
25
+ mkdirSync(skillDir, { recursive: true });
26
+ copyFileSync(SKILL_TEMPLATE, dest);
27
+ return { skipped: false, path: dest };
28
+ }
@@ -0,0 +1,48 @@
1
+ // src/deploy-gemini.js
2
+ import { existsSync, readFileSync, writeFileSync, appendFileSync, mkdirSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { homedir } from 'node:os';
6
+
7
+ const __dirname = fileURLToPath(new URL('.', import.meta.url));
8
+ const GEMINI_TEMPLATE = join(__dirname, '../templates/gemini.md');
9
+
10
+ const OPEN_MARKER = '<!-- capi-guard -->';
11
+ const CLOSE_MARKER = '<!-- /capi-guard -->';
12
+
13
+ /**
14
+ * Append (or re-append) the Capi Guard block to the user's ~/.gemini/GEMINI.md.
15
+ *
16
+ * Idempotent: if the marker is already present and overwrite is false, skip.
17
+ * When overwrite is true, the old block is stripped and the fresh template is appended.
18
+ *
19
+ * @param {string} [homeDir] Override home directory (for testing).
20
+ * @param {boolean} [overwrite]
21
+ * @returns {{ skipped: boolean, path: string }}
22
+ */
23
+ export function deployGemini(homeDir = homedir(), overwrite = false) {
24
+ const geminiDir = join(homeDir, '.gemini');
25
+ const dest = join(geminiDir, 'GEMINI.md');
26
+ const template = readFileSync(GEMINI_TEMPLATE, 'utf8');
27
+
28
+ const existing = existsSync(dest) ? readFileSync(dest, 'utf8') : '';
29
+
30
+ if (existing.includes(OPEN_MARKER)) {
31
+ if (!overwrite) return { skipped: true, path: dest };
32
+
33
+ // Strip old block (everything between markers, inclusive)
34
+ const stripped = existing.replace(
35
+ new RegExp(`${OPEN_MARKER}[\\s\\S]*?${CLOSE_MARKER}`, 'g'),
36
+ ''
37
+ ).trimEnd();
38
+
39
+ mkdirSync(geminiDir, { recursive: true });
40
+ writeFileSync(dest, stripped + '\n' + template + '\n');
41
+ return { skipped: false, path: dest };
42
+ }
43
+
44
+ mkdirSync(geminiDir, { recursive: true });
45
+ const prefix = existing && !existing.endsWith('\n') ? '\n' : '';
46
+ appendFileSync(dest, prefix + template + '\n');
47
+ return { skipped: false, path: dest };
48
+ }
@@ -4,26 +4,55 @@ import { join } from 'node:path';
4
4
 
5
5
  export const DEFAULT_ENTRIES = [
6
6
  '',
7
- '# laravel-security-agent (Capi Guard)',
7
+ '# ── Capi Guard — security rules ──────────────────────────────────────',
8
+ '',
9
+ '# Environment',
10
+ '# .env.example is safe: commit it with key names but empty values',
11
+ '# (APP_KEY=, DB_PASSWORD=) — never commit the real .env',
8
12
  '.env',
9
13
  '.env.*',
10
14
  '!.env.example',
15
+ '',
16
+ '# Deployment — often contain server IPs, SSH passwords, sudo commands',
11
17
  'deploy.php',
12
18
  'deployer.php',
19
+ 'deployer.json',
20
+ '.deploy/',
21
+ '',
22
+ '# Cryptographic keys and certificates',
13
23
  '*.pem',
14
24
  '*.key',
15
25
  '*.p12',
16
26
  '*.pfx',
27
+ '*.jks',
28
+ '*.keystore',
17
29
  'id_rsa',
30
+ 'id_rsa.pub',
18
31
  'id_ed25519',
32
+ 'id_ed25519.pub',
33
+ '',
34
+ '# Credential and token stores',
35
+ 'auth.json',
36
+ '',
37
+ '# Docker local overrides — often include server IPs and passwords',
38
+ 'docker-compose.override.yml',
39
+ 'docker-compose.local.yml',
40
+ '',
41
+ '# Database dumps — contain raw user data and credentials',
42
+ '*.sql',
43
+ '*.sql.gz',
44
+ '*.dump',
45
+ '',
46
+ '# Laravel runtime artifacts',
47
+ '/.phpunit.result.cache',
48
+ '/storage/debugbar/',
19
49
  ];
20
50
 
21
51
  export function buildLinesToAdd(existingContent, entries) {
52
+ const existingLines = new Set(existingContent.split('\n').map(l => l.trim()));
22
53
  return entries.filter(entry => {
23
- // Always include structural lines (blank lines and comments)
24
- if (entry === '' || entry.startsWith('#')) return true;
25
- const lines = existingContent.split('\n').map(l => l.trim());
26
- return !lines.includes(entry.trim());
54
+ if (entry === '') return true; // always keep blank lines for formatting
55
+ return !existingLines.has(entry.trim()); // deduplicate comments and entries alike
27
56
  });
28
57
  }
29
58
 
@@ -0,0 +1,88 @@
1
+ ---
2
+ name: capi-guard
3
+ description: Laravel security audit agent for Capi Guard. Invoke to scan for vulnerabilities, analyze auth flows, and apply CVE patches.
4
+ ---
5
+
6
+ # Capi Guard 🐾 — Laravel Security Skill
7
+
8
+ You are **Capi Guard**, a security audit agent for Laravel projects.
9
+
10
+ ## LANGUAGE
11
+
12
+ Detect the language of the user's message and respond entirely in that language.
13
+
14
+ ## REQUIRED BEHAVIOR
15
+
16
+ 1. NEVER modify code without asking the user first.
17
+ 2. For each issue found, present:
18
+ - File and line where the problem is
19
+ - Why it is a risk (category: IDOR, SQL Injection, Mass Assignment, XSS, CSRF, etc.)
20
+ - What you intend to do to fix it
21
+ - Wait for explicit approval before editing.
22
+ 3. If you find multiple issues, list ALL of them first, then ask which ones to fix and in what order.
23
+ 4. After each fix, show the diff and confirm.
24
+
25
+ ## SECURITY CATEGORIES TO AUDIT
26
+
27
+ - **IDOR** — direct object references without ownership checks
28
+ - **SQL Injection** — raw DB queries with user input
29
+ - **Mass Assignment** — missing `$fillable` / `$guarded` on models
30
+ - **XSS** — unescaped `{!! !!}` in Blade, `v-html` in Vue
31
+ - **CSRF** — missing `@csrf` on forms, unprotected POST routes
32
+ - **Authorization** — missing `$this->authorize()` in controllers
33
+ - **File Upload** — missing MIME validation, storing in public/
34
+ - **Rate Limiting** — public endpoints without throttle middleware
35
+ - **Credentials in Code** — hardcoded secrets, keys committed to git
36
+ - **Security Headers** — missing CSP, X-Frame-Options, HSTS
37
+ - **Git Secrets** — `.env`, `deploy.php`, SSH keys in history
38
+
39
+ ## CALLABLE SKILLS
40
+
41
+ When deeper analysis is needed, invoke the Capi Guard PHP backend via `POST /api/agent/invoke` (requires a Sanctum Bearer token with the `agent:invoke` ability):
42
+
43
+ - **`vulnerabilityScan`** `{ path: string }` — static analysis across 13 security categories on the given path (e.g. `"app/Http/Controllers"`). Returns findings sorted by severity.
44
+ - **`analyzeAuthFlow`** `{ controller: string }` — inspects a controller's public methods via PHP Reflection, detecting missing `$this->authorize()` or `Gate::authorize()` calls.
45
+ - **`applySecurityPatch`** `{ cveId: string, filePath: string }` — looks up the CVE in `config/security-agent.php`, creates a timestamped backup, applies the patch, and runs `php artisan optimize:clear`.
46
+ - **`sanitizeGitHistory`** `{ backupBranch?: string, dryRun?: boolean, repoPath?: string, generateScriptPath?: string }` — two-phase audit and scrub of secrets across full git history. Defaults to dry-run; always verifies a backup branch before rewriting.
47
+
48
+ See `.github/manifest.json` for the full OpenAPI spec.
49
+
50
+ ## MANDATORY WORKFLOW
51
+
52
+ When invoked for any security task, execute **in this order**:
53
+
54
+ ### 1. Reconnaissance
55
+ - List affected controllers
56
+ - Map related routes in `routes/web.php` and `routes/api.php`
57
+ - Identify models, policies, and middleware in scope
58
+
59
+ ### 2. Static Analysis
60
+ - Scan each in-scope file for the categories above
61
+ - Note: file path, line number, category, severity (critical / important / suggestion)
62
+
63
+ ### 3. Report
64
+ - Present ALL findings before touching any file
65
+ - Group by severity: critical → important → suggestion
66
+ - For each finding: location, risk explanation, proposed fix
67
+
68
+ ### 4. Await Approval
69
+ - Ask which issues to fix and in what order
70
+ - Do NOT proceed until the user confirms
71
+
72
+ ### 5. Apply Fixes
73
+ - Fix one issue at a time
74
+ - Show a diff after each change
75
+ - Confirm before moving to the next
76
+
77
+ ## SCOPE
78
+
79
+ Act **only** on:
80
+ - PHP files in `app/`, `routes/`, `config/`, `bootstrap/`
81
+ - `.env.example` (never `.env`)
82
+ - Blade templates in `resources/views/`
83
+ - Vue/JS files only for `v-html` checks
84
+
85
+ Do NOT alter:
86
+ - Already-executed migrations
87
+ - `vendor/`
88
+ - Test files (read-only)
@@ -0,0 +1,26 @@
1
+ <!-- capi-guard -->
2
+ ## Capi Guard 🐾 — Laravel Security Agent
3
+
4
+ You have the Capi Guard security skill installed for this project.
5
+
6
+ When the user asks about security, vulnerabilities, or anything related to the Laravel project's safety:
7
+
8
+ 1. **Never modify code without asking first.**
9
+ 2. Scan for: IDOR, SQL Injection, Mass Assignment, XSS, CSRF, missing authorization, file upload risks, rate limiting gaps, hardcoded credentials, security headers, and secrets in git history.
10
+ 3. Present ALL findings before touching any file. Group by severity.
11
+ 4. Wait for explicit approval before applying any fix.
12
+ 5. Show a diff after each change and confirm before continuing.
13
+
14
+ **Scope:** `app/`, `routes/`, `config/`, `bootstrap/`, `resources/views/`, `.env.example`. Never touch `vendor/`, `.env`, already-executed migrations, or test files (read-only).
15
+
16
+ ## Callable Skills
17
+
18
+ Call the Capi Guard PHP backend via `POST /api/agent/invoke` (Sanctum Bearer token, ability `agent:invoke`):
19
+
20
+ - **`vulnerabilityScan`** `{ path }` — static analysis across 13 categories
21
+ - **`analyzeAuthFlow`** `{ controller }` — finds missing `authorize()` calls via PHP Reflection
22
+ - **`applySecurityPatch`** `{ cveId, filePath }` — applies CVE patches with backup + Artisan post-run
23
+ - **`sanitizeGitHistory`** `{ backupBranch?, dryRun?, repoPath?, generateScriptPath? }` — audits and scrubs secrets from git history
24
+
25
+ Full spec: `.github/manifest.json`.
26
+ <!-- /capi-guard -->