guardvibe 2.3.9 → 2.4.2

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/CHANGELOG.md ADDED
@@ -0,0 +1,212 @@
1
+ # Changelog
2
+
3
+ All notable changes to GuardVibe are documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [2.4.1] - 2026-04-04
9
+
10
+ ### Added
11
+ - VG910: Hono SSE injection detection via `streamSSE()` (CVE-2026-29085)
12
+ - VG911: Kubernetes Secret hardcoded value detection
13
+ - VG912: MongoDB NoSQL injection via query operators
14
+
15
+ ## [2.4.0] - 2026-04-04
16
+
17
+ ### Added
18
+ - Buddy format (`--format buddy`) — compact ASCII character with mood-based security feedback
19
+ - 5 face expressions based on security grade (A through F)
20
+ - Grade-aware contextual message pool
21
+
22
+ ### Changed
23
+ - Claude Code hook now uses buddy format by default for real-time visual feedback
24
+
25
+ ## [2.3.9] - 2026-04-03
26
+
27
+ ### Added
28
+ - 6 new supply chain rules (VG860-868)
29
+ - Yarn and pnpm lockfile support
30
+ - Advanced typosquat detection
31
+
32
+ ## [2.3.8] - 2026-04-03
33
+
34
+ ### Changed
35
+ - Capitalize extension name to GuardVibe in Gemini CLI gallery
36
+
37
+ ## [2.3.7] - 2026-04-02
38
+
39
+ ### Added
40
+ - Gemini CLI extensions gallery support (gemini-extension.json)
41
+
42
+ ## [2.3.6] - 2026-04-02
43
+
44
+ ### Added
45
+ - Platform-specific setup guides for all 6 IDEs in README
46
+
47
+ ## [2.3.5] - 2026-04-01
48
+
49
+ ### Fixed
50
+ - Correct rule count: 322 → 307 (actual), update all module counts in README
51
+
52
+ ## [2.3.4] - 2026-04-01
53
+
54
+ ### Fixed
55
+ - Suppress false positives in generate-policy template strings
56
+
57
+ ## [2.3.3] - 2026-04-01
58
+
59
+ ### Changed
60
+ - README: add self-scan dogfooding section, update stats to 322 rules / 25 tools
61
+
62
+ ## [2.3.2] - 2026-04-01
63
+
64
+ ### Fixed
65
+ - Fix ReDoS in policy-check glob matching (VG107)
66
+
67
+ ## [2.3.1] - 2026-04-01
68
+
69
+ ### Changed
70
+ - Scan visibility rules: agent always reports GuardVibe results to user
71
+
72
+ ## [1.7.1] - 2026-04-01
73
+
74
+ ### Added
75
+ - 10 new XSS/injection rules covering form actions, file uploads, rich text editors, and template injection
76
+
77
+ ## [1.7.0] - 2026-04-01
78
+
79
+ ### Added
80
+ - 24 new rules from proactive threat research
81
+ - Supply chain attack detection rules
82
+ - CI/CD pipeline security rules
83
+ - Kubernetes misconfiguration detection
84
+ - AI/LLM security rules
85
+ - New CVE version intelligence entries
86
+
87
+ ## [1.6.1] - 2026-04-01
88
+
89
+ ### Added
90
+ - 4 new supply-chain rules for npm publish leak protection
91
+
92
+ ### Security
93
+ - Self-hardening of the publish pipeline to prevent accidental credential leaks
94
+
95
+ ## [1.6.0] - 2026-03-31
96
+
97
+ ### Added
98
+ - Agent-native security layer
99
+ - Command guard for dangerous shell operations
100
+ - Config diff tool for detecting security regressions
101
+ - Repository security posture scoring
102
+ - Deep remediation with expanded fix suggestions
103
+
104
+ ## [1.5.0] - 2026-03-31
105
+
106
+ ### Added
107
+ - PR review security scanning
108
+ - Git history scan for leaked secrets
109
+ - Policy engine with compliance enforcement
110
+ - Taint analysis for data flow tracking
111
+ - 100% fixCode coverage across all rules
112
+ - Expanded patch generation for auto-fix suggestions
113
+
114
+ ## [1.4.0] - 2026-03-31
115
+
116
+ ### Added
117
+ - `check_package_health` tool for typosquat detection, maintenance status, and adoption metrics
118
+ - `exploit` and `audit` fields on SecurityRule for compliance demonstrations
119
+ - fixCode secure code examples added to all 25 rules that were missing them
120
+
121
+ ### Changed
122
+ - Compliance mapping deepened with GDPR and ISO 27001 controls
123
+ - Performance improvements for large project scanning
124
+
125
+ ## [1.3.3] - 2026-03-31
126
+
127
+ ### Fixed
128
+ - Node.js 18 compatibility issue
129
+
130
+ ### Security
131
+ - npm provenance via Sigstore for cryptographic package signing
132
+ - Branch protection enabled (force push disabled on main)
133
+ - Tag protection for version tags (`v*`)
134
+ - Minimal CI permissions (`contents: read` only)
135
+
136
+ ## [1.3.2] - 2026-03-31
137
+
138
+ ### Changed
139
+ - Rebranded project as GuardVibe with new description and metadata
140
+
141
+ ## [0.6.1] - 2026-03-30
142
+
143
+ ### Fixed
144
+ - OSV severity normalization returning incorrect values
145
+
146
+ ### Changed
147
+ - Updated MCP SDK dependency
148
+
149
+ ## [0.6.0] - 2026-03-30
150
+
151
+ ### Added
152
+ - `.guardviberc` configuration file support with rule disable, severity override, and scan exclusions
153
+ - Compliance mapping for SOC2, PCI-DSS, and HIPAA with `compliance_report` tool
154
+ - Terraform IaC security rules (VG300-VG304): S3, IAM, RDS, security groups
155
+ - SARIF v2.1.0 output for CI/CD integration (`export_sarif` tool)
156
+
157
+ ### Fixed
158
+ - `scan_dependencies` severity and summary showing undefined when fetching OSV details
159
+
160
+ ## [0.5.0] - 2026-03-30
161
+
162
+ ### Added
163
+ - `fixCode` field on SecurityRule type with secure code examples for core, Go, Java, PHP, Ruby rules
164
+ - `scan_staged` tool for pre-commit security scanning
165
+ - Dockerfile security rules (VG200-VG204): root user, secrets in ENV, untagged images
166
+ - CI/CD security rules (VG210-VG213): secrets interpolation, unpinned actions, write-all permissions
167
+ - Security guides for Django, NestJS, Hono, Supabase, and tRPC
168
+ - fixCode snippets rendered in security reports
169
+
170
+ ### Changed
171
+ - Renamed project from VibeGuard to GuardVibe across entire codebase
172
+ - Cleaned up all old VibeGuard references and outdated specs
173
+
174
+ ## [0.4.0] - 2026-03-30
175
+
176
+ ### Added
177
+ - `scan_directory` tool for filesystem-native project scanning
178
+ - `scan_dependencies` tool with manifest parsing and OSV batch query
179
+ - `scan_secrets` tool with pattern-based and entropy-based secret detection
180
+ - `guardvibe-ignore` inline comment suppression (supports `//`, `#`, `<!-- -->`)
181
+ - Finding deduplication in analysis pipeline
182
+
183
+ ### Changed
184
+ - `check_project` refactored to use structured findings instead of string parsing
185
+ - Extracted `analyzeCode()` as reusable analysis function
186
+ - Rules split into per-language modules for maintainability
187
+
188
+ ## [0.3.0] - 2026-03-30
189
+
190
+ ### Added
191
+ - Project scanning with `check_project` tool
192
+ - CLI auto-setup (`npx guardvibe init`) for Claude Code, Cursor, Gemini CLI
193
+ - Go security rules (SQL injection, command injection, template escaping)
194
+ - Java security rules
195
+ - PHP security rules
196
+ - Ruby security rules
197
+ - Test infrastructure with tsx and node:test
198
+ - Rule tests for core, Go, Java, PHP, Ruby
199
+
200
+ ## [0.2.0] - 2026-03-30
201
+
202
+ ### Added
203
+ - New security rules for Python
204
+ - Improved Python support
205
+
206
+ ## [0.1.0] - 2026-03-30
207
+
208
+ ### Added
209
+ - Initial release as VibeGuard Security MCP server
210
+ - Core OWASP security rules (SQL injection, XSS, CSRF, command injection)
211
+ - `check_code` tool for code snippet analysis
212
+ - MCP server with stdio transport
package/build/cli.js CHANGED
@@ -136,7 +136,7 @@ function setupClaudeGuide() {
136
136
  matcher: "Edit|Write",
137
137
  hooks: [{
138
138
  type: "command",
139
- command: "jq -r '.tool_input.file_path' | xargs npx -y guardvibe check --format markdown 2>/dev/null || true"
139
+ command: "jq -r '.tool_input.file_path' | xargs npx -y guardvibe check --format buddy 2>/dev/null || true"
140
140
  }]
141
141
  }
