guardvibe 3.0.27 → 3.0.29

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.
@@ -31,7 +31,7 @@ export const coreRules = [
31
31
  severity: "high",
32
32
  owasp: "A01:2025 Broken Access Control",
33
33
  description: "API route handler without authentication middleware or auth check.",
34
- pattern: /(?:app|router)\.(get|post|put|delete|patch)\s*\(\s*['"](?!(?:\/(?:api\/)?)?(?:health|status|ping|ready|live|metrics|public|favicon|robots|sitemap)\b)[^'"]*['"]\s*,\s*(?:async\s+)?\(?(?:req|request)/gi,
34
+ pattern: /(?:app|router)\.(get|post|put|delete|patch)\s*\(\s*['"](?!(?:\/(?:api\/)?)?(?:health|status|ping|ready|live|metrics|public|favicon|robots|sitemap)\b)[^'"]*['"]\s*,\s*(?:async\s+)?\(?\b(?:req|request)\b/gi,
35
35
  languages: ["javascript", "typescript"],
36
36
  fix: "Add authentication middleware before route handlers: app.get('/api/data', authMiddleware, handler). Use frameworks like Passport.js, Clerk, or Auth0.",
37
37
  fixCode: "// Add auth middleware before handler\napp.get('/api/data', authMiddleware, async (req, res) => {\n // handler code\n});",
@@ -162,6 +162,16 @@ function hasAuthGuardPattern(code) {
162
162
  if (/await\s+(?:\w+\.)*\w*(?:auth|Auth|session|Session|permission|Permission|guard|Guard|verify|Verify|protect|Protect|check|Check|ensure|Ensure|require|Require|assert|Assert|authorize|Authorize)\w*\s*\(/i.test(code)) {
163
163
  return true;
164
164
  }
165
+ // Pattern 4: Express-style middleware function with auth-related name (sync, takes req/res/next).
166
+ // e.g. `function requireAuth(req, res, next)` or `const authMiddleware = (req, res, next) => {`
167
+ if (/(?:function\s+(?:require|auth|protect|verify|guard|ensure|check|assert|authorize)\w*\s*\(\s*req\b|(?:const|let)\s+(?:require|auth|protect|verify|guard|ensure|check|assert|authorize)\w*\s*=\s*(?:async\s+)?\(\s*req\b)/i.test(code)) {
168
+ return true;
169
+ }
170
+ // Pattern 5: middleware passed inline to express route registration.
171
+ // e.g. `app.get('/x', requireAuth, handler)` or `router.post('/y', authMiddleware, ...)`.
172
+ if (/(?:app|router)\.(?:get|post|put|delete|patch|all|use)\s*\([^,)]+,\s*(?:require|auth|protect|verify|guard|ensure|check|assert|authorize|isAuthenticated|isLoggedIn|hasPermission)\w*\s*[,\)]/i.test(code)) {
173
+ return true;
174
+ }
165
175
  return false;
166
176
  }
167
177
  /**
@@ -304,6 +314,20 @@ export function analyzeCode(code, language, framework, filePath, configDir, rule
304
314
  continue;
305
315
  if (rule.id.startsWith("VG21") && !filePath && language !== "yaml")
306
316
  continue;
317
+ // Skip credential rules in test files — fixtures and assertions intentionally use fake values.
318
+ const isTestFile = filePath && /(?:\.(?:spec|test|e2e|stories)\.(?:ts|tsx|js|jsx|mjs|cjs)$|\/__tests__\/|\/tests?\/|\/cypress\/|\/playwright\/)/i.test(filePath);
319
+ if (isTestFile && (rule.id === "VG001" || rule.id === "VG062"))
320
+ continue;
321
+ // Skip Expo-specific rule (VG708) when project is not an Expo app.
322
+ // The rule's regex incorrectly matches the literal strings "app.json"/"app.config.ts"
323
+ // appearing in unrelated configs (e.g. angular.json's tsConfig field).
324
+ if (rule.id === "VG708" && filePath) {
325
+ const fileName = filePath.split("/").pop() ?? "";
326
+ const isExpoConfigFile = /^app\.(json|config\.(js|ts|mjs|cjs))$/.test(fileName);
327
+ const importsExpo = /(?:from\s+['"]expo[\w-]*['"]|require\s*\(\s*['"]expo[\w-]*['"])/i.test(code);
328
+ if (!isExpoConfigFile && !importsExpo)
329
+ continue;
330
+ }
307
331
  // ── Context-aware rule skipping (pattern-agnostic) ──────────────
308
332
  const authRuleIds = new Set(["VG420", "VG952", "VG002", "VG402"]);
309
333
  const adminRoleRuleIds = new Set(["VG426", "VG957"]);
@@ -538,12 +562,45 @@ export function analyzeCode(code, language, framework, filePath, configDir, rule
538
562
  if (isHumanReadableString(lines, lineNumber))
539
563
  continue;
540
564
  }
565
+ // Skip credential rules when the variable name signals test/example/mock intent.
566
+ // e.g. `testingPassword`, `examplePassword`, `mockApiKey`, `placeholderSecret`.
567
+ if (rule.id === "VG001" || rule.id === "VG062") {
568
+ const matchedLine = lines[lineNumber - 1] ?? "";
569
+ if (/(?:^|\s|\b)(?:testing|example|mock|placeholder|sample|demo|fake|dummy|stub|fixture)[A-Z_]/.test(matchedLine))
570
+ continue;
571
+ }
572
+ // Skip VG010 (SQL injection) on Angular HTTP service calls — http.get/post/etc.
573
+ // are HTTP client methods, not SQL. The existing pattern's `get` keyword catches them.
574
+ if (rule.id === "VG010") {
575
+ const matchedLine = lines[lineNumber - 1] ?? "";
576
+ const isHttpClientCall = /(?:this\.)?(?:http|httpClient|httpService|api|client)\.(?:get|post|put|delete|patch|head|options)\s*\(/i.test(matchedLine);
577
+ const importsHttpClient = /from\s+['"]@angular\/common\/http['"]/i.test(code) || /import\s+.*HttpClient/i.test(code);
578
+ const fileIsAngularService = filePath ? /\.(?:service|component|directive|pipe|guard|resolver|interceptor)\.ts$/i.test(filePath) : false;
579
+ if (isHttpClientCall && (importsHttpClient || fileIsAngularService))
580
+ continue;
581
+ // Also skip when matched call has no SQL keyword anywhere on the line — covers fetch/axios template-literal URLs.
582
+ const hasSqlKeyword = /\b(?:SELECT|INSERT|UPDATE|DELETE|FROM|WHERE|JOIN|UNION|DROP|TRUNCATE|ALTER|CREATE\s+TABLE)\b/i.test(matchedLine);
583
+ const isFetchOrAxios = /(?:fetch|axios|got|ky|undici|request)\s*[.\(]|axios\.(?:get|post|put|delete|patch)/i.test(matchedLine);
584
+ if (isFetchOrAxios && !hasSqlKeyword)
585
+ continue;
586
+ }
541
587
  // Skip supply chain rules for known legitimate packages
542
588
  if (["VG872", "VG873"].includes(rule.id)) {
543
589
  const pkgMatch = /"([\w@/-]+)"/.exec(match[0]);
544
590
  if (pkgMatch && isLegitimatePackage(pkgMatch[1]))
545
591
  continue;
546
592
  }
593
+ // Skip VG863 for non-publishable apps. Signals that this is an application, not a library:
594
+ // no publishing fields (bin/exports/module/types), main does not point at a build dir,
595
+ // and start script runs a runtime/framework directly.
596
+ if (rule.id === "VG863") {
597
+ const hasPublishingFields = /"(?:bin|exports|module|types|typings)"\s*:/i.test(code);
598
+ const mainPointsToBuild = /"main"\s*:\s*"(?:dist|build|lib|out)\//i.test(code);
599
+ const runtimeNames = "node|nodemon|tsx|ts-node|next|nest|vite|remix|astro";
600
+ const startsAsApp = new RegExp('"start"\\s*:\\s*"(?:' + runtimeNames + ')\\b', "i").test(code);
601
+ if (!hasPublishingFields && !mainPointsToBuild && startsAsApp)
602
+ continue;
603
+ }
547
604
  // Skip VG106 for non-secret variable names (TokenCount, tokenBalance, hashMap, etc.)
548
605
  if (rule.id === "VG106") {
549
606
  const varName = match[0].split(/\s*(?:===|!==|==|!=)/)[0].trim();
@@ -649,6 +706,11 @@ function isDuplicatePair(a, b) {
649
706
  // Same rule name = same vulnerability
650
707
  if (a.rule.name === b.rule.name)
651
708
  return true;
709
+ // Both are SQL injection variants — VG010 (generic) and VG123 (template literal specific) overlap.
710
+ // VG123 is more specific so it should dominate. isMoreSpecific handles the prefix order.
711
+ const sqlInjectionRules = new Set(["VG010", "VG123"]);
712
+ if (sqlInjectionRules.has(a.rule.id) && sqlInjectionRules.has(b.rule.id))
713
+ return true;
652
714
  // Both are XSS/innerHTML related — the core VG012+VG408 duplicate case
653
715
  if (a.rule.name.includes("innerHTML") && b.rule.name.includes("innerHTML"))
654
716
  return true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "guardvibe",
3
- "version": "3.0.27",
3
+ "version": "3.0.29",
4
4
  "mcpName": "io.github.goklab/guardvibe",
5
5
  "description": "Security MCP for vibe coding. 365 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",