guardvibe 3.0.38 → 3.0.39

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.
@@ -341,6 +341,9 @@ export function analyzeCode(code, language, framework, filePath, configDir, rule
341
341
  const isWebhookRoute = filePath && /webhook/i.test(filePath);
342
342
  const isCronRoute = filePath && /(?:cron|scheduled|jobs?)\//i.test(filePath);
343
343
  const isAdminRoute = filePath && /\/admin\//i.test(filePath);
344
+ // Server-side batch context: scripts, migrations, seeds. These run offline or
345
+ // on-deploy, not against user requests, so DoS-from-unbounded-results doesn't apply.
346
+ const isBatchScriptFile = filePath && /\/(?:scripts?|migrations?|seeds?|fixtures?)\//i.test(filePath);
344
347
  // Skip rate-limit rules when the file installs a global rate limiter via app.use().
345
348
  // Covers `app.use(rateLimit({...}))`, `app.use(limiter)`, `app.use('/api', rateLimit({...}))`,
346
349
  // and named middleware vars matching limiter naming conventions.
@@ -370,6 +373,15 @@ export function analyzeCode(code, language, framework, filePath, configDir, rule
370
373
  // Skip rate limiting for cron and webhook routes
371
374
  if (isCronRoute && rateLimitRuleIds.has(rule.id))
372
375
  continue;
376
+ // Skip VG955 (Missing Pagination) in non-user-facing contexts:
377
+ // scripts, migrations, seeds, cron jobs. These read all records by design
378
+ // for batch processing, not for serving to clients.
379
+ if (rule.id === "VG955" && (isBatchScriptFile || isCronRoute))
380
+ continue;
381
+ // Skip VG955 in bulk-* server actions (bulk-archive, bulk-approve, bulk-ban etc.)
382
+ // These intentionally process a caller-provided list of IDs.
383
+ if (rule.id === "VG955" && filePath && /\/bulk-[\w-]+\.(?:ts|tsx|js|jsx)$/i.test(filePath))
384
+ continue;
373
385
  if (isWebhookRoute && rateLimitRuleIds.has(rule.id))
374
386
  continue;
375
387
  // Skip rate limiting for admin routes with auth guard
@@ -617,6 +629,18 @@ export function analyzeCode(code, language, framework, filePath, configDir, rule
617
629
  if (!hasPublishingFields && !mainPointsToBuild && startsAsApp)
618
630
  continue;
619
631
  }
632
+ // Skip VG955 (Missing Pagination) when the query is bounded by ID(s):
633
+ // findMany({ where: { id: x } }) returns at most 1; findMany({ where: { id: { in: [...] } } })
634
+ // is bounded by the caller-provided list. Same applies to *Id fields like partnerId, userId.
635
+ if (rule.id === "VG955") {
636
+ const matched = match[0];
637
+ if (/\bin\s*:\s*\[/i.test(matched))
638
+ continue; // where: { x: { in: [...] } }
639
+ if (/\b(?:id|[a-zA-Z]+Id)\s*:\s*\{?\s*in\s*:/i.test(matched))
640
+ continue; // where: { partnerId: { in: ids } }
641
+ if (/\b(?:id|[a-zA-Z]+Id)\s*:\s*[a-zA-Z_$]/i.test(matched))
642
+ continue; // where: { id: someVar }
643
+ }
620
644
  // Skip VG106 for non-secret variable names (TokenCount, tokenBalance, hashMap, etc.)
621
645
  // and for comparisons against literals/null/undefined that are emptiness checks,
622
646
  // not timing-sensitive secret equality (e.g. token !== '' or apiKey == null).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "guardvibe",
3
- "version": "3.0.38",
3
+ "version": "3.0.39",
4
4
  "mcpName": "io.github.goklab/guardvibe",
5
5
  "description": "Security MCP for vibe coding. 365 rules, 38 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",