guardvibe 3.0.40 → 3.0.42
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/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
[](https://www.npmjs.com/package/guardvibe)
|
|
7
7
|
[](https://codecov.io/gh/goklab/guardvibe)
|
|
8
8
|
|
|
9
|
-
**The security MCP built for vibe coding.** 365 security rules,
|
|
9
|
+
**The security MCP built for vibe coding.** 365 security rules, 36 tools covering the entire AI-generated code journey — from first line to production deployment.
|
|
10
10
|
|
|
11
11
|
Works with **Claude Code, Cursor, Gemini CLI, Codex, VS Code (Copilot), Windsurf**, and any MCP-compatible coding agent.
|
|
12
12
|
|
|
@@ -14,7 +14,7 @@ Works with **Claude Code, Cursor, Gemini CLI, Codex, VS Code (Copilot), Windsurf
|
|
|
14
14
|
|
|
15
15
|
Most security tools are built for enterprise security teams. GuardVibe is built for **you** — the developer using AI to build and ship web apps fast.
|
|
16
16
|
|
|
17
|
-
- **365 security rules,
|
|
17
|
+
- **365 security rules, 36 tools** purpose-built for the stacks AI agents generate
|
|
18
18
|
- **Zero setup friction** — `npx guardvibe` and you're scanning
|
|
19
19
|
- **No account required** — runs 100% locally, no API keys, no cloud
|
|
20
20
|
- **Understands your stack** — not generic SAST, but rules that know Next.js, Supabase, Stripe, Clerk, and the tools you actually use
|
|
@@ -441,7 +441,7 @@ If your AI agent cannot connect to GuardVibe:
|
|
|
441
441
|
|
|
442
442
|
1. **Restart your IDE/agent.** MCP servers are started by the host application. After running `npx guardvibe init`, restart Claude Code, Cursor, or Gemini CLI for the config to take effect.
|
|
443
443
|
2. **Check the config path.** Run `npx guardvibe init claude` again and verify the output shows the correct config file location (`.mcp.json` in your project root for Claude Code, `.cursor/mcp.json` for Cursor).
|
|
444
|
-
3. **Re-run `init` to upgrade.** When upgrading GuardVibe, re-run `npx guardvibe init claude` — `.mcp.json` is pinned to a specific version (e.g. `guardvibe@3.0.
|
|
444
|
+
3. **Re-run `init` to upgrade.** When upgrading GuardVibe, re-run `npx guardvibe init claude` — `.mcp.json` is pinned to a specific version (e.g. `guardvibe@3.0.41`) at init time for fast deterministic startup. Stale pins won't auto-update.
|
|
445
445
|
4. **Verify Node.js version.** GuardVibe requires Node.js >= 18.0.0. Check with `node --version`.
|
|
446
446
|
5. **Check npx cache.** If you upgraded GuardVibe and the old version is cached, run `npx -y guardvibe@latest` to force the latest version.
|
|
447
447
|
|
|
@@ -8,7 +8,7 @@ export const advancedSecurityRules = [
|
|
|
8
8
|
severity: "high",
|
|
9
9
|
owasp: "A02:2025 Injection",
|
|
10
10
|
description: "User input is interpolated into HTTP response headers. Attackers can inject CRLF characters to add arbitrary headers (Set-Cookie, Location) or split the response.",
|
|
11
|
-
pattern: /(?:setHeader|set|append|headers\.set)\s*\(\s*["'][^"']+["']\s*,\s*(?:`[^`]*\$\{|[^"']*\+\s*(?:req\.|request\.|params\.|query\.|searchParams|input|body|user))/gi,
|
|
11
|
+
pattern: /(?:res(?:ponse)?\.(?:setHeader|set|append)|headers\.(?:set|append)|setHeader|appendHeader)\s*\(\s*["'][^"']+["']\s*,\s*(?:`[^`]*\$\{|[^"']*\+\s*(?:req\.|request\.|params\.|query\.|searchParams|input|body|user))/gi,
|
|
12
12
|
languages: ["javascript", "typescript"],
|
|
13
13
|
fix: "Never interpolate user input into response headers. Sanitize by removing \\r and \\n characters.",
|
|
14
14
|
fixCode: '// Sanitize header values\nconst safeValue = userInput.replace(/[\\r\\n]/g, "");\nres.setHeader("Content-Disposition", `attachment; filename="${safeValue}"`);',
|
package/build/index.js
CHANGED
|
@@ -60,7 +60,7 @@ function mergeStatsIntoOutput(results, summary, format) {
|
|
|
60
60
|
const server = new McpServer({
|
|
61
61
|
name: "guardvibe",
|
|
62
62
|
version: pkg.version,
|
|
63
|
-
description: "Security MCP for vibe coding — single source of truth for AI assistants. 365 security rules and
|
|
63
|
+
description: "Security MCP for vibe coding — single source of truth for AI assistants. 365 security rules and 36 tools. Use full_audit for a comprehensive PASS/FAIL/WARN verdict with deterministic result hash, coverage %, and unified report across code, secrets, dependencies, config, taint analysis, and auth coverage. IMPORTANT: When full_audit returns FAIL/WARN, call remediation_plan to get a mandatory section-by-section fix checklist covering ALL 6 sections (not just code). After fixing, call verify_remediation to confirm all sections were addressed. Same code = same hash = same results regardless of which AI assistant runs it. Covers OWASP, Next.js, Supabase, Stripe, Clerk, Prisma, Hono, AI SDK, MCP server security, host hardening. Maps to SOC2, PCI-DSS, HIPAA, GDPR, ISO27001, EU AI Act. Runs 100% locally with zero configuration.",
|
|
64
64
|
});
|
|
65
65
|
// Tool 1: Analyze code for security vulnerabilities
|
|
66
66
|
server.tool("check_code", "Analyze inline code for security vulnerabilities (OWASP Top 10, XSS, SQL injection, insecure patterns). Pass code as a string parameter. For scanning files on disk, use scan_file instead. Example: check_code({code: 'app.get(...)', language: 'javascript'})", {
|
|
@@ -321,8 +321,8 @@ export function analyzeCode(code, language, framework, filePath, configDir, rule
|
|
|
321
321
|
// - VG010/VG011/VG013/VG014: injection rules trigger on payload strings like
|
|
322
322
|
// agent.get('/?q=' + sqlPayload) which match the regex but aren't database calls
|
|
323
323
|
// - VG042/VG678: HTTP-response/security-header rules (tests don't serve to real users)
|
|
324
|
-
const isTestFile = filePath && /(?:\.(?:spec|test|e2e|stories)\.(?:ts|tsx|js|jsx|mjs|cjs)$|\/__tests__\/|\/tests?\/|\/cypress\/|\/playwright\/)/i.test(filePath);
|
|
325
|
-
if (isTestFile && ["VG001", "VG062", "VG010", "VG011", "VG013", "VG014", "VG042", "VG678"].includes(rule.id))
|
|
324
|
+
const isTestFile = filePath && /(?:\.(?:[\w-]+-)?(?:spec|test|e2e|stories|cy)\.(?:ts|tsx|js|jsx|mjs|cjs)$|\/__tests__\/|\/tests?\/|\/cypress\/|\/playwright\/)/i.test(filePath);
|
|
325
|
+
if (isTestFile && ["VG001", "VG062", "VG010", "VG011", "VG013", "VG014", "VG042", "VG130", "VG678"].includes(rule.id))
|
|
326
326
|
continue;
|
|
327
327
|
// Skip Expo-specific rule (VG708) when project is not an Expo app.
|
|
328
328
|
// The rule's regex incorrectly matches the literal strings "app.json"/"app.config.ts"
|
|
@@ -625,7 +625,10 @@ export function analyzeCode(code, language, framework, filePath, configDir, rule
|
|
|
625
625
|
// Skip VG863 for non-publishable apps. Signals that this is an application, not a library:
|
|
626
626
|
// no publishing fields (bin/exports/module/types), main does not point at a build dir,
|
|
627
627
|
// and start script runs a runtime/framework directly.
|
|
628
|
+
// Also skip when "private": true — npm refuses to publish private packages outright.
|
|
628
629
|
if (rule.id === "VG863") {
|
|
630
|
+
if (/"private"\s*:\s*true\b/.test(code))
|
|
631
|
+
continue;
|
|
629
632
|
const hasPublishingFields = /"(?:bin|exports|module|types|typings)"\s*:/i.test(code);
|
|
630
633
|
const mainPointsToBuild = /"main"\s*:\s*"(?:dist|build|lib|out)\//i.test(code);
|
|
631
634
|
const runtimeNames = "node|nodemon|tsx|ts-node|next|nest|vite|remix|astro";
|
|
@@ -637,6 +640,7 @@ export function analyzeCode(code, language, framework, filePath, configDir, rule
|
|
|
637
640
|
// Skip VG955 (Missing Pagination) when the query is bounded by ID(s):
|
|
638
641
|
// findMany({ where: { id: x } }) returns at most 1; findMany({ where: { id: { in: [...] } } })
|
|
639
642
|
// is bounded by the caller-provided list. Same applies to *Id fields like partnerId, userId.
|
|
643
|
+
// Shorthand form { userId } / { teamId } counts as bound — these are tenant-scoped queries.
|
|
640
644
|
if (rule.id === "VG955") {
|
|
641
645
|
const matched = match[0];
|
|
642
646
|
if (/\bin\s*:\s*\[/i.test(matched))
|
|
@@ -645,6 +649,8 @@ export function analyzeCode(code, language, framework, filePath, configDir, rule
|
|
|
645
649
|
continue; // where: { partnerId: { in: ids } }
|
|
646
650
|
if (/\b(?:id|[a-zA-Z]+Id)\s*:\s*[a-zA-Z_$]/i.test(matched))
|
|
647
651
|
continue; // where: { id: someVar }
|
|
652
|
+
if (/\b(?:id|[a-zA-Z]+Id)\s*[,}]/i.test(matched))
|
|
653
|
+
continue; // where: { userId } shorthand
|
|
648
654
|
}
|
|
649
655
|
// Skip VG106 for non-secret variable names (TokenCount, tokenBalance, hashMap, etc.)
|
|
650
656
|
// and for comparisons against literals/null/undefined that are emptiness checks,
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "guardvibe",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.42",
|
|
4
4
|
"mcpName": "io.github.goklab/guardvibe",
|
|
5
|
-
"description": "Security MCP for vibe coding. 365 rules,
|
|
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",
|
|
7
7
|
"bin": {
|
|
8
8
|
"guardvibe": "build/cli.js",
|