guardvibe 3.0.25 → 3.0.26

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 CHANGED
@@ -5,6 +5,16 @@ All notable changes to GuardVibe are documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [3.0.26] - 2026-04-25
9
+
10
+ ### Fixed
11
+ - `init claude` now writes `.mcp.json` (Claude Code v2.x project-scope filename) instead of `.claude.json` — fixes silent install failure where MCP server was never loaded
12
+ - VG964 (server-only missing) now requires Next.js context (`from 'next/...'` or `require('next/...')`) — no longer fires on plain CommonJS Node files
13
+ - VG138 (plaintext password compare) no longer matches `typeof password !== 'string'` type guards
14
+ - VG148 (login brute-force) now detects rate-limit middleware passed as positional argument before bcrypt.compare
15
+ - VG061 (JWT no expiry) now correctly recognizes `expiresIn` anywhere in the `jwt.sign` argument list
16
+ - VG030 (missing rate limit) no longer fires when route declaration includes a `*Limiter`, `*Throttle`, `*RateLimit`, `*Brute`, or `*SlowDown` middleware
17
+
8
18
  ## [2.7.1] - 2026-04-04
9
19
 
10
20
  ### Fixed
package/build/cli/init.js CHANGED
@@ -11,8 +11,8 @@ const GUARDVIBE_MCP_CONFIG = {
11
11
  };
12
12
  const platforms = {
13
13
  claude: {
14
- path: join(process.cwd(), ".claude.json"),
15
- description: "Claude Code (.claude.json)",
14
+ path: join(process.cwd(), ".mcp.json"),
15
+ description: "Claude Code (.mcp.json)",
16
16
  },
17
17
  gemini: {
18
18
  path: join(homedir(), ".gemini", "settings.json"),
@@ -154,7 +154,7 @@ function setupSecurityGuide(platformName) {
154
154
  else if (platformName === "gemini")
155
155
  setupGeminiGuide();
156
156
  const gitignoreEntries = {
157
- claude: [".claude.json", ".claude/", "CLAUDE.md"],
157
+ claude: [".mcp.json", ".claude/", "CLAUDE.md"],
158
158
  cursor: [".cursor/", ".cursorrules"],
159
159
  gemini: ["GEMINI.md"],
160
160
  };
@@ -110,7 +110,7 @@ export const advancedSecurityRules = [
110
110
  severity: "critical",
111
111
  owasp: "A02:2025 Cryptographic Failures",
112
112
  description: "Password is compared using direct string equality (=== or ==) instead of a hashing function. This means passwords are stored or transmitted in plaintext.",
113
- pattern: /(?:password|passwd|pwd)\s*(?:===|!==|==|!=)\s*(?:(?:req|request|body|input|data|form|user)[\.\[]|["'])/gi,
113
+ pattern: /(?<!typeof\s)(?:password|passwd|pwd)\s*(?:===|!==|==|!=)\s*(?:(?:req|request|body|input|data|form|user)[\.\[]|["'](?!(?:string|number|boolean|undefined|object|function|symbol|bigint)["']))/gi,
114
114
  languages: ["javascript", "typescript", "python"],
115
115
  fix: "Never compare passwords directly. Use bcrypt.compare() or argon2.verify() to compare against hashed passwords.",
116
116
  fixCode: '// BAD: plaintext comparison\nif (user.password === inputPassword) { ... }\n\n// GOOD: hash comparison\nimport bcrypt from "bcrypt";\nconst valid = await bcrypt.compare(inputPassword, user.passwordHash);\nif (!valid) return new Response("Invalid", { status: 401 });',
@@ -240,7 +240,7 @@ export const advancedSecurityRules = [
240
240
  severity: "high",
241
241
  owasp: "A07:2025 Identification and Authentication Failures",
242
242
  description: "Login/authentication endpoint compares passwords without rate limiting or account lockout. Attackers can try unlimited password combinations.",
243
- pattern: /(?:signIn|login|authenticate|logIn)\b[\s\S]{0,500}?(?:bcrypt\.compare|argon2\.verify|compare|verify)[\s\S]{0,300}?(?:(?!rateLimit|limiter|throttle|lockout|maxAttempts|failedAttempts|loginAttempts|Ratelimit)[\s\S]){5,}?(?:return|Response|res\.)/gi,
243
+ pattern: /(?:signIn|login|authenticate|logIn)\b(?:(?!rateLimit|limiter|throttle|lockout|maxAttempts|failedAttempts|loginAttempts|Ratelimit|brute)[\s\S]){0,500}?(?:bcrypt\.compare|argon2\.verify|compare|verify)(?:(?!rateLimit|limiter|throttle|lockout|maxAttempts|failedAttempts|loginAttempts|Ratelimit|brute)[\s\S]){5,300}?(?:return|Response|res\.)/gi,
244
244
  languages: ["javascript", "typescript"],
245
245
  fix: "Add rate limiting and account lockout to login endpoints.",
246
246
  fixCode: '// Add rate limiting to login\nimport { Ratelimit } from "@upstash/ratelimit";\nconst loginLimiter = new Ratelimit({\n redis: Redis.fromEnv(),\n limiter: Ratelimit.slidingWindow(5, "15 m"), // 5 attempts per 15 min\n});\n\nconst { success } = await loginLimiter.limit(email);\nif (!success) return new Response("Too many attempts", { status: 429 });',
@@ -140,7 +140,7 @@ export const coreRules = [
140
140
  severity: "medium",
141
141
  owasp: "A04:2025 Insecure Design",
142
142
  description: "Authentication or API endpoints without rate limiting are vulnerable to brute force attacks.",
143
- pattern: /(?:app|router)\.\s*(?:get|post|put|delete|patch|use)\s*\(\s*['"](?:\/login|\/auth|\/signin|\/register|\/signup|\/forgot-password)/gi,
143
+ pattern: /(?:app|router)\.\s*(?:get|post|put|delete|patch|use)\s*\(\s*['"](?:\/login|\/auth|\/signin|\/register|\/signup|\/forgot-password)['"]\s*,(?!\s*(?:\w*[Ll]imiter|\w*[Tt]hrottle|\w*[Rr]ate[Ll]imit|\w*[Bb]rute|\w*[Ss]low[Dd]own))/gi,
144
144
  languages: ["javascript", "typescript", "python", "go"],
145
145
  fix: "Add rate limiting middleware. Express: npm install express-rate-limit. FastAPI: use slowapi. Apply stricter limits on auth endpoints (e.g. 5 requests/minute).",
146
146
  fixCode: "// Express rate limiting\nimport rateLimit from 'express-rate-limit';\napp.use('/api/', rateLimit({ windowMs: 15 * 60 * 1000, max: 100 }));",
@@ -200,7 +200,7 @@ export const coreRules = [
200
200
  severity: "high",
201
201
  owasp: "A07:2025 Auth Failures",
202
202
  description: "JWT token created without expiration time.",
203
- pattern: /jwt\.sign\s*\([^)]*(?!\bexpiresIn\b)[^)]*\)/gi,
203
+ pattern: /jwt\.sign\s*\((?:(?!\bexpiresIn\b)[^)])*\)/gi,
204
204
  languages: ["javascript", "typescript"],
205
205
  fix: "Always set token expiration: jwt.sign(payload, secret, { expiresIn: '15m' }).",
206
206
  fixCode: "// Always set expiration\nconst token = jwt.sign(payload, secret, { expiresIn: '15m' });",
@@ -65,7 +65,7 @@ export const modernStackRules = [
65
65
  severity: "high",
66
66
  owasp: "A01:2025 Broken Access Control",
67
67
  description: 'File contains sensitive server-side logic (database queries, secret access) but does not import "server-only". Without this guard, the module can be accidentally imported by a Client Component, leaking server code to the browser bundle.',
68
- pattern: /^(?![\s\S]*?(?:['"]server-only['"]|['"]use server['"]|['"]use client['"])[\s\S]*?)[\s\S]*?(?:process\.env\.(?!NEXT_PUBLIC_)\w+(?:_KEY|_SECRET|_TOKEN)|(?:prisma|db|supabase)\.(?:query|from|\$queryRaw))/g,
68
+ pattern: /^(?=[\s\S]*?(?:from\s+['"]next(?:\/[^'"]*)?['"]|require\s*\(\s*['"]next(?:\/[^'"]*)?['"]))(?![\s\S]*?(?:['"]server-only['"]|['"]use server['"]|['"]use client['"])[\s\S]*?)[\s\S]*?(?:process\.env\.(?!NEXT_PUBLIC_)\w+(?:_KEY|_SECRET|_TOKEN)|(?:prisma|db|supabase)\.(?:query|from|\$queryRaw))/g,
69
69
  languages: ["javascript", "typescript"],
70
70
  fix: 'Add import "server-only" at the top of files that contain server-side logic.',
71
71
  fixCode: '// Add at the very top of server-only modules\nimport "server-only";\n\n// Now this file cannot be imported by Client Components\nexport async function getSecretData() {\n const key = process.env.SECRET_KEY;\n return prisma.user.findMany();\n}',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "guardvibe",
3
- "version": "3.0.25",
3
+ "version": "3.0.26",
4
4
  "mcpName": "io.github.goklab/guardvibe",
5
5
  "description": "Security MCP for vibe coding. 341 rules, 36 tools, CLI + doctor. Host security, auth coverage mapping, LLM-powered deep scan (IDOR/business logic), taint analysis. Plus Next.js, Supabase, Clerk, Stripe, Prisma, tRPC, Hono, GraphQL, Convex, Turso, Uploadthing, AI SDK, and the full AI-generated stack.",
6
6
  "type": "module",