142
142
  ];
@@ -560,7 +560,8 @@ async function runFileCheck(filePath, flags) {
560
560
  process.exit(1);
561
561
  }
562
562
  const format = flags.format ?? "markdown";
563
- const result = checkCode(content, language, undefined, resolved, undefined, format === "json" ? "json" : "markdown");
563
+ const formatArg = format === "json" ? "json" : format === "buddy" ? "buddy" : "markdown";
564
+ const result = checkCode(content, language, undefined, resolved, undefined, formatArg);
564
565
  const outputFile = flags.output ?? null;
565
566
  if (outputFile) {
566
567
  writeFileSync(outputFile, result, "utf-8");
@@ -592,7 +593,7 @@ function printUsage() {
592
593
  npx guardvibe-scan --format sarif --output results.sarif
593
594
 
594
595
  Options:
595
- --format <type> Output format: markdown (default), json, sarif
596
+ --format <type> Output format: markdown (default), json, sarif, buddy
596
597
  --output <file> Write results to file instead of stdout
597
598
  --fail-on <level> Exit 1 when findings at this level or above exist
598
599
  critical (default) | high | medium | low | none
@@ -123,4 +123,16 @@ export const databaseRules = [
123
123
  fixCode: '-- PostgreSQL: use SECURITY INVOKER\nCREATE OR REPLACE FUNCTION get_user_data(user_id uuid)\nRETURNS TABLE (id uuid, name text)\nLANGUAGE sql\nSECURITY INVOKER -- respects RLS!\nAS $$\n SELECT id, name FROM users WHERE id = user_id;\n$$;\n\n// TypeScript: call with anon key (not service role)\nconst { data } = await supabase.rpc("get_user_data", { user_id: userId });',
124
124
  compliance: ["SOC2:CC6.1"],
125
125
  },
126
+ {
127
+ id: "VG912",
128
+ name: "MongoDB NoSQL Injection via Query Operators",
129
+ severity: "high",
130
+ owasp: "A02:2025 Injection",
131
+ description: "MongoDB query operators ($where, $regex, $gt, $ne, $nin) used in database queries may be vulnerable to NoSQL injection if user input is passed directly without validation. Attackers can manipulate query logic to bypass authentication or extract data.",
132
+ pattern: /\.(find|findOne|updateOne|deleteOne|aggregate)\(\s*\{[^}]*(\$where|\$regex|\$gt|\$ne|\$nin)/g,
133
+ languages: ["javascript", "typescript"],
134
+ fix: "Validate and sanitize all user input before using it in MongoDB queries. Use a schema validation library (zod, joi) to ensure query parameters match expected types. Never pass raw request body directly to MongoDB queries.",
135
+ fixCode: 'import { z } from "zod";\n\n// Validate input before query\nconst schema = z.object({ id: z.string().regex(/^[a-f0-9]{24}$/) });\nconst { id } = schema.parse(req.body);\n\n// Safe query — no raw operators from user input\nconst user = await db.collection("users").findOne({ _id: new ObjectId(id) });',
136
+ compliance: ["SOC2:CC7.1", "PCI-DSS:Req6.5.1"],
137
+ },
126
138
  ];
@@ -244,4 +244,16 @@ export const deploymentRules = [
244
244
  fixCode: '// Validate URL scheme\nfunction isSafeUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n return ["https:", "http:"].includes(parsed.protocol);\n } catch {\n return false;\n }\n}\n\n// Usage\n<img src={isSafeUrl(userUrl) ? userUrl : "/placeholder.png"} />',
245
245
  compliance: ["SOC2:CC7.1"],
246
246
  },
247
+ {
248
+ id: "VG911",
249
+ name: "Kubernetes Secret Hardcoded Value",
250
+ severity: "critical",
251
+ owasp: "A07:2025 Identification and Authentication Failures",
252
+ description: "Kubernetes Secret manifest contains hardcoded base64-encoded values in the data field. These secrets are only base64-encoded (not encrypted) and will be exposed in version control. Use External Secrets, Sealed Secrets, or a secrets manager instead.",
253
+ pattern: /kind:\s*Secret[\s\S]*?data:[\s\S]*?(?!\s*\{\{)[\w+/=]{8,}/g,
254
+ languages: ["yaml"],
255
+ fix: "Never commit Secret manifests with hardcoded values. Use External Secrets Operator, Sealed Secrets, or inject secrets via CI/CD pipeline. Store sensitive values in a secrets manager (Vault, AWS Secrets Manager, etc.).",
256
+ fixCode: '# Use External Secrets Operator\napiVersion: external-secrets.io/v1beta1\nkind: ExternalSecret\nmetadata:\n name: my-secret\nspec:\n refreshInterval: 1h\n secretStoreRef:\n name: vault-backend\n kind: SecretStore\n target:\n name: my-secret\n data:\n - secretKey: password\n remoteRef:\n key: secret/data/myapp\n property: password',
257
+ compliance: ["SOC2:CC6.1", "PCI-DSS:Req6.5.3", "HIPAA:§164.312(a)"],
258
+ },
247
259
  ];
@@ -482,4 +482,16 @@ export const modernStackRules = [
482
482
  fixCode: 'import { randomUUID } from "crypto";\nimport path from "path";\n\n// Generate safe filename\nconst ext = path.extname(file.name).toLowerCase();\nconst ALLOWED_EXT = [".jpg", ".jpeg", ".png", ".webp", ".pdf"];\nif (!ALLOWED_EXT.includes(ext)) throw new Error("Invalid file type");\nconst safeName = `${randomUUID()}${ext}`;\nawait fs.writeFile(`/uploads/${safeName}`, buffer);',
483
483
  compliance: ["SOC2:CC7.1"],
484
484
  },
485
+ {
486
+ id: "VG910",
487
+ name: "Hono SSE Injection via streamSSE",
488
+ severity: "medium",
489
+ owasp: "A02:2025 Injection",
490
+ description: "Hono's streamSSE() sends Server-Sent Events to clients. If event, id, or retry fields contain unsanitized user input, attackers can inject CR/LF characters to forge SSE messages, hijack event streams, or trigger client-side actions. Related to CVE-2026-29085.",
491
+ pattern: /streamSSE\s*\(/g,
492
+ languages: ["javascript", "typescript"],
493
+ fix: "Sanitize all SSE field values by stripping CR/LF characters (\\r, \\n) before passing them to streamSSE. Never use raw user input in event, id, or retry fields.",
494
+ fixCode: '// Sanitize SSE fields\nfunction sanitizeSSE(value: string): string {\n return value.replace(/[\\r\\n]/g, "");\n}\n\n// Usage with Hono streamSSE\nreturn streamSSE(c, async (stream) => {\n await stream.writeSSE({\n event: sanitizeSSE(eventName),\n data: sanitizeSSE(data),\n id: sanitizeSSE(id),\n });\n});',
495
+ compliance: ["SOC2:CC7.1"],
496
+ },
485
497
  ];
@@ -6,4 +6,4 @@ export interface Finding {
6
6
  }
7
7
  export declare function analyzeCode(code: string, language: string, framework?: string, filePath?: string, configDir?: string, rules?: SecurityRule[]): Finding[];
8
8
  export declare function formatFindingsJson(findings: Finding[], extra?: Record<string, unknown>): string;
9
- export declare function checkCode(code: string, language: string, framework?: string, filePath?: string, configDir?: string, format?: "markdown" | "json", rules?: SecurityRule[]): string;
9
+ export declare function checkCode(code: string, language: string, framework?: string, filePath?: string, configDir?: string, format?: "markdown" | "json" | "buddy", rules?: SecurityRule[]): string;
@@ -1,3 +1,4 @@
1
+ import { basename } from "path";
1
2
  import { owaspRules } from "../data/rules/index.js";
2
3
  import { loadConfig } from "../utils/config.js";
3
4
  import { loadIgnoreFile, isIgnored } from "../utils/ignore.js";
@@ -421,6 +422,9 @@ export function checkCode(code, language, framework, filePath, configDir, format
421
422
  if (format === "json") {
422
423
  return formatFindingsJson(findings);
423
424
  }
425
+ if (format === "buddy") {
426
+ return formatBuddyOutput(findings, filePath);
427
+ }
424
428
  if (findings.length === 0) {
425
429
  return formatCleanReport(language, framework);
426
430
  }
@@ -547,3 +551,49 @@ function formatReport(findings, language, framework) {
547
551
  }
548
552
  return lines.join("\n");
549
553
  }
554
+ // ─── Buddy Format ────────────────────────────────────────────────
555
+ function severityWeight(s) {
556
+ return s === "critical" ? 4 : s === "high" ? 3 : s === "medium" ? 2 : 1;
557
+ }
558
+ function formatBuddyOutput(findings, filePath) {
559
+ const counts = { critical: 0, high: 0, medium: 0, low: 0 };
560
+ for (const f of findings) {
561
+ const sev = f.rule.severity;
562
+ if (sev in counts)
563
+ counts[sev]++;
564
+ }
565
+ let score = 100;
566
+ score -= counts.critical * 15;
567
+ score -= counts.high * 8;
568
+ score -= counts.medium * 3;
569
+ score -= counts.low * 1;
570
+ score = Math.max(0, Math.min(100, score));
571
+ const grade = score >= 90 ? "A" : score >= 75 ? "B" : score >= 60 ? "C" : score >= 40 ? "D" : "F";
572
+ const faces = {
573
+ A: "\\[^_^]/",
574
+ B: " [^_^]b",
575
+ C: " [o_o] ",
576
+ D: " [>_<] ",
577
+ F: " [X_X]!",
578
+ };
579
+ const face = faces[grade] || faces.C;
580
+ const messages = {
581
+ A: ["All clear, captain!", "Fort Knox level!", "Zero issues. Nice!", "Secure & clean!"],
582
+ B: ["Looking good!", "Almost perfect!", "Solid work!", "Just minor things."],
583
+ C: ["Some issues here...", "Needs attention.", "Review recommended."],
584
+ D: ["Multiple issues!", "Fix these ASAP.", "Getting risky..."],
585
+ F: ["Red alert!", "Critical issues!", "Stop and fix now!", "Danger zone!"],
586
+ };
587
+ const pool = messages[grade] || messages.C;
588
+ const msg = pool[Math.floor(Math.random() * pool.length)];
589
+ if (findings.length === 0) {
590
+ return `🛡️ ${face} GuardVibe: ${grade} [${score}] ✓ ${msg}`;
591
+ }
592
+ const sorted = [...findings].sort((a, b) => severityWeight(b.rule.severity) - severityWeight(a.rule.severity));
593
+ const top = sorted[0];
594
+ const fileName = filePath ? basename(filePath) : "unknown";
595
+ const severityIcon = counts.critical > 0 ? "🚨" : counts.high > 0 ? "⚠" : "⚡";
596
+ const total = counts.critical + counts.high + counts.medium + counts.low;
597
+ const detail = `${total} issue${total > 1 ? "s" : ""} — ${top.rule.name} (${fileName}:${top.line})`;
598
+ return `🛡️ ${face} GuardVibe: ${grade} [${score}] ${severityIcon} ${detail} — ${msg}`;
599
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "guardvibe",
3
- "version": "2.3.9",
3
+ "version": "2.4.2",
4
4
  "description": "Security MCP for vibe coding. 313 rules, 25 tools for Next.js, Supabase, Clerk, Stripe, Prisma, tRPC, Hono, GraphQL, Convex, Turso, Uploadthing, AI SDK, and the full AI-generated stack.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -8,12 +8,22 @@
8
8
  "guardvibe-init": "build/cli.js",
9
9
  "guardvibe-scan": "build/cli.js"
10
10
  },
11
+ "types": "./build/index.d.ts",
11
12
  "files": [
12
- "build"
13
+ "build",
14
+ "README.md",
15
+ "LICENSE",
16
+ "CHANGELOG.md"
13
17
  ],
14
18
  "exports": {
15
- ".": "./build/index.js",
16
- "./plugins": "./build/plugins/types.js"
19
+ ".": {
20
+ "types": "./build/index.d.ts",
21
+ "default": "./build/index.js"
22
+ },
23
+ "./plugins": {
24
+ "types": "./build/plugins/types.d.ts",
25
+ "default": "./build/plugins/types.js"
26
+ }
17
27
  },
18
28
  "scripts": {
19
29
  "build": "tsc",