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(), ".
|
|
15
|
-
description: "Claude Code (.
|
|
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: [".
|
|
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)
|
|
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 });',
|
package/build/data/rules/core.js
CHANGED
|
@@ -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*\(
|
|
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.
|
|
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",
|