guardvibe 1.8.0 → 1.8.2
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 +6 -1
- package/build/cli.js +14 -1
- package/build/data/rules/modern-stack.js +2 -2
- package/build/index.d.ts +1 -1
- package/build/index.js +11 -4
- package/build/tools/export-sarif.js +4 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# GuardVibe
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/guardvibe)
|
|
4
|
+
[](https://opensource.org/licenses/Apache-2.0)
|
|
5
|
+
[](https://github.com/goklab/guardvibe/actions/workflows/ci.yml)
|
|
6
|
+
[](https://www.npmjs.com/package/guardvibe)
|
|
7
|
+
|
|
3
8
|
**The security MCP built for vibe coding.** 277 security rules covering the entire AI-generated code journey — from first line to production deployment.
|
|
4
9
|
|
|
5
10
|
Works with **Claude Code, Cursor, Gemini CLI, Codex, Windsurf**, and any MCP-compatible coding agent.
|
|
@@ -430,7 +435,7 @@ GuardVibe takes supply chain security seriously:
|
|
|
430
435
|
- **Minimal CI permissions** — GitHub Actions workflows use `permissions: contents: read` only
|
|
431
436
|
- **Zero runtime dependencies** — only MCP SDK and Zod (both widely audited)
|
|
432
437
|
|
|
433
|
-
To report a vulnerability, please email
|
|
438
|
+
To report a vulnerability, please email info@goklab.com or open a GitHub issue.
|
|
434
439
|
|
|
435
440
|
## License
|
|
436
441
|
|
package/build/cli.js
CHANGED
|
@@ -362,10 +362,23 @@ async function main() {
|
|
|
362
362
|
console.log(pkg.version);
|
|
363
363
|
process.exit(0);
|
|
364
364
|
}
|
|
365
|
-
if (args
|
|
365
|
+
if (args[0] === "--help" || args[0] === "-h") {
|
|
366
366
|
printUsage();
|
|
367
367
|
process.exit(0);
|
|
368
368
|
}
|
|
369
|
+
// No args: if stdin is a pipe, start MCP server; if TTY, show help
|
|
370
|
+
if (args.length === 0) {
|
|
371
|
+
if (process.stdin.isTTY) {
|
|
372
|
+
printUsage();
|
|
373
|
+
process.exit(0);
|
|
374
|
+
}
|
|
375
|
+
else {
|
|
376
|
+
// Started by MCP client (Claude Code, Cursor, etc.) — launch MCP server
|
|
377
|
+
const { startMcpServer } = await import("./index.js");
|
|
378
|
+
await startMcpServer();
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
369
382
|
const command = args[0];
|
|
370
383
|
if (command === "init") {
|
|
371
384
|
const platform = args[1]?.toLowerCase();
|
|
@@ -38,7 +38,7 @@ export const modernStackRules = [
|
|
|
38
38
|
severity: "high",
|
|
39
39
|
owasp: "A04:2023 Unrestricted Resource Consumption",
|
|
40
40
|
description: "File upload handler does not validate file type (MIME type or extension). Attackers can upload executable files, scripts, or malicious content.",
|
|
41
|
-
pattern: /(?:formData\.get|req\.file|
|
|
41
|
+
pattern: /(?:formData\.get\s*\(|req\.file\b|multer\s*\(|busboy|formidable\s*\(|Files?\s*\[)[\s\S]{0,500}?(?:writeFile|putObject|\.upload\s*\(|\.save\s*\(|createBucket|\.put\s*\()(?:(?!mime|type|extension|contentType|allowedTypes|accept|fileFilter|allowedMimeTypes)[\s\S]){0,200}/gi,
|
|
42
42
|
languages: ["javascript", "typescript"],
|
|
43
43
|
fix: "Always validate file types against an allowlist before storing. Check both MIME type and extension.",
|
|
44
44
|
fixCode: '// Validate file type before upload\nconst ALLOWED_TYPES = ["image/jpeg", "image/png", "image/webp"];\nconst file = formData.get("file") as File;\nif (!ALLOWED_TYPES.includes(file.type)) {\n return new Response("Invalid file type", { status: 400 });\n}\nif (file.size > 5 * 1024 * 1024) {\n return new Response("File too large", { status: 400 });\n}',
|
|
@@ -50,7 +50,7 @@ export const modernStackRules = [
|
|
|
50
50
|
severity: "medium",
|
|
51
51
|
owasp: "A04:2023 Unrestricted Resource Consumption",
|
|
52
52
|
description: "File upload handler does not enforce a file size limit. Attackers can upload extremely large files to exhaust storage or memory.",
|
|
53
|
-
pattern: /(?:formData\.get|req\.file|
|
|
53
|
+
pattern: /(?:formData\.get\s*\(|req\.file\b|multer\s*\()[\s\S]{0,300}?(?:writeFile|putObject|\.upload\s*\(|\.save\s*\(|\.put\s*\()(?:(?!size|limit|max|MB|GB|bytes|fileSizeLimit)[\s\S]){0,200}/gi,
|
|
54
54
|
languages: ["javascript", "typescript"],
|
|
55
55
|
fix: "Enforce a file size limit before processing uploads. Typical limits: 5MB for images, 50MB for documents.",
|
|
56
56
|
fixCode: '// Check file size before upload\nconst MAX_SIZE = 5 * 1024 * 1024; // 5MB\nconst file = formData.get("file") as File;\nif (file.size > MAX_SIZE) {\n return new Response("File too large (max 5MB)", { status: 400 });\n}',
|
package/build/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
export
|
|
2
|
+
export declare function startMcpServer(): Promise<void>;
|
package/build/index.js
CHANGED
|
@@ -288,6 +288,9 @@ server.tool("explain_remediation", "Deep explanation of a security finding: why
|
|
|
288
288
|
const results = explainRemediation(rule_id, code, format, rules);
|
|
289
289
|
return { content: [{ type: "text", text: results }] };
|
|
290
290
|
});
|
|
291
|
+
export async function startMcpServer() {
|
|
292
|
+
return main();
|
|
293
|
+
}
|
|
291
294
|
async function main() {
|
|
292
295
|
// Load plugins
|
|
293
296
|
const config = loadConfig(process.cwd());
|
|
@@ -319,7 +322,11 @@ async function main() {
|
|
|
319
322
|
await server.connect(transport);
|
|
320
323
|
console.error("GuardVibe Security MCP server running on stdio");
|
|
321
324
|
}
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
325
|
+
// Only auto-start when run directly (not imported by cli.ts)
|
|
326
|
+
const isDirectRun = process.argv[1]?.replace(/\.js$/, "").endsWith("index");
|
|
327
|
+
if (isDirectRun) {
|
|
328
|
+
main().catch((error) => {
|
|
329
|
+
console.error("Fatal error:", error);
|
|
330
|
+
process.exit(1);
|
|
331
|
+
});
|
|
332
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createRequire } from "module";
|
|
1
2
|
import { readFileSync, statSync } from "fs";
|
|
2
3
|
import { extname, basename, resolve } from "path";
|
|
3
4
|
import { analyzeCode } from "./check-code.js";
|
|
@@ -5,6 +6,8 @@ import { owaspRules } from "../data/rules/index.js";
|
|
|
5
6
|
import { loadConfig } from "../utils/config.js";
|
|
6
7
|
import { EXTENSION_MAP, DEFAULT_EXCLUDES } from "../utils/constants.js";
|
|
7
8
|
import { walkDirectory } from "../utils/walk-directory.js";
|
|
9
|
+
const _require = createRequire(import.meta.url);
|
|
10
|
+
const _pkg = _require("../../package.json");
|
|
8
11
|
function severityToLevel(severity) {
|
|
9
12
|
if (severity === "critical" || severity === "high")
|
|
10
13
|
return "error";
|
|
@@ -72,7 +75,7 @@ export function exportSarif(path, rules) {
|
|
|
72
75
|
tool: {
|
|
73
76
|
driver: {
|
|
74
77
|
name: "GuardVibe",
|
|
75
|
-
version:
|
|
78
|
+
version: _pkg.version,
|
|
76
79
|
informationUri: "https://guardvibe.dev",
|
|
77
80
|
rules: sarifRules,
|
|
78
81
|
},
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "guardvibe",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.2",
|
|
4
4
|
"description": "Security MCP for vibe coding. 277 rules, 22 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": {
|
|
7
|
-
"guardvibe": "build/
|
|
7
|
+
"guardvibe": "build/cli.js",
|
|
8
8
|
"guardvibe-init": "build/cli.js",
|
|
9
9
|
"guardvibe-scan": "build/cli.js"
|
|
10
10
|
},
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
],
|
|
80
80
|
"author": "GokLab",
|
|
81
81
|
"license": "Apache-2.0",
|
|
82
|
-
"homepage": "https://
|
|
82
|
+
"homepage": "https://guardvibe.dev",
|
|
83
83
|
"repository": {
|
|
84
84
|
"type": "git",
|
|
85
85
|
"url": "https://github.com/goklab/guardvibe.git"
|