@vibefoundry/vibe-shield 1.1.1 โ†’ 2.0.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.
Files changed (35) hide show
  1. package/README.md +31 -11
  2. package/SKILL.md +26 -93
  3. package/dist/bin/vibe-shield.d.ts +1 -1
  4. package/dist/bin/vibe-shield.js +38 -11
  5. package/dist/src/init/scaffold.d.ts +1 -1
  6. package/dist/src/init/scaffold.js +26 -93
  7. package/dist/src/mcp/server.js +5 -1
  8. package/dist/src/mcp-guard/skill-auditor.js +11 -3
  9. package/dist/src/reporter/console-reporter.js +14 -0
  10. package/dist/src/reporter/executive.d.ts +4 -0
  11. package/dist/src/reporter/executive.js +58 -0
  12. package/dist/src/reporter/formatters.d.ts +1 -1
  13. package/dist/src/reporter/formatters.js +10 -3
  14. package/dist/src/reporter/patch-prompt-writer.js +3 -3
  15. package/dist/src/scanner/attack-surface.d.ts +4 -0
  16. package/dist/src/scanner/attack-surface.js +50 -0
  17. package/dist/src/scanner/engine.d.ts +2 -3
  18. package/dist/src/scanner/engine.js +21 -39
  19. package/dist/src/scanner/mappings.d.ts +17 -0
  20. package/dist/src/scanner/mappings.js +39 -0
  21. package/dist/src/scanner/redact.d.ts +1 -0
  22. package/dist/src/scanner/redact.js +12 -0
  23. package/dist/src/scanner/rules/hardening.d.ts +5 -0
  24. package/dist/src/scanner/rules/hardening.js +116 -0
  25. package/dist/src/scanner/rules/helpers.js +2 -0
  26. package/dist/src/scanner/rules/index.js +6 -0
  27. package/dist/src/scanner/rules/response-hardening.d.ts +2 -0
  28. package/dist/src/scanner/rules/response-hardening.js +120 -0
  29. package/dist/src/scanner/rules/secret-entropy.js +0 -2
  30. package/dist/src/scanner/types.d.ts +33 -1
  31. package/dist/src/scanner/types.js +6 -2
  32. package/dist/src/scanner/version.d.ts +2 -0
  33. package/dist/src/scanner/version.js +69 -0
  34. package/dist/src/secrets/patterns.js +40 -0
  35. package/package.json +99 -99
package/README.md CHANGED
@@ -14,7 +14,7 @@ vibe-shield is a **static security scanner built for that failure mode**, plus a
14
14
  [![node](https://img.shields.io/badge/node-%E2%89%A518.17.0-5fa04e?style=flat-square&logo=nodedotjs)](#-requirements)
15
15
  [![license](https://img.shields.io/github/license/avivgerz-hue/vibe-shield?style=flat-square&color=blue)](./LICENSE)
16
16
  [![zero dependencies](https://img.shields.io/badge/runtime%20deps-0-brightgreen?style=flat-square)](./package.json)
17
- [![rules](https://img.shields.io/badge/detection%20signatures-60-8b5cf6?style=flat-square)](./src/scanner/rules)
17
+ [![rules](https://img.shields.io/badge/detection%20signatures-91-8b5cf6?style=flat-square)](./src/scanner/rules)
18
18
  [![self-scan](https://img.shields.io/badge/self--scan-100%2F100%20A%2B-16a34a?style=flat-square)](#-it-scans-itself)
19
19
 
20
20
  ```bash
@@ -27,6 +27,26 @@ npx -y @vibefoundry/vibe-shield scan
27
27
 
28
28
  ---
29
29
 
30
+ ## v2.0.0: eight defensive vectors
31
+
32
+ The v2 catalogue covers client exposure; auth and route protection; database/RLS; AI and web sinks; infrastructure; dependency hygiene; secrets and cryptography; and agent/MCP integrity. The new hardening checks include production source maps, insecure JWT settings, explicit and omitted cookie flags, locally absent security headers, container users, lifecycle scripts, lockfiles and weak cryptography. Run `rules` for the complete catalogue.
33
+
34
+ The scanner produces a heuristic **attack-surface inventory** of route methods, observed guard signals, SQL tables and RLS signals, AI entrypoints, and MCP/agent files. Header checks cover recognized server configuration files; cookie checks cover common literal setter options. Both are advisory: external middleware, deployment settings and dynamic options require review. Signals do not prove guards or policies work, and code outside the scanned scope is not assessed. Run `audit-skills` separately for agent-integrity checks.
35
+
36
+ Generate an executive report or agent remediation prompt explicitly:
37
+
38
+ ```bash
39
+ npx -y @vibefoundry/vibe-shield scan --report SECURITY-REPORT.md --patch-prompt PATCH-PROMPT.md
40
+ npx -y @vibefoundry/vibe-shield scan --format html --out security-report.html
41
+ npx -y @vibefoundry/vibe-shield audit-skills --report agent-report.html
42
+ ```
43
+
44
+ Reports include severity, CWE, locations, snippets, OWASP 2025 web mappings for every rule and contextual LLM mappings when applicable, and illustrative remediation. Examples are **not** automatic project-specific patches; validate them against the application. The scanner itself is offline and read-only by default; `--cache`, `--out`, `--report`, `--patch-prompt` and `init` explicitly write files. Installing with `npx` can require network access. An A+ score applies only to the rules and files examined and is not a security certification.
45
+
46
+ > The source tree targets v2.0.0; the npm commands acquire the published version, which may lag this branch until a release is published. To exercise this checkout locally, run `npm ci && npm run build`, then `node dist/bin/vibe-shield.js` with the same arguments.
47
+
48
+ ---
49
+
30
50
  ## The problem, in one file
31
51
 
32
52
  This is the shape of code an agent writes when you ask for "a delete endpoint":
@@ -45,7 +65,7 @@ It works. It also has **three critical vulnerabilities** โ€” no authentication,
45
65
  `npx -y @vibefoundry/vibe-shield scan` catches all three in **17 milliseconds**:
46
66
 
47
67
  ```
48
- ๐Ÿ›ก๏ธ vibe-shield v1.0.0 ยท security scan
68
+ ๐Ÿ›ก๏ธ vibe-shield ยท security scan (illustrative output)
49
69
  target /home/you/app
50
70
 
51
71
  ๐Ÿ’€ GRADE F โ€” 0/100 ยท 3 critical
@@ -61,7 +81,7 @@ app/api/users/route.ts
61
81
  await db.query(`DELETE FROM users WHERE id = ${id} AND owner = ${userId}`);
62
82
  CRITICAL 4:22 VSB-AUTH-004 Record ownership taken from the request instead of the session (IDOR)
63
83
 
64
- 7 files ยท 1 KiB ยท 412 files/s ยท 17 ms ยท 48 rules
84
+ 7 files ยท 1 KiB ยท 412 files/s ยท 17 ms ยท 79 rules
65
85
 
66
86
  โš  3 critical findings โ€” rotate any exposed credential before anything else.
67
87
  Fix it npx -y @vibefoundry/vibe-shield scan --fix-prompt # writes SECURITY_PATCH_PROMPT.md for your agent
@@ -126,13 +146,13 @@ Traditional SAST rules are built around human mistakes: a forgotten escape, a mi
126
146
  | writes `CREATE TABLE` | writes `CREATE TABLE` **and forgets the `ENABLE ROW LEVEL SECURITY`**, so the anon key reads everything |
127
147
  | adds `dangerouslySetInnerHTML` to render a doc | renders **model output** with it, creating stored XSS with a step counter |
128
148
 
129
- vibe-shield encodes those specific shapes: 60 signatures across five families, each one derived from a real agent-generated bug rather than a generic CWE checklist.
149
+ vibe-shield encodes those specific shapes: 91 signatures across eight defensive categories, each one derived from a real agent-generated bug rather than a generic CWE checklist.
130
150
 
131
151
  ---
132
152
 
133
153
  ## ๐Ÿ“Š Vulnerability Coverage Matrix
134
154
 
135
- **48 code signatures + 12 agent-integrity signatures = 60.** Every rule has an id, a CWE, a vulnerable example, a fixed example, and ordered remediation steps โ€” run `npx -y @vibefoundry/vibe-shield rules` or `npx -y @vibefoundry/vibe-shield explain <ID>`.
155
+ **79 code signatures + 12 agent-integrity signatures = 91.** Every rule has an id, a CWE, an illustrative vulnerable shape, remediation guidance, and an OWASP association โ€” run `npx -y @vibefoundry/vibe-shield rules` or `npx -y @vibefoundry/vibe-shield explain <ID>`.
136
156
 
137
157
  ### Client-side secret & data exposure โ€” `VSB-CLIENT-*`
138
158
 
@@ -243,7 +263,7 @@ Three tools:
243
263
 
244
264
  | Tool | What it does |
245
265
  | --- | --- |
246
- | `vibe_shield_scan` | Runs the 60 rules over a project or specific paths โ†’ grade, score, findings with file:line, CWE and remediation |
266
+ | `vibe_shield_scan` | Runs the code-scanning rules over a project or specific paths โ†’ grade, score, findings with file:line, CWE and remediation |
247
267
  | `vibe_shield_audit_skills` | Audits `.claude/skills`, `.cursor` rules, `AGENTS.md` and MCP configs for prompt injection and exfiltration traps |
248
268
  | `vibe_shield_explain_rule` | Full CWE detail, vulnerable/fixed examples and remediation for any rule id or slug |
249
269
 
@@ -254,7 +274,7 @@ Three tools:
254
274
  {
255
275
  "mcpServers": {
256
276
  "github": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-github"] },
257
- "vibe-shield": { "command": "npx", "args": ["--yes", "@vibefoundry/vibe-shield@1.1.0", "mcp"] }
277
+ "vibe-shield": { "command": "npx", "args": ["--yes", "@vibefoundry/vibe-shield@1.1.1", "mcp"] }
258
278
  }
259
279
  }
260
280
  ```
@@ -392,12 +412,12 @@ This repository runs its own gate on every commit and in CI:
392
412
 
393
413
  ```console
394
414
  $ npx -y @vibefoundry/vibe-shield scan
395
- ๐Ÿ›ก๏ธ vibe-shield v1.0.0 ยท security scan
415
+ ๐Ÿ›ก๏ธ vibe-shield ยท security scan (illustrative output)
396
416
  target /you/vibe-shield
397
417
 
398
418
  ๐Ÿ† GRADE A+ โ€” 100/100
399
419
 
400
- 21 files ยท 172 KiB ยท 236 files/s ยท 89 ms ยท 48 rules
420
+ 21 files ยท 172 KiB ยท 236 files/s ยท 89 ms ยท 79 rules
401
421
 
402
422
  Nothing to fix. Keep the shield up. ๐Ÿ›ก๏ธ
403
423
 
@@ -441,7 +461,7 @@ Suppressed findings are **counted and reported** in the scorecard, never silentl
441
461
  ```
442
462
  discover โ”€โ”€โ–ถ project context โ”€โ”€โ–ถ rule gate โ”€โ”€โ–ถ detect โ”€โ”€โ–ถ suppress โ”€โ”€โ–ถ score โ”€โ”€โ–ถ report
443
463
  โ”‚ โ”‚ โ”‚ โ”‚
444
- โ”‚ โ”‚ โ”‚ โ””โ”€ 60 rules, each a pure (FileContext) => RuleHit[]
464
+ โ”‚ โ”‚ โ”‚ โ””โ”€ 91 rules, each a pure (FileContext) => RuleHit[]
445
465
  โ”‚ โ”‚ โ””โ”€ cheap content hints: most rules skip most files
446
466
  โ”‚ โ””โ”€ manifests, framework flags, cross-file RLS index, git index, middleware matchers
447
467
  โ””โ”€ one tree walk, gitignore/.vibe-shieldignore layering, binary + size + test/doc pruning
@@ -471,7 +491,7 @@ vibe-shield version | help
471
491
 
472
492
  | Flag | Default | Meaning |
473
493
  | --- | --- | --- |
474
- | `--format <fmt>` | `console` | `console` `compact` `summary` `json` `sarif` `github` |
494
+ | `--format <fmt>` | `console` | `console` `compact` `summary` `json` `sarif` `github` `markdown` `html` |
475
495
  | `--fail-on <sev>` | `critical` | Exit 1 at/above this severity |
476
496
  | `--severity <sev>` | โ€” | Only report at/above this severity |
477
497
  | `--fix-prompt` | off | Write `SECURITY_PATCH_PROMPT.md` |
package/SKILL.md CHANGED
@@ -1,124 +1,57 @@
1
1
  ---
2
2
  name: vibe-shield
3
- description: Audit any change for AI-introduced security bugs (leaked keys, unguarded API routes, disabled Row Level Security, SQL injection, prompt injection, poisoned MCP servers) and fix them before reporting a task as done. Use whenever you write or modify application code, API routes, server actions, database migrations, auth logic, environment variables, LLM calls, webhook handlers, agent skills or MCP configuration.
3
+ description: Apply a six-phase defensive security review to changes affecting applications, APIs, data, AI agents, and MCP configuration. Use static evidence, preserve behavior, and report limitations.
4
4
  allowed-tools: Bash(npx -y @vibefoundry/vibe-shield scan*), Bash(npx -y @vibefoundry/vibe-shield audit-skills*), Bash(npx -y @vibefoundry/vibe-shield explain*), Read(./**), Grep, Glob
5
5
  license: MIT
6
6
  metadata:
7
7
  author: VibeFoundry
8
8
  homepage: https://github.com/avivgerz-hue/vibe-shield
9
- version: 1.0.0
9
+ version: 2.0.0
10
10
  ---
11
11
 
12
- # vibe-shield
12
+ # Defensive AppSec architect protocol
13
13
 
14
- You are not allowed to say "done" until the code you just wrote passes a security audit.
14
+ Work only within the authorized project. Static findings are evidence for review, not proof of exploitability or a guarantee of safety. Do not transmit source code or secrets. Ask before changing production services, rotating credentials, or making destructive changes.
15
15
 
16
- AI coding agents ship a specific, repeatable class of vulnerability: a `SUPABASE_SERVICE_ROLE_KEY` behind a `NEXT_PUBLIC_` prefix, a `DELETE` route handler with no session check, a `CREATE TABLE` with no `ENABLE ROW LEVEL SECURITY`, a tool whose `execute` forwards model output into `exec`. These are not exotic โ€” they are the default shape of code written quickly by something optimising for "it works". This skill is the second pair of eyes.
16
+ ## Phase 1: Attack-surface reconnaissance
17
17
 
18
- ## When to run
18
+ Map entrypoints and trust boundaries: API methods, authentication and authorization, middleware matchers, database tables and policies, storage, LLM inputs and tools, webhooks, and agent/MCP configuration. Check deployment configuration and exclusions. Identify what the scanner cannot see.
19
19
 
20
- Run the audit **after every change that touches**:
21
-
22
- - an API route, route handler, server action, RPC endpoint or GraphQL mutation
23
- - authentication, session, role, permission or ownership logic
24
- - a database migration, policy, grant, schema or Supabase table
25
- - an environment variable, config file, `.env*` file or build config
26
- - anything calling an LLM, a tool, a webhook, a shell command or the filesystem
27
- - `.claude/`, `.cursor/`, `AGENTS.md`, `mcp.json` or any skill/config file
28
-
29
- If you did not touch any of those, you do not need to run it.
30
-
31
- ## The loop
20
+ ## Phase 2: Automated static scan and skill audit
32
21
 
33
22
  ```bash
34
- # 1. Scan (a whole-repo scan finishes in well under a second)
35
- npx -y @vibefoundry/vibe-shield scan --fail-on high
36
-
37
- # 2. If it fails, generate the machine-readable fix list
38
- npx -y @vibefoundry/vibe-shield scan --fix-prompt
39
-
40
- # 3. Read SECURITY_PATCH_PROMPT.md and fix every finding, critical first
41
- # Each entry has the exact file:line, the vulnerable snippet, the CWE and
42
- # the required change. Apply it literally.
43
-
44
- # 4. Re-run until it exits 0
45
- npx -y @vibefoundry/vibe-shield scan --fail-on high
23
+ npx -y @vibefoundry/vibe-shield scan . --format json
24
+ npx -y @vibefoundry/vibe-shield audit-skills . --format json
46
25
  ```
47
26
 
48
- `--fail-on high` exits non-zero while any high or critical finding exists. That is the gate.
49
-
50
- ## Reading a finding
51
-
52
- ```
53
- CRITICAL 47:15 VSB-CLIENT-001 Server-only secret exposed through a public environment prefix
54
- const key = process.env.NEXT_PUBLIC_OPENAI_API_KEY;
55
- ```
27
+ Inspect findings, inventory, ignored paths, and the files scanned. The explicit `.` includes test and documentation files: review fixtures as examples rather than blindly changing them. Use `explain <RULE_ID>` to investigate a rule. These commands run locally; first-time installation with npx requires registry access.
56
28
 
57
- | Part | Meaning |
58
- | --- | --- |
59
- | `47:15` | exact line and column to edit |
60
- | `VSB-CLIENT-001` | rule id โ€” use it with `explain` for full docs |
61
- | message | why this specific line is exploitable |
62
- | `(CWE-200)` | bug class, for a deeper search if the fix is unclear |
29
+ ## Phase 3: Deep contextual threat modeling
63
30
 
64
- Need the full picture? `npx -y @vibefoundry/vibe-shield explain VSB-CLIENT-001` prints the vulnerable shape, the fixed shape, remediation steps and references.
31
+ Trace untrusted input through authentication, ownership checks and tenant boundaries to database, filesystem, network, HTML, and LLM sinks. Inspect IDOR, business-logic bypasses, webhook signature verification and asynchronous jobs. Check cross-file guards and deployed database policies; absence of a static finding is not evidence of protection.
65
32
 
66
- ## Hard rules
33
+ ## Phase 4: Surgical zero-regression remediation
67
34
 
68
- 1. **Fix the root cause.** Never delete an auth check, disable RLS, silence a log or add a catch-all `catch {}` to make the finding disappear.
69
- 2. **Never suppress.** Do not add `// vibe-shield-disable`, do not edit `.vibe-shieldignore`, do not pass `--ignore`. Suppression is a decision for the human.
70
- 3. **Rotate exposed credentials.** If the scan reported a live key, tell the user to rotate it at the provider in the same message. Removing the line does not un-leak it โ€” the value may already be in a bundle, a cache or a git history.
71
- 4. **Report honestly.** If you cannot fix a finding (you need a decision, a credential or a provider change), say so explicitly, name the rule id, and stop.
72
- 5. **Re-verify.** A fix is not finished until the gate exits 0.
35
+ - On Next.js mutation routes, authenticate the session on the server and authorize the target resource against the session principal before writes. Do not trust identity from request bodies.
36
+ - Enable Supabase RLS and write action-specific policies using the authenticated principal; test both permitted and denied tenants before deploying migrations.
37
+ - Validate inputs at the boundary with a schema such as Zod, then use parameterized database queries. Treat LLM output as untrusted.
38
+ - Use explicit CORS allowlists, secure cookie flags and a CSP appropriate for the application. Test login, redirects, and browser behavior.
39
+ - Report exposed credentials to the owner for provider-side rotation; avoid reproducing their values in reports. Do not suppress findings or weaken controls to obtain a higher score. Ask for missing business or deployment decisions.
73
40
 
74
- ## Agent surface audit
41
+ ## Phase 5: Verification gate
75
42
 
76
- When you add or modify a skill, rule file, MCP server or instruction file, also run:
43
+ Run project tests and both audits again. Aim for 100/100 Grade A+ with no high or critical findings, but report any unresolved finding, exclusion, false positive, or verification limitation honestly rather than claiming success. Never equate a clean score with a complete security assessment.
77
44
 
78
45
  ```bash
79
- npx -y @vibefoundry/vibe-shield audit-skills
46
+ npx -y @vibefoundry/vibe-shield scan --fail-on high
47
+ npx -y @vibefoundry/vibe-shield audit-skills --fail-on high
80
48
  ```
81
49
 
82
- Twelve `VSB-AGENT-*` rules check for hidden Unicode (zero-width and bidi characters used to smuggle instructions past review), `curl`/`wget` exfiltration of environment variables, credential-harvesting instructions (`.env`, `~/.ssh`, `~/.aws`), registry-tag or remote MCP servers, literal tokens in an `env` block, safety-override language, over-broad tool permissions, base64 `eval` payloads, remote-instruction fetching, wildcard `allowed-tools`, and shell injection in skill scripts.
83
-
84
- Each finding carries a `triage` field: `block` means refuse and escalate, `review` means ask the user, `report` means mention it and continue. Do not blanket-refuse a repository because a rule fired โ€” read the triage.
85
-
86
- ## Flags worth knowing
50
+ ## Phase 6: Executive security sign-off
87
51
 
88
- | Flag | Effect |
89
- | --- | --- |
90
- | `--format json` | full machine-readable report (schemaVersion 1) |
91
- | `--format sarif` | SARIF 2.1.0 for GitHub code scanning |
92
- | `--format compact` | one line per finding |
93
- | `--format github` | inline GitHub Actions annotations |
94
- | `--severity high` | only report high and critical |
95
- | `--fail-on medium` | stricter gate |
96
- | `--include-tests` | include test and fixture files |
97
- | `--cache` | reuse results between runs |
98
- | `--quiet` | one-line verdict (ideal for piping) |
99
- | `rules` | list every rule |
100
- | `explain <RULE_ID>` | full documentation for one rule |
101
-
102
- If the repository has a `.mcp.json`, the same three capabilities are also
103
- available as MCP tools โ€” `vibe_shield_scan`, `vibe_shield_audit_skills` and
104
- `vibe_shield_explain_rule`. Prefer those when they are listed, because they
105
- return structured findings instead of text you have to parse.
106
-
107
- ## Definition of done
108
-
109
- - [ ] `npx -y @vibefoundry/vibe-shield scan --fail-on high` exits `0`
110
- - [ ] `npx -y @vibefoundry/vibe-shield audit-skills` exits `0` if you touched agent files
111
- - [ ] every credential the scan surfaced has been flagged to the user for rotation
112
- - [ ] no suppression directive was added
113
- - [ ] the feature still works and the existing tests still pass
114
-
115
- ## Install it into a repository
52
+ Produce a Markdown or HTML report with scope, inventory, risks prioritized by severity, evidence, actions, test results and remaining uncertainty. Illustrative code examples are not project-specific patches; review and adapt them. Obtain human approval before deployment or provider-side action.
116
53
 
117
54
  ```bash
118
- npx -y @vibefoundry/vibe-shield init
55
+ npx -y @vibefoundry/vibe-shield scan --report SECURITY-REPORT.md --patch-prompt PATCH-PROMPT.md
56
+ npx -y @vibefoundry/vibe-shield audit-skills --report AGENT-REPORT.html
119
57
  ```
120
-
121
- That writes this file to `.claude/skills/vibe-shield/SKILL.md`, appends a security
122
- gate section to `AGENTS.md`, adds a `.cursor/rules/vibe-shield.mdc`, and installs a
123
- GitHub Actions workflow that fails the pull request on new high or critical
124
- findings. Every future task in that repository starts guarded.
@@ -32,7 +32,7 @@ export declare const defaultIo: () => CliIo;
32
32
  export declare const EXIT_OK = 0;
33
33
  export declare const EXIT_FINDINGS = 1;
34
34
  export declare const EXIT_USAGE = 2;
35
- declare const HELP = "vibe-shield \u2014 security scanner for AI-generated code\n\nUSAGE\n vibe-shield <command> [options]\n\nCOMMANDS\n scan [paths...] Scan the project (default: current directory).\n audit-skills [paths...] Audit agent skills, Cursor rules, AGENTS.md and MCP configs.\n init Install the Agent Skill, AGENTS.md section and CI workflow.\n rules List every detection rule.\n explain <RULE_ID> Show full documentation for a rule.\n mcp Serve the Model Context Protocol tools over stdio.\n version Print the version.\n help Print this help.\n\nSCAN OPTIONS\n --format <fmt> console | compact | summary | json | sarif | github (console)\n --out <file> Write the report to a file instead of stdout.\n --fix-prompt Write SECURITY_PATCH_PROMPT.md with exact fix instructions.\n --fail-on <severity> Exit 1 when a finding at/above this severity exists. (critical)\n --severity <severity> Only report findings at/above this severity.\n --rules <ids> Comma-separated rule ids/slugs (supports VSB-DB-*).\n --ignore <glob> Extra gitignore-style pattern (repeatable).\n --include-tests Include test, spec and fixture files.\n --include-docs Include Markdown and docs/.\n --cache Reuse .vibe-shield-cache.json between runs.\n --max-findings <n> Limit the console list (0 = all). (50)\n --quiet Print only the verdict line and the exit code.\n --no-color Disable ANSI colour.\n --no-shield-ignore Ignore .vibe-shieldignore (e.g. to scan excluded fixtures).\n --json Shorthand for --format json.\n\nINIT OPTIONS\n --target <dir> Repository to install into. (cwd)\n --agent <kind> claude | cursor | generic | all. (all)\n --no-workflow Skip the GitHub Actions workflow.\n --force Overwrite existing files.\n --yes Accepted for non-interactive CI use (init never prompts).\n\nEXAMPLES\n npx -y @vibefoundry/vibe-shield scan\n npx -y @vibefoundry/vibe-shield scan --fail-on high --format github\n npx -y @vibefoundry/vibe-shield scan --fix-prompt\n npx -y @vibefoundry/vibe-shield init\n npx -y @vibefoundry/vibe-shield explain VSB-DB-001\n npx -y @vibefoundry/vibe-shield audit-skills .claude\n";
35
+ declare const HELP = "vibe-shield \u2014 security scanner for AI-generated code\n\nUSAGE\n vibe-shield <command> [options]\n\nCOMMANDS\n scan [paths...] Scan the project (default: current directory).\n audit-skills [paths...] Audit agent skills, Cursor rules, AGENTS.md and MCP configs.\n init Install the Agent Skill, AGENTS.md section and CI workflow.\n rules List every detection rule.\n explain <RULE_ID> Show full documentation for a rule.\n mcp Serve the Model Context Protocol tools over stdio.\n version Print the version.\n help Print this help.\n\nSCAN OPTIONS\n --format <fmt> console | compact | summary | json | sarif | github | markdown | html\n --out <file> Write the report to a file.\n --report <file> Write a report (format inferred from extension).\n --patch-prompt <file> Write a remediation prompt to this file.\n --fix-prompt Write SECURITY_PATCH_PROMPT.md with exact fix instructions.\n --fail-on <severity> Exit 1 when a finding at/above this severity exists. (critical)\n --severity <severity> Only report findings at/above this severity.\n --rules <ids> Comma-separated rule ids/slugs (supports VSB-DB-*).\n --ignore <glob> Extra gitignore-style pattern (repeatable).\n --include-tests Include test, spec and fixture files.\n --include-docs Include Markdown and docs/.\n --cache Reuse .vibe-shield-cache.json between runs.\n --max-findings <n> Limit the console list (0 = all). (50)\n --quiet Print only the verdict line and the exit code.\n --no-color Disable ANSI colour.\n --no-shield-ignore Ignore .vibe-shieldignore (e.g. to scan excluded fixtures).\n --json Shorthand for --format json.\n\nINIT OPTIONS\n --target <dir> Repository to install into. (cwd)\n --agent <kind> claude | cursor | generic | all. (all)\n --no-workflow Skip the GitHub Actions workflow.\n --force Overwrite existing files.\n --yes Accepted for non-interactive CI use (init never prompts).\n\nEXAMPLES\n npx -y @vibefoundry/vibe-shield scan\n npx -y @vibefoundry/vibe-shield scan --fail-on high --format github\n npx -y @vibefoundry/vibe-shield scan --fix-prompt\n npx -y @vibefoundry/vibe-shield init\n npx -y @vibefoundry/vibe-shield explain VSB-DB-001\n npx -y @vibefoundry/vibe-shield audit-skills .claude\n";
36
36
  interface ParsedArgs {
37
37
  command: string;
38
38
  positionals: string[];
@@ -94,8 +94,10 @@ COMMANDS
94
94
  help Print this help.
95
95
 
96
96
  SCAN OPTIONS
97
- --format <fmt> console | compact | summary | json | sarif | github (console)
98
- --out <file> Write the report to a file instead of stdout.
97
+ --format <fmt> console | compact | summary | json | sarif | github | markdown | html
98
+ --out <file> Write the report to a file.
99
+ --report <file> Write a report (format inferred from extension).
100
+ --patch-prompt <file> Write a remediation prompt to this file.
99
101
  --fix-prompt Write ${patch_prompt_writer_1.PATCH_PROMPT_FILENAME} with exact fix instructions.
100
102
  --fail-on <severity> Exit 1 when a finding at/above this severity exists. (critical)
101
103
  --severity <severity> Only report findings at/above this severity.
@@ -130,6 +132,7 @@ const BOOLEAN_FLAGS = new Set([
130
132
  // `--mcp` is an alias for the `mcp` subcommand, so `npx -y
131
133
  // @vibefoundry/vibe-shield --mcp` works the way most MCP clients expect.
132
134
  'mcp',
135
+ 'version',
133
136
  'fix-prompt',
134
137
  'include-tests',
135
138
  'include-docs',
@@ -150,6 +153,8 @@ const BOOLEAN_FLAGS = new Set([
150
153
  const VALUE_FLAGS = new Set([
151
154
  'format',
152
155
  'out',
156
+ 'report',
157
+ 'patch-prompt',
153
158
  'fail-on',
154
159
  'severity',
155
160
  'rules',
@@ -236,9 +241,10 @@ async function emitReport(result, io, options, parsed) {
236
241
  if (noColor)
237
242
  color.enabled = false;
238
243
  let patchPath = null;
239
- if (options.fixPrompt) {
244
+ if (options.fixPrompt || flagString(parsed, 'patch-prompt')) {
240
245
  patchPath = await (0, patch_prompt_writer_1.writePatchPrompt)(result, {
241
246
  outDir: io.cwd,
247
+ fileName: flagString(parsed, 'patch-prompt'),
242
248
  minSeverity: ((0, types_1.isSeverity)(flagString(parsed, 'severity')) ? flagString(parsed, 'severity') : 'info'),
243
249
  });
244
250
  }
@@ -262,11 +268,17 @@ async function emitReport(result, io, options, parsed) {
262
268
  if (patchPath) {
263
269
  write(io, 'stderr', `\n๐Ÿ“ Wrote ${path.relative(io.cwd, patchPath) || patchPath} โ€” hand it to your agent, or run \`npx -y @vibefoundry/vibe-shield scan\` after fixing.\n`);
264
270
  }
265
- if (options.out) {
266
- const target = path.resolve(io.cwd, options.out);
271
+ const reportPath = flagString(parsed, 'report');
272
+ const outputPath = reportPath ?? options.out;
273
+ if (outputPath) {
274
+ const target = path.resolve(io.cwd, outputPath);
267
275
  const { promises: fs } = await Promise.resolve().then(() => __importStar(require('node:fs')));
268
- await fs.writeFile(target, (0, formatters_1.formatResult)(result, options.format === 'console' ? 'json' : options.format), 'utf8');
269
- write(io, 'stderr', `๐Ÿ“„ Report written to ${options.out}\n`);
276
+ const inferred = { '.md': 'markdown', '.markdown': 'markdown', '.html': 'html', '.sarif': 'sarif', '.json': 'json' }[path.extname(outputPath).toLowerCase()];
277
+ const fileFormat = reportPath && !flagString(parsed, 'format') ? inferred : options.format === 'console' ? 'json' : options.format;
278
+ if (!fileFormat)
279
+ throw new Error('Cannot infer report format from extension; use --format.');
280
+ await fs.writeFile(target, (0, formatters_1.formatResult)(result, fileFormat), 'utf8');
281
+ write(io, 'stderr', `๐Ÿ“„ Report written to ${outputPath}\n`);
270
282
  }
271
283
  }
272
284
  /* -------------------------------------------------------------------------- */
@@ -300,9 +312,15 @@ async function commandScan(parsed, io) {
300
312
  write(io, 'stderr', `vibe-shield: no such file or directory: ${missing.join(', ')}\n`);
301
313
  return exports.EXIT_USAGE;
302
314
  }
315
+ // For a single directory outside cwd, report paths relative to that project,
316
+ // and discover its own config, middleware and migrations.
317
+ const target = parsed.positionals.length === 1 ? path.resolve(io.cwd, parsed.positionals[0]) : '';
318
+ const outside = target && (path.relative(io.cwd, target) === '..' || path.relative(io.cwd, target).startsWith(`..${path.sep}`));
319
+ const externalRoot = outside ? ((0, node_fs_1.statSync)(target).isDirectory() ? target : path.dirname(target)) : undefined;
320
+ const externalPaths = externalRoot ? [path.relative(externalRoot, target) || '.'] : undefined;
303
321
  const result = await (0, engine_1.scanProject)({
304
- rootDir: io.cwd,
305
- paths: parsed.positionals.length ? parsed.positionals : undefined,
322
+ rootDir: externalRoot ?? io.cwd,
323
+ paths: externalPaths ?? (parsed.positionals.length ? parsed.positionals : undefined),
306
324
  rules,
307
325
  ignorePatterns: (flagString(parsed, 'ignore') ?? '').split('\n').filter(Boolean),
308
326
  // `undefined` means "use the engine default" (which is: include everything
@@ -346,8 +364,12 @@ async function commandAuditSkills(parsed, io) {
346
364
  write(io, 'stderr', `vibe-shield: --fail-on expects one of: critical, high, medium, low, info\n`);
347
365
  return exports.EXIT_USAGE;
348
366
  }
349
- const result = await (0, skill_auditor_1.auditSkills)(io.cwd, {
350
- paths: parsed.positionals.length ? parsed.positionals : undefined,
367
+ const target = parsed.positionals.length === 1 ? path.resolve(io.cwd, parsed.positionals[0]) : '';
368
+ const relative = target ? path.relative(io.cwd, target) : '';
369
+ const outside = relative === '..' || relative.startsWith(`..${path.sep}`);
370
+ const externalRoot = outside && (0, node_fs_1.existsSync)(target) && (0, node_fs_1.statSync)(target).isDirectory() ? target : undefined;
371
+ const result = await (0, skill_auditor_1.auditSkills)(externalRoot ?? io.cwd, {
372
+ paths: externalRoot ? undefined : parsed.positionals.length ? parsed.positionals : undefined,
351
373
  version: await (0, engine_1.packageVersion)(),
352
374
  });
353
375
  await emitReport(result, io, {
@@ -414,6 +436,7 @@ function commandRules(parsed, io) {
414
436
  severity: rule.severity,
415
437
  confidence: rule.confidence,
416
438
  cwe: rule.cwe.id,
439
+ owasp: rule.owasp,
417
440
  description: rule.description,
418
441
  remediation: rule.remediation,
419
442
  references: rule.references,
@@ -470,6 +493,10 @@ function commandExplain(parsed, io) {
470
493
  out.push(` ${color.cyan(reference)}`);
471
494
  out.push('');
472
495
  out.push(color.dim(`CWE: ${rule.cwe.name} โ€” ${rule.cwe.url}`));
496
+ if (rule.owasp?.web)
497
+ out.push(color.dim(`OWASP: ${rule.owasp.web.id} ${rule.owasp.web.name} (${rule.owasp.web.basis})`));
498
+ if (rule.owasp?.llm.length)
499
+ out.push(color.dim(`OWASP LLM: ${rule.owasp.llm.map(m => `${m.id} ${m.name}`).join(', ')} (contextual)`));
473
500
  out.push('');
474
501
  write(io, 'stdout', `${out.join('\n')}\n`);
475
502
  return exports.EXIT_OK;
@@ -54,7 +54,7 @@ export interface InitResult {
54
54
  blocked: string[];
55
55
  warnings: string[];
56
56
  }
57
- export declare const SKILL_TEMPLATE = "---\nname: vibe-shield\ndescription: Audit any change for AI-introduced security bugs (leaked keys, unguarded API routes, disabled Row Level Security, SQL injection, prompt injection, poisoned MCP servers) and fix them before reporting a task as done. Use whenever you write or modify application code, API routes, server actions, database migrations, auth logic, environment variables, LLM calls, webhook handlers, agent skills or MCP configuration.\nallowed-tools: Bash(npx -y @vibefoundry/vibe-shield scan*), Bash(npx -y @vibefoundry/vibe-shield audit-skills*), Bash(npx -y @vibefoundry/vibe-shield explain*), Read(./**), Grep, Glob\nlicense: MIT\nmetadata:\n author: VibeFoundry\n homepage: https://github.com/avivgerz-hue/vibe-shield\n version: 1.0.0\n---\n\n# vibe-shield\n\nYou are not allowed to say \"done\" until the code you just wrote passes a security audit.\n\nAI coding agents ship a specific, repeatable class of vulnerability: a `SUPABASE_SERVICE_ROLE_KEY` behind a `NEXT_PUBLIC_` prefix, a `DELETE` route handler with no session check, a `CREATE TABLE` with no `ENABLE ROW LEVEL SECURITY`, a tool whose `execute` forwards model output into `exec`. These are not exotic \u2014 they are the default shape of code written quickly by something optimising for \"it works\". This skill is the second pair of eyes.\n\n## When to run\n\nRun the audit **after every change that touches**:\n\n- an API route, route handler, server action, RPC endpoint or GraphQL mutation\n- authentication, session, role, permission or ownership logic\n- a database migration, policy, grant, schema or Supabase table\n- an environment variable, config file, `.env*` file or build config\n- anything calling an LLM, a tool, a webhook, a shell command or the filesystem\n- `.claude/`, `.cursor/`, `AGENTS.md`, `mcp.json` or any skill/config file\n\nIf you did not touch any of those, you do not need to run it.\n\n## The loop\n\n```bash\n# 1. Scan (a whole-repo scan finishes in well under a second)\nnpx -y @vibefoundry/vibe-shield scan --fail-on high\n\n# 2. If it fails, generate the machine-readable fix list\nnpx -y @vibefoundry/vibe-shield scan --fix-prompt\n\n# 3. Read SECURITY_PATCH_PROMPT.md and fix every finding, critical first\n# Each entry has the exact file:line, the vulnerable snippet, the CWE and\n# the required change. Apply it literally.\n\n# 4. Re-run until it exits 0\nnpx -y @vibefoundry/vibe-shield scan --fail-on high\n```\n\n`--fail-on high` exits non-zero while any high or critical finding exists. That is the gate.\n\n## Reading a finding\n\n```\nCRITICAL 47:15 VSB-CLIENT-001 Server-only secret exposed through a public environment prefix\n const key = process.env.NEXT_PUBLIC_OPENAI_API_KEY;\n```\n\n| Part | Meaning |\n| --- | --- |\n| `47:15` | exact line and column to edit |\n| `VSB-CLIENT-001` | rule id \u2014 use it with `explain` for full docs |\n| message | why this specific line is exploitable |\n| `(CWE-200)` | bug class, for a deeper search if the fix is unclear |\n\nNeed the full picture? `npx -y @vibefoundry/vibe-shield explain VSB-CLIENT-001` prints the vulnerable shape, the fixed shape, remediation steps and references.\n\n## Hard rules\n\n1. **Fix the root cause.** Never delete an auth check, disable RLS, silence a log or add a catch-all `catch {}` to make the finding disappear.\n2. **Never suppress.** Do not add `// vibe-shield-disable`, do not edit `.vibe-shieldignore`, do not pass `--ignore`. Suppression is a decision for the human.\n3. **Rotate exposed credentials.** If the scan reported a live key, tell the user to rotate it at the provider in the same message. Removing the line does not un-leak it \u2014 the value may already be in a bundle, a cache or a git history.\n4. **Report honestly.** If you cannot fix a finding (you need a decision, a credential or a provider change), say so explicitly, name the rule id, and stop.\n5. **Re-verify.** A fix is not finished until the gate exits 0.\n\n## Agent surface audit\n\nWhen you add or modify a skill, rule file, MCP server or instruction file, also run:\n\n```bash\nnpx -y @vibefoundry/vibe-shield audit-skills\n```\n\nTwelve `VSB-AGENT-*` rules check for hidden Unicode (zero-width and bidi characters used to smuggle instructions past review), `curl`/`wget` exfiltration of environment variables, credential-harvesting instructions (`.env`, `~/.ssh`, `~/.aws`), registry-tag or remote MCP servers, literal tokens in an `env` block, safety-override language, over-broad tool permissions, base64 `eval` payloads, remote-instruction fetching, wildcard `allowed-tools`, and shell injection in skill scripts.\n\nEach finding carries a `triage` field: `block` means refuse and escalate, `review` means ask the user, `report` means mention it and continue. Do not blanket-refuse a repository because a rule fired \u2014 read the triage.\n\n## Flags worth knowing\n\n| Flag | Effect |\n| --- | --- |\n| `--format json` | full machine-readable report (schemaVersion 1) |\n| `--format sarif` | SARIF 2.1.0 for GitHub code scanning |\n| `--format compact` | one line per finding |\n| `--format github` | inline GitHub Actions annotations |\n| `--severity high` | only report high and critical |\n| `--fail-on medium` | stricter gate |\n| `--include-tests` | include test and fixture files |\n| `--cache` | reuse results between runs |\n| `--quiet` | one-line verdict (ideal for piping) |\n| `rules` | list every rule |\n| `explain <RULE_ID>` | full documentation for one rule |\n\nIf the repository has a `.mcp.json`, the same three capabilities are also\navailable as MCP tools \u2014 `vibe_shield_scan`, `vibe_shield_audit_skills` and\n`vibe_shield_explain_rule`. Prefer those when they are listed, because they\nreturn structured findings instead of text you have to parse.\n\n## Definition of done\n\n- [ ] `npx -y @vibefoundry/vibe-shield scan --fail-on high` exits `0`\n- [ ] `npx -y @vibefoundry/vibe-shield audit-skills` exits `0` if you touched agent files\n- [ ] every credential the scan surfaced has been flagged to the user for rotation\n- [ ] no suppression directive was added\n- [ ] the feature still works and the existing tests still pass\n\n## Install it into a repository\n\n```bash\nnpx -y @vibefoundry/vibe-shield init\n```\n\nThat writes this file to `.claude/skills/vibe-shield/SKILL.md`, appends a security\ngate section to `AGENTS.md`, adds a `.cursor/rules/vibe-shield.mdc`, and installs a\nGitHub Actions workflow that fails the pull request on new high or critical\nfindings. Every future task in that repository starts guarded.\n";
57
+ export declare const SKILL_TEMPLATE = "---\nname: vibe-shield\ndescription: Apply a six-phase defensive security review to changes affecting applications, APIs, data, AI agents, and MCP configuration. Use static evidence, preserve behavior, and report limitations.\nallowed-tools: Bash(npx -y @vibefoundry/vibe-shield scan*), Bash(npx -y @vibefoundry/vibe-shield audit-skills*), Bash(npx -y @vibefoundry/vibe-shield explain*), Read(./**), Grep, Glob\nlicense: MIT\nmetadata:\n author: VibeFoundry\n homepage: https://github.com/avivgerz-hue/vibe-shield\n version: 2.0.0\n---\n\n# Defensive AppSec architect protocol\n\nWork only within the authorized project. Static findings are evidence for review, not proof of exploitability or a guarantee of safety. Do not transmit source code or secrets. Ask before changing production services, rotating credentials, or making destructive changes.\n\n## Phase 1: Attack-surface reconnaissance\n\nMap entrypoints and trust boundaries: API methods, authentication and authorization, middleware matchers, database tables and policies, storage, LLM inputs and tools, webhooks, and agent/MCP configuration. Check deployment configuration and exclusions. Identify what the scanner cannot see.\n\n## Phase 2: Automated static scan and skill audit\n\n```bash\nnpx -y @vibefoundry/vibe-shield scan . --format json\nnpx -y @vibefoundry/vibe-shield audit-skills . --format json\n```\n\nInspect findings, inventory, ignored paths, and the files scanned. The explicit `.` includes test and documentation files: review fixtures as examples rather than blindly changing them. Use `explain <RULE_ID>` to investigate a rule. These commands run locally; first-time installation with npx requires registry access.\n\n## Phase 3: Deep contextual threat modeling\n\nTrace untrusted input through authentication, ownership checks and tenant boundaries to database, filesystem, network, HTML, and LLM sinks. Inspect IDOR, business-logic bypasses, webhook signature verification and asynchronous jobs. Check cross-file guards and deployed database policies; absence of a static finding is not evidence of protection.\n\n## Phase 4: Surgical zero-regression remediation\n\n- On Next.js mutation routes, authenticate the session on the server and authorize the target resource against the session principal before writes. Do not trust identity from request bodies.\n- Enable Supabase RLS and write action-specific policies using the authenticated principal; test both permitted and denied tenants before deploying migrations.\n- Validate inputs at the boundary with a schema such as Zod, then use parameterized database queries. Treat LLM output as untrusted.\n- Use explicit CORS allowlists, secure cookie flags and a CSP appropriate for the application. Test login, redirects, and browser behavior.\n- Report exposed credentials to the owner for provider-side rotation; avoid reproducing their values in reports. Do not suppress findings or weaken controls to obtain a higher score. Ask for missing business or deployment decisions.\n\n## Phase 5: Verification gate\n\nRun project tests and both audits again. Aim for 100/100 Grade A+ with no high or critical findings, but report any unresolved finding, exclusion, false positive, or verification limitation honestly rather than claiming success. Never equate a clean score with a complete security assessment.\n\n```bash\nnpx -y @vibefoundry/vibe-shield scan --fail-on high\nnpx -y @vibefoundry/vibe-shield audit-skills --fail-on high\n```\n\n## Phase 6: Executive security sign-off\n\nProduce a Markdown or HTML report with scope, inventory, risks prioritized by severity, evidence, actions, test results and remaining uncertainty. Illustrative code examples are not project-specific patches; review and adapt them. Obtain human approval before deployment or provider-side action.\n\n```bash\nnpx -y @vibefoundry/vibe-shield scan --report SECURITY-REPORT.md --patch-prompt PATCH-PROMPT.md\nnpx -y @vibefoundry/vibe-shield audit-skills --report AGENT-REPORT.html\n```\n";
58
58
  export declare const AGENTS_SECTION = "## Security gate (vibe-shield)\n\nThis repository is guarded by [vibe-shield](https://github.com/avivgerz-hue/vibe-shield).\n\nBefore you report any task as complete:\n\n1. Run `npx -y @vibefoundry/vibe-shield scan --fail-on high` and fix every finding it reports.\n2. Never suppress a finding (`vibe-shield-disable`, `.vibe-shieldignore` edits,\n `--ignore`) to make the gate pass \u2014 that is the human's call.\n3. If you touched `.claude/`, `.cursor/`, `AGENTS.md`, `mcp.json` or a skill,\n also run `npx -y @vibefoundry/vibe-shield audit-skills`.\n4. Surface any exposed credential to the user for rotation. Do not \"fix\" it by\n deleting the line and moving on.\n\nThe gate exists because the most common way AI-written code reaches production\nwith a leaked `SUPABASE_SERVICE_ROLE_KEY` or an unauthenticated `DELETE`\nendpoint is that nobody asked it a second question.\n";
59
59
  /** Key this tool owns inside `mcpServers`; nothing else is ever touched. */
60
60
  export declare const MCP_SERVER_KEY = "vibe-shield";