@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.
- package/README.md +31 -11
- package/SKILL.md +26 -93
- package/dist/bin/vibe-shield.d.ts +1 -1
- package/dist/bin/vibe-shield.js +38 -11
- package/dist/src/init/scaffold.d.ts +1 -1
- package/dist/src/init/scaffold.js +26 -93
- package/dist/src/mcp/server.js +5 -1
- package/dist/src/mcp-guard/skill-auditor.js +11 -3
- package/dist/src/reporter/console-reporter.js +14 -0
- package/dist/src/reporter/executive.d.ts +4 -0
- package/dist/src/reporter/executive.js +58 -0
- package/dist/src/reporter/formatters.d.ts +1 -1
- package/dist/src/reporter/formatters.js +10 -3
- package/dist/src/reporter/patch-prompt-writer.js +3 -3
- package/dist/src/scanner/attack-surface.d.ts +4 -0
- package/dist/src/scanner/attack-surface.js +50 -0
- package/dist/src/scanner/engine.d.ts +2 -3
- package/dist/src/scanner/engine.js +21 -39
- package/dist/src/scanner/mappings.d.ts +17 -0
- package/dist/src/scanner/mappings.js +39 -0
- package/dist/src/scanner/redact.d.ts +1 -0
- package/dist/src/scanner/redact.js +12 -0
- package/dist/src/scanner/rules/hardening.d.ts +5 -0
- package/dist/src/scanner/rules/hardening.js +116 -0
- package/dist/src/scanner/rules/helpers.js +2 -0
- package/dist/src/scanner/rules/index.js +6 -0
- package/dist/src/scanner/rules/response-hardening.d.ts +2 -0
- package/dist/src/scanner/rules/response-hardening.js +120 -0
- package/dist/src/scanner/rules/secret-entropy.js +0 -2
- package/dist/src/scanner/types.d.ts +33 -1
- package/dist/src/scanner/types.js +6 -2
- package/dist/src/scanner/version.d.ts +2 -0
- package/dist/src/scanner/version.js +69 -0
- package/dist/src/secrets/patterns.js +40 -0
- 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
|
[](#-requirements)
|
|
15
15
|
[](./LICENSE)
|
|
16
16
|
[](./package.json)
|
|
17
|
-
[](./src/scanner/rules)
|
|
18
18
|
[](#-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
|
|
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 ยท
|
|
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:
|
|
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
|
-
**
|
|
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
|
|
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.
|
|
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
|
|
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 ยท
|
|
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
|
-
โ โ โ โโ
|
|
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:
|
|
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:
|
|
9
|
+
version: 2.0.0
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
-
#
|
|
12
|
+
# Defensive AppSec architect protocol
|
|
13
13
|
|
|
14
|
-
|
|
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
|
-
|
|
16
|
+
## Phase 1: Attack-surface reconnaissance
|
|
17
17
|
|
|
18
|
-
|
|
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
|
-
|
|
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
|
-
|
|
35
|
-
npx -y @vibefoundry/vibe-shield
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
33
|
+
## Phase 4: Surgical zero-regression remediation
|
|
67
34
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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
|
-
##
|
|
41
|
+
## Phase 5: Verification gate
|
|
75
42
|
|
|
76
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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[];
|
package/dist/bin/vibe-shield.js
CHANGED
|
@@ -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
|
|
98
|
-
--out <file> Write the report to a file
|
|
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
|
-
|
|
266
|
-
|
|
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
|
-
|
|
269
|
-
|
|
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
|
|
350
|
-
|
|
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:
|
|
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";
|