guardvibe 1.9.6 → 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.
@@ -33,7 +33,7 @@ export const apiSecurityRules = [
33
33
  severity: "high",
34
34
  owasp: "API2:2023 Broken Authentication",
35
35
  description: "Next.js Route Handler that performs data operations without any authentication check. API routes are publicly accessible by default.",
36
- pattern: /export\s+(?:async\s+)?function\s+(?:GET|POST|PUT|DELETE|PATCH)\s*\([^)]*\)\s*\{(?:(?!auth\s*\(|getServerSession|currentUser|getUser|requireAuth|requireAdmin|requireRole|isAuthenticated|verifyToken|checkAuth|clerkClient|getToken|session|protect|withAuth)[\s\S]){10,}?(?:prisma|db|supabase|query|fetch|sql)\.\w+/g,
36
+ pattern: /export\s+(?:async\s+)?function\s+(?:GET|POST|PUT|DELETE|PATCH)\s*\([^)]*\)\s*\{(?:(?!auth\s*\(|getServerSession|currentUser|getUser|requireAuth|requireAdmin|requireRole|isAuthenticated|verifyToken|checkAuth|clerkClient|getToken|session|protect|withAuth|verifyAuth|checkPermission|assertAuth|ensureAuth|guardAuth|validateAuth|authorize|checkSession|verifySession|validateSession|ensureAuthenticated)[\s\S]){10,}?(?:prisma|db|supabase|query|fetch|sql)\.\w+/g,
37
37
  languages: ["javascript", "typescript"],
38
38
  fix: "Add authentication at the start of every Route Handler that reads or writes data.",
39
39
  fixCode: 'import { auth } from "@clerk/nextjs/server";\n\nexport async function GET() {\n const { userId } = await auth();\n if (!userId) return new Response("Unauthorized", { status: 401 });\n // ... data access\n}',
@@ -96,7 +96,7 @@ export const apiSecurityRules = [
96
96
  severity: "high",
97
97
  owasp: "API5:2023 Broken Function Level Authorization",
98
98
  description: "Endpoint in /admin or /api/admin path performs operations without verifying admin role or permissions. Any authenticated user could access admin functionality.",
99
- pattern: /(?:\/api\/admin|\/admin)[\s\S]*?export\s+(?:async\s+)?function\s+(?:GET|POST|PUT|DELETE|PATCH)\s*\([^)]*\)\s*\{(?:(?!role|isAdmin|orgRole|permission|requireAdmin|checkRole|adminOnly|org:admin)[\s\S]){10,}?(?:prisma|db|supabase|sql)\.\w+/g,
99
+ pattern: /(?:\/api\/admin|\/admin)[\s\S]*?export\s+(?:async\s+)?function\s+(?:GET|POST|PUT|DELETE|PATCH)\s*\([^)]*\)\s*\{(?:(?!role|isAdmin|orgRole|permission|requireAdmin|checkRole|adminOnly|org:admin|verifyAuth|checkPermission|assertAuth|ensureAuth|authorize)[\s\S]){10,}?(?:prisma|db|supabase|sql)\.\w+/g,
100
100
  languages: ["javascript", "typescript"],
101
101
  fix: "Always verify admin role/permissions in admin endpoints.",
102
102
  fixCode: 'const { userId, orgRole } = await auth();\nif (orgRole !== "org:admin") {\n return new Response("Forbidden", { status: 403 });\n}',
@@ -6,7 +6,7 @@ export const authRules = [
6
6
  severity: "high",
7
7
  owasp: "A01:2025 Broken Access Control",
8
8
  description: "Route handler accesses database without authentication check. Anyone can call this endpoint.",
9
- pattern: /export\s+(?:async\s+)?function\s+(?:GET|POST|PUT|DELETE|PATCH)\s*\([^)]*\)\s*\{(?:(?!auth\s*\(|getServerSession|currentUser|getUser|requireAuth|requireAdmin|isAuthenticated|verifyToken|checkAuth|protect)[\s\S])*?(?:prisma|db|supabase)\.\w+/g,
9
+ pattern: /export\s+(?:async\s+)?function\s+(?:GET|POST|PUT|DELETE|PATCH)\s*\([^)]*\)\s*\{(?:(?!auth\s*\(|getServerSession|currentUser|getUser|requireAuth|requireAdmin|isAuthenticated|verifyToken|checkAuth|protect|verifyAuth|checkPermission|assertAuth|ensureAuth|guardAuth|validateAuth|authorize|checkSession|verifySession|validateSession|ensureAuthenticated|withAuth)[\s\S])*?(?:prisma|db|supabase)\.\w+/g,
10
10
  languages: ["javascript", "typescript"],
11
11
  fix: "Add authentication check at the start of every route handler that accesses data.",
12
12
  fixCode: 'import { auth } from "@clerk/nextjs/server";\n\nexport async function GET() {\n const { userId } = await auth();\n if (!userId) return new Response("Unauthorized", { status: 401 });\n const data = await db.query(...);\n}',
@@ -69,7 +69,7 @@ export const authRules = [
69
69
  severity: "high",
70
70
  owasp: "A01:2025 Broken Access Control",
71
71
  description: "Admin or dashboard route handler does not verify user role or permissions.",
72
- pattern: /(?:\/admin|\/dashboard)[\s\S]*?export\s+(?:async\s+)?function\s+(?:GET|POST|PUT|DELETE|PATCH|default)\s*\([^)]*\)\s*\{(?:(?!role|permission|isAdmin|orgRole|checkRole|requireAdmin|requireRole|adminOnly)[\s\S])*?\}/g,
72
+ pattern: /(?:\/admin|\/dashboard)[\s\S]*?export\s+(?:async\s+)?function\s+(?:GET|POST|PUT|DELETE|PATCH|default)\s*\([^)]*\)\s*\{(?:(?!role|permission|isAdmin|orgRole|checkRole|requireAdmin|requireRole|adminOnly|verifyAuth|checkPermission|assertAuth|ensureAuth|authorize)[\s\S])*?\}/g,
73
73
  languages: ["javascript", "typescript"],
74
74
  fix: "Always verify user roles and permissions in admin routes.",
75
75
  fixCode: 'import { auth } from "@clerk/nextjs/server";\n\nexport async function GET() {\n const { userId, orgRole } = await auth();\n if (orgRole !== "org:admin") {\n return new Response("Forbidden", { status: 403 });\n }\n}',
@@ -19,7 +19,7 @@ export const coreRules = [
19
19
  severity: "critical",
20
20
  owasp: "A01:2025 Broken Access Control",
21
21
  description: "Cloud provider API key or token pattern detected in source code (AWS, GitHub, OpenAI, Stripe).",
22
- pattern: /(?:AKIA[0-9A-Z]{16}|(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9_]{36,}|sk-[A-Za-z0-9]{20,}|sk_live_[A-Za-z0-9]{5,}|rk_live_[A-Za-z0-9]{5,})/g,
22
+ pattern: /(?:AKIA[0-9A-Z]{16}|(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9_]{36,}|sk-(?:proj-)?[A-Za-z0-9\-_]{20,}|sk_live_[A-Za-z0-9]{5,}|rk_live_[A-Za-z0-9]{5,})/g,
23
23
  languages: ["javascript", "typescript", "python", "go", "html", "shell"],
24
24
  fix: "Remove hardcoded keys immediately. Use environment variables or a secrets manager (AWS Secrets Manager, Vault). Rotate any compromised keys.",
25
25
  fixCode: "// Store keys in environment variables\nconst awsKey = process.env.AWS_ACCESS_KEY_ID;\nconst githubToken = process.env.GITHUB_TOKEN;",
@@ -386,4 +386,52 @@ export const coreRules = [
386
386
  fixCode: '// BAD: user input in event handler\n// `<img onerror="${userInput}">`\n\n// GOOD: use addEventListener\nconst img = document.createElement("img");\nimg.addEventListener("error", () => handleError(sanitizedInput));',
387
387
  compliance: ["SOC2:CC7.1"],
388
388
  },
389
+ {
390
+ id: "VG111",
391
+ name: "SSRF via User-Controlled URL",
392
+ severity: "high",
393
+ owasp: "A10:2025 Server-Side Request Forgery",
394
+ description: "User-controlled input is passed directly to fetch(), axios, or http.request() as the URL. Attackers can make the server request internal services (169.254.169.254 for cloud metadata, localhost admin panels, internal APIs) leading to data exfiltration or remote code execution.",
395
+ pattern: /(?:fetch|axios\.(?:get|post|put|delete|patch|request)|got(?:\.(?:get|post|put|delete|patch))?|request|http\.(?:get|request)|https\.(?:get|request)|urllib\.request\.urlopen)\s*\(\s*(?:url|uri|href|endpoint|target|destination|webhook[Uu]rl|callback[Uu]rl|redirect[Uu]rl|image[Uu]rl|proxy[Uu]rl|api[Uu]rl|base[Uu]rl|link|src|source|remoteUrl|externalUrl|userUrl|inputUrl|requestUrl)\b/gi,
396
+ languages: ["javascript", "typescript", "python"],
397
+ fix: "Validate URLs against an allowlist of trusted domains. Block private/internal IP ranges (10.x, 172.16-31.x, 192.168.x, 127.x, 169.254.x, ::1). Use a URL parser to check the hostname before making the request.",
398
+ fixCode: '// Validate URL before fetching\nconst ALLOWED_HOSTS = ["api.example.com", "cdn.example.com"];\nconst parsed = new URL(userUrl);\nif (!ALLOWED_HOSTS.includes(parsed.hostname)) {\n throw new Error("Blocked: untrusted host");\n}\n// Also block private IPs\nconst ip = await dns.resolve(parsed.hostname);\nif (isPrivateIP(ip)) throw new Error("Blocked: internal host");\nawait fetch(parsed.href);',
399
+ compliance: ["SOC2:CC7.1", "PCI-DSS:Req6.5.1"],
400
+ },
401
+ {
402
+ id: "VG112",
403
+ name: "XSS via insertAdjacentHTML",
404
+ severity: "high",
405
+ owasp: "A02:2025 Injection",
406
+ description: "insertAdjacentHTML() renders raw HTML strings into the DOM without sanitization, enabling Cross-Site Scripting (XSS). Unlike textContent, this method parses and executes HTML including script tags and event handlers.",
407
+ pattern: /\.insertAdjacentHTML\s*\(\s*["'](?:beforebegin|afterbegin|beforeend|afterend)["']\s*,/gi,
408
+ languages: ["javascript", "typescript"],
409
+ fix: "Use textContent or innerText for plain text. If HTML is needed, sanitize with DOMPurify first.",
410
+ fixCode: '// BAD: XSS risk\nel.insertAdjacentHTML("beforeend", userInput);\n\n// GOOD: plain text\nel.insertAdjacentText("beforeend", userInput);\n\n// GOOD: sanitized HTML\nimport DOMPurify from "dompurify";\nel.insertAdjacentHTML("beforeend", DOMPurify.sanitize(userInput));',
411
+ compliance: ["SOC2:CC7.1", "PCI-DSS:Req6.5.7"],
412
+ },
413
+ {
414
+ id: "VG113",
415
+ name: "XSS/SSRF via XMLHttpRequest",
416
+ severity: "high",
417
+ owasp: "A02:2025 Injection",
418
+ description: "XMLHttpRequest.open() is called with a user-controlled URL. This can lead to SSRF (server-side) or data exfiltration (client-side) if the URL is not validated.",
419
+ pattern: /\.open\s*\(\s*["'](?:GET|POST|PUT|DELETE|PATCH)["']\s*,\s*(?:url|uri|href|endpoint|target|userUrl|inputUrl|src)\b/gi,
420
+ languages: ["javascript", "typescript"],
421
+ fix: "Validate the URL against an allowlist before passing to XMLHttpRequest.open(). Prefer fetch() with URL validation over raw XHR.",
422
+ fixCode: '// Validate URL before XHR\nconst allowed = ["https://api.example.com"];\nconst parsed = new URL(userUrl);\nif (!allowed.some(a => userUrl.startsWith(a))) throw new Error("Blocked");\nxhr.open("GET", parsed.href);',
423
+ compliance: ["SOC2:CC7.1"],
424
+ },
425
+ {
426
+ id: "VG114",
427
+ name: "SQL Injection via Template Literal",
428
+ severity: "critical",
429
+ owasp: "A02:2025 Injection",
430
+ description: "SQL query constructed using JavaScript template literals with interpolated variables. Template literal SQL is just as dangerous as string concatenation — any user-controlled value can break out of the SQL context and inject arbitrary queries.",
431
+ pattern: /(?:query|execute|raw|sql|prepare|QueryRow|QueryContext|db\.run|db\.all|db\.get|connection\.query)\s*\(\s*`[^`]*\$\{/gi,
432
+ languages: ["javascript", "typescript"],
433
+ fix: "Use parameterized queries. For tagged template literals (e.g. Prisma sql``, Drizzle sql``), the tagged version IS safe — only raw template literals passed to query() are dangerous.",
434
+ fixCode: '// BAD: template literal SQL\ndb.query(`SELECT * FROM users WHERE id = \'${userId}\'`);\n\n// GOOD: parameterized query\ndb.query("SELECT * FROM users WHERE id = $1", [userId]);\n\n// ALSO SAFE: tagged template literal (Prisma/Drizzle)\nimport { sql } from "drizzle-orm";\ndb.execute(sql`SELECT * FROM users WHERE id = ${userId}`);',
435
+ compliance: ["SOC2:CC7.1", "PCI-DSS:Req6.5.1"],
436
+ },
389
437
  ];
@@ -30,7 +30,7 @@ export const nextjsRules = [
30
30
  severity: "critical",
31
31
  owasp: "A01:2025 Broken Access Control",
32
32
  description: "Server Action performs data mutations without verifying user authentication. Anyone can invoke Server Actions directly via POST request.",
33
- pattern: /["']use server["'][\s\S]{0,500}?export\s+async\s+function\s+\w+\s*\([^)]*\)\s*\{(?![\s\S]{0,800}?(?:auth\s*\(|getServerSession|currentUser|getUser|requireAuth|clerkClient))/g,
33
+ pattern: /["']use server["'][\s\S]{0,500}?export\s+async\s+function\s+\w+\s*\([^)]*\)\s*\{(?![\s\S]{0,800}?(?:auth\s*\(|getServerSession|currentUser|getUser|requireAuth|requireAdmin|clerkClient|verifyAuth|checkPermission|assertAuth|ensureAuth|authorize|withAuth))/g,
34
34
  languages: ["javascript", "typescript"],
35
35
  fix: "Always verify authentication at the start of every Server Action.",
36
36
  fixCode: '"use server";\nimport { auth } from "@clerk/nextjs/server";\n\nexport async function deleteItem(id: string) {\n const { userId } = await auth();\n if (!userId) throw new Error("Unauthorized");\n}',
@@ -114,7 +114,7 @@ export const nextjsRules = [
114
114
  severity: "medium",
115
115
  owasp: "A01:2025 Broken Access Control",
116
116
  description: "redirect() or NextResponse.redirect() uses user-controlled input (searchParams, query) which can redirect users to malicious sites.",
117
- pattern: /redirect\s*\(\s*(?:searchParams|params|req\.query|request\.url|url|query)\s*[\.\[]/g,
117
+ pattern: /(?:redirect|NextResponse\.redirect|res\.redirect|Response\.redirect)\s*\(\s*(?:searchParams|params|req\.query|request\.url|url|query|returnTo|callbackUrl|next|goto|returnUrl|redirectUrl|destination)\b/gi,
118
118
  languages: ["javascript", "typescript"],
119
119
  fix: "Validate redirect URLs against an allowlist of trusted domains.",
120
120
  fixCode: '// Validate redirect URL\nconst ALLOWED_HOSTS = ["example.com"];\nconst target = searchParams.get("next") ?? "/";\ntry {\n const url = new URL(target, request.url);\n if (!ALLOWED_HOSTS.includes(url.hostname)) redirect("/");\n redirect(url.pathname);\n} catch {\n redirect("/");\n}',
@@ -169,7 +169,7 @@ export function analyzeCode(code, language, framework, filePath, configDir, rule
169
169
  continue;
170
170
  // Context-aware: skip rate limiting rules for admin routes that have admin auth
171
171
  const isAdminRoute = filePath && /\/admin\//i.test(filePath);
172
- const hasAdminAuth = isAdminRoute && /(?:requireAdmin|adminOnly|orgRole|org:admin|isAdmin|checkRole|requireRole)/i.test(code);
172
+ const hasAdminAuth = isAdminRoute && /(?:requireAdmin|adminOnly|orgRole|org:admin|isAdmin|checkRole|requireRole|verifyAuth|checkPermission|assertAuth|ensureAuth|authorize)/i.test(code);
173
173
  if (hasAdminAuth && rateLimitRuleIds.has(rule.id))
174
174
  continue;
175
175
  // Skip npm package rules (VG863/VG864/VG865): only apply to package.json files
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "guardvibe",
3
- "version": "1.9.6",
3
+ "version": "2.0.0",
4
4
  "description": "Security MCP for vibe coding. 277 rules, 24 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": {