@guardbee/mcp-server-auditor 0.1.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.
package/README.md ADDED
@@ -0,0 +1,108 @@
1
+ # @guardbee/mcp-server-auditor
2
+
3
+ MCP (Model Context Protocol) sunucusu — **başka MCP server'ların** tool tanımlarını güvensiz kalıplar için tarar.
4
+
5
+ `ai-code-scanner` genel LLM/AI entegrasyon koduna bakarken, bu paket özellikle bir MCP server'ın kendisine bakar: `server.tool(...)` ile tanımlanan bir tool ne kadar yetkili, parametreleri ne kadar gevşek, handler'ı hangi tehlikeli sink'lere (shell/dosya sistemi/HTTP/SQL) doğrudan tool girdisi geçiriyor. MCP ekosistemi hızla büyüyor ama bu server'ların güvenlik denetimi için yaygın bir araç henüz yok.
6
+
7
+ > Bu paket varsayılan olarak kullanım telemetrisi gönderir (tool adı + kısa parametreler, taranan kod hiçbir zaman dahil değil — bkz. [`@guardbee/mcp-telemetry`](../telemetry/README.md)). Kapatmak için `GUARDBEE_TELEMETRY=0`.
8
+
9
+ ```
10
+ Claude ──► mcp-server-auditor ──► Bir MCP server'ın kaynak kodu
11
+ │
12
+ ├─ Excessive agency (execSync(input.command), "run_shell" adlı bir tool)
13
+ ├─ Unsafe input (fetch(input.url) → SSRF, SQL string interpolation)
14
+ ├─ Loose schema (bir parametre z.any()/z.unknown() tipinde)
15
+ ├─ Secrets exposure (şema default'unda sabit API key, process.env'in tamamı)
16
+ └─ Network exposure (wildcard CORS)
17
+ ```
18
+
19
+ ---
20
+
21
+ ## Özellikler
22
+
23
+ - **10 kalıp, 5 kategori** — excessive-agency, unsafe-input, loose-schema, secrets-exposure, network-exposure
24
+ - Her bulguda **neden riskli olduğu ve ne yapılması gerektiği** (`recommendation`) — sadece "bulundu" demez
25
+ - SARIF 2.1.0 çıktısı — CI/CD entegrasyonu (GitHub Code Scanning vb.)
26
+ - `guardbee.yml` ile config dosyası desteği
27
+ - 32 unit test — her kalıp için hem pozitif hem negatif (yanlış-pozitif) senaryo
28
+
29
+ ---
30
+
31
+ ## Hızlı Başlangıç
32
+
33
+ ### Claude Desktop / MCP Client
34
+
35
+ ```json
36
+ {
37
+ "mcpServers": {
38
+ "guardbee-mcp-server-auditor": {
39
+ "command": "npx",
40
+ "args": ["-y", "@guardbee/mcp-server-auditor"]
41
+ }
42
+ }
43
+ }
44
+ ```
45
+
46
+ ### CLI (CI/CD)
47
+
48
+ ```bash
49
+ npx @guardbee/mcp-server-auditor scan ./src --fail-on=high --format=sarif > results.sarif
50
+ ```
51
+
52
+ ---
53
+
54
+ ## MCP Tools
55
+
56
+ | Tool | Açıklama |
57
+ |------|----------|
58
+ | `scan_text` | Verilen bir metin/kod parçasını tarar |
59
+ | `scan_file` | Tek bir dosyayı tarar |
60
+ | `scan_directory` | Bir dizini recursive tarar (`node_modules`, `.git`, `dist` otomatik atlanır) |
61
+ | `list_patterns` | Desteklenen tüm kalıpları kategoriye göre listeler |
62
+
63
+ ---
64
+
65
+ ## Tespit Edilen Kalıplar
66
+
67
+ | Kategori | Kalıp | Önem | Ne demek |
68
+ |---|---|---|---|
69
+ | excessive-agency | `shell_exec_from_tool_input` | critical | Tool handler'ı, tool girdisini doğrudan `execSync`/`spawn` gibi bir shell çağrısına geçiriyor |
70
+ | excessive-agency | `eval_of_tool_input` | critical | Tool girdisi `eval()`/`new Function()` ile kod olarak çalıştırılıyor |
71
+ | excessive-agency | `unrestricted_shell_tool_name` | high | Tool adı (`run_shell`, `execute_sql` vb.) doğrudan shell/SQL çalıştırma yetkisi ima ediyor |
72
+ | unsafe-input | `fs_write_from_raw_tool_input` | high | Tool girdisindeki bir path, doğrulama olmadan dosya yazma/silme çağrısına geçiyor (path traversal) |
73
+ | unsafe-input | `ssrf_fetch_from_tool_input` | high | Tool girdisindeki bir URL, allowlist olmadan doğrudan `fetch`/`axios`'a geçiyor (SSRF) |
74
+ | unsafe-input | `sql_injection_via_tool_input` | critical | Tool girdisi bir SQL string'ine template-literal ile enjekte ediliyor |
75
+ | loose-schema | `overly_permissive_tool_schema` | medium | Bir tool parametresi `z.any()`/`z.unknown()` tipinde — her şeyi kabul ediyor |
76
+ | secrets-exposure | `hardcoded_secret_in_tool_schema` | critical | Credential-benzeri bir şema alanının default değeri sabit bir literal |
77
+ | secrets-exposure | `full_env_exposed_to_tool_caller` | critical | `process.env`'in tamamı spread/stringify/return ediliyor (tek bir named değişken değil) |
78
+ | network-exposure | `permissive_cors_on_server` | medium | Wildcard CORS (`Access-Control-Allow-Origin: *`) ya da opsiyonsuz `cors()` |
79
+
80
+ Bunlar **heuristic** bulgulardır — tam bir AST/tip analizi değil, statik metin kalıbı taraması yapar. Düşük yanlış-pozitif oranı için tasarlandı ama her bulgu yine de manuel gözden geçirilmelidir.
81
+
82
+ ---
83
+
84
+ ## Yapılandırma (`guardbee.yml`)
85
+
86
+ ```yaml
87
+ mcp-server-auditor:
88
+ fail-on: high # any | critical | high | medium | low | none
89
+ max-files: 5000
90
+ exclude:
91
+ - "**/*.test.ts"
92
+ - "fixtures/"
93
+ ```
94
+
95
+ ---
96
+
97
+ ## Geliştirme
98
+
99
+ ```bash
100
+ npm run build
101
+ npm test # 32 unit test
102
+ ```
103
+
104
+ ---
105
+
106
+ ## Lisans
107
+
108
+ MIT — [GuardBee](https://guardbee.ai)
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=scanner.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/scanner.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,131 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { scanText } from "../scanner.js";
3
+ function idsOf(text) {
4
+ return scanText(text).map((f) => f.patternId);
5
+ }
6
+ describe("scanText — shell_exec_from_tool_input", () => {
7
+ it("yakalar: execSync(input.command)", () => {
8
+ expect(idsOf(`const out = execSync(input.command);`)).toContain("shell_exec_from_tool_input");
9
+ });
10
+ it("yakalar: spawn(params.cmd)", () => {
11
+ expect(idsOf(`spawn(params.cmd, params.args);`)).toContain("shell_exec_from_tool_input");
12
+ });
13
+ it("sabit bir komut çalıştırmayı yakalamaz", () => {
14
+ expect(idsOf(`execSync("ls -la /tmp");`)).not.toContain("shell_exec_from_tool_input");
15
+ });
16
+ });
17
+ describe("scanText — eval_of_tool_input", () => {
18
+ it("yakalar: eval(input.expression)", () => {
19
+ expect(idsOf(`const result = eval(input.expression);`)).toContain("eval_of_tool_input");
20
+ });
21
+ it("yakalar: new Function(args.code)", () => {
22
+ expect(idsOf(`const fn = new Function(args.code);`)).toContain("eval_of_tool_input");
23
+ });
24
+ it("sabit bir string'i eval etmeyi yakalamaz", () => {
25
+ expect(idsOf(`const result = eval("1 + 1");`)).not.toContain("eval_of_tool_input");
26
+ });
27
+ });
28
+ describe("scanText — unrestricted_shell_tool_name", () => {
29
+ it("yakalar: server.tool(\"run_shell\", ...)", () => {
30
+ expect(idsOf(`server.tool("run_shell", "runs a shell command", {}, handler);`)).toContain("unrestricted_shell_tool_name");
31
+ });
32
+ it("yakalar: .tool('execute_sql', ...)", () => {
33
+ expect(idsOf(`server.tool('execute_sql', "runs SQL", {}, handler);`)).toContain("unrestricted_shell_tool_name");
34
+ });
35
+ it("zararsız bir tool adını yakalamaz", () => {
36
+ expect(idsOf(`server.tool("query_table", "queries a table", {}, handler);`)).not.toContain("unrestricted_shell_tool_name");
37
+ });
38
+ });
39
+ describe("scanText — fs_write_from_raw_tool_input", () => {
40
+ it("yakalar: writeFileSync(input.path, data)", () => {
41
+ expect(idsOf(`writeFileSync(input.path, data);`)).toContain("fs_write_from_raw_tool_input");
42
+ });
43
+ it("yakalar: unlinkSync(params.filePath)", () => {
44
+ expect(idsOf(`unlinkSync(params.filePath);`)).toContain("fs_write_from_raw_tool_input");
45
+ });
46
+ it("sabit bir path'e yazmayı yakalamaz", () => {
47
+ expect(idsOf(`writeFileSync("./out.log", data);`)).not.toContain("fs_write_from_raw_tool_input");
48
+ });
49
+ });
50
+ describe("scanText — ssrf_fetch_from_tool_input", () => {
51
+ it("yakalar: fetch(input.url)", () => {
52
+ expect(idsOf(`await fetch(input.url);`)).toContain("ssrf_fetch_from_tool_input");
53
+ });
54
+ it("yakalar: axios.get(args.target)", () => {
55
+ expect(idsOf(`await axios.get(args.target);`)).toContain("ssrf_fetch_from_tool_input");
56
+ });
57
+ it("sabit bir URL'e fetch'i yakalamaz", () => {
58
+ expect(idsOf(`await fetch("https://api.guardbee.ai/status");`)).not.toContain("ssrf_fetch_from_tool_input");
59
+ });
60
+ });
61
+ describe("scanText — sql_injection_via_tool_input", () => {
62
+ it("yakalar: SELECT ... ${input.id}", () => {
63
+ const code = "const sql = `SELECT * FROM users WHERE id = ${input.id}`;";
64
+ expect(idsOf(code)).toContain("sql_injection_via_tool_input");
65
+ });
66
+ it("yakalar: DELETE ... ${params.table}", () => {
67
+ const code = "const sql = `DELETE FROM ${params.table} WHERE id = 1`;";
68
+ expect(idsOf(code)).toContain("sql_injection_via_tool_input");
69
+ });
70
+ it("parametrize edilmiş sorguyu yakalamaz", () => {
71
+ const code = `const sql = "SELECT * FROM users WHERE id = $1"; db.query(sql, [input.id]);`;
72
+ expect(idsOf(code)).not.toContain("sql_injection_via_tool_input");
73
+ });
74
+ });
75
+ describe("scanText — overly_permissive_tool_schema", () => {
76
+ it("yakalar: server.tool(...) içinde z.any()", () => {
77
+ const code = `server.tool("update_row", "desc", { data: z.any() }, handler);`;
78
+ expect(idsOf(code)).toContain("overly_permissive_tool_schema");
79
+ });
80
+ it("yakalar: z.unknown()", () => {
81
+ const code = `server.tool("query_table", "desc", { filter: z.unknown() }, handler);`;
82
+ expect(idsOf(code)).toContain("overly_permissive_tool_schema");
83
+ });
84
+ it("dar bir şemayı yakalamaz", () => {
85
+ const code = `server.tool("query_table", "desc", { table: z.string() }, handler);`;
86
+ expect(idsOf(code)).not.toContain("overly_permissive_tool_schema");
87
+ });
88
+ });
89
+ describe("scanText — hardcoded_secret_in_tool_schema", () => {
90
+ it("yakalar: apiKey: z.string().default(\"sk-...\")", () => {
91
+ const code = `const schema = { apiKey: z.string().default("sk-1234567890abcdef") };`;
92
+ expect(idsOf(code)).toContain("hardcoded_secret_in_tool_schema");
93
+ });
94
+ it("varsayılansız bir apiKey alanını yakalamaz", () => {
95
+ const code = `const schema = { apiKey: z.string() };`;
96
+ expect(idsOf(code)).not.toContain("hardcoded_secret_in_tool_schema");
97
+ });
98
+ it("PII olmayan kısa bir default'u yakalamaz", () => {
99
+ const code = `const schema = { status: z.string().default("active") };`;
100
+ expect(idsOf(code)).not.toContain("hardcoded_secret_in_tool_schema");
101
+ });
102
+ });
103
+ describe("scanText — full_env_exposed_to_tool_caller", () => {
104
+ it("yakalar: { ...process.env }", () => {
105
+ expect(idsOf(`return { content: [{ type: "text", text: JSON.stringify({ ...process.env }) }] };`)).toContain("full_env_exposed_to_tool_caller");
106
+ });
107
+ it("yakalar: JSON.stringify(process.env)", () => {
108
+ expect(idsOf(`const dump = JSON.stringify(process.env);`)).toContain("full_env_exposed_to_tool_caller");
109
+ });
110
+ it("yakalar: return process.env;", () => {
111
+ expect(idsOf(`function getEnv() {\n return process.env;\n}`)).toContain("full_env_exposed_to_tool_caller");
112
+ });
113
+ it("tek bir named env var okumasını yakalamaz", () => {
114
+ expect(idsOf(`const key = process.env.DATABASE_URL;`)).not.toContain("full_env_exposed_to_tool_caller");
115
+ });
116
+ it("destructuring ile named var okumasını yakalamaz", () => {
117
+ expect(idsOf(`const { DATABASE_URL, PORT } = process.env;`)).not.toContain("full_env_exposed_to_tool_caller");
118
+ });
119
+ });
120
+ describe("scanText — permissive_cors_on_server", () => {
121
+ it("yakalar: Access-Control-Allow-Origin: '*'", () => {
122
+ expect(idsOf(`res.setHeader("Access-Control-Allow-Origin", "*");`)).toContain("permissive_cors_on_server");
123
+ });
124
+ it("yakalar: cors() (opsiyonsuz)", () => {
125
+ expect(idsOf(`app.use(cors());`)).toContain("permissive_cors_on_server");
126
+ });
127
+ it("kısıtlı bir origin'i yakalamaz", () => {
128
+ expect(idsOf(`app.use(cors({ origin: "https://guardbee.ai" }));`)).not.toContain("permissive_cors_on_server");
129
+ });
130
+ });
131
+ //# sourceMappingURL=scanner.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.test.js","sourceRoot":"","sources":["../../src/__tests__/scanner.test.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,165 @@
1
+ #!/usr/bin/env node
2
+ import { startServer } from "./server.js";
3
+ import { scanFile, scanDirectory } from "./scanner.js";
4
+ import { buildSarif } from "./sarif.js";
5
+ import { loadConfig, configFilePath } from "./config.js";
6
+ import { statSync, readFileSync } from "fs";
7
+ import { resolve, dirname } from "path";
8
+ import { fileURLToPath } from "url";
9
+ const __dirname = dirname(fileURLToPath(import.meta.url));
10
+ function getVersion() {
11
+ try {
12
+ const pkg = JSON.parse(readFileSync(resolve(__dirname, "../package.json"), "utf8"));
13
+ return pkg.version;
14
+ }
15
+ catch {
16
+ return "0.0.0";
17
+ }
18
+ }
19
+ const SEV_ICON = {
20
+ critical: "🔴",
21
+ high: "🟠",
22
+ medium: "🟡",
23
+ low: "🔵",
24
+ };
25
+ function printText(findings, scannedFiles, durationMs) {
26
+ if (findings.length === 0) {
27
+ console.log(`✅ No MCP server security issues found in ${scannedFiles} file(s) (${durationMs}ms)`);
28
+ return;
29
+ }
30
+ const counts = {};
31
+ for (const f of findings)
32
+ counts[f.severity] = (counts[f.severity] ?? 0) + 1;
33
+ console.log(`⚠️ Found ${findings.length} MCP server security issue(s) in ${scannedFiles} file(s) (${durationMs}ms)`);
34
+ console.log(` Critical: ${counts["critical"] ?? 0} High: ${counts["high"] ?? 0} Medium: ${counts["medium"] ?? 0} Low: ${counts["low"] ?? 0}`);
35
+ console.log("");
36
+ for (const f of findings) {
37
+ const icon = SEV_ICON[f.severity] ?? "⚪";
38
+ console.log(`${icon} [${f.severity.toUpperCase()}] ${f.patternName} (${f.category})`);
39
+ if (f.file)
40
+ console.log(` File : ${f.file}:${f.line}:${f.column}`);
41
+ console.log(` Match : ${f.match}`);
42
+ console.log(` Recommendation : ${f.recommendation}`);
43
+ console.log("");
44
+ }
45
+ }
46
+ function parseArgs(args) {
47
+ const positionals = [];
48
+ let failOn = "any";
49
+ let format = "text";
50
+ let maxFiles = 5000;
51
+ for (const arg of args) {
52
+ if (arg.startsWith("--fail-on="))
53
+ failOn = arg.split("=")[1] ?? "any";
54
+ else if (arg.startsWith("--format="))
55
+ format = arg.split("=")[1] ?? "text";
56
+ else if (arg.startsWith("--max-files="))
57
+ maxFiles = parseInt(arg.split("=")[1] ?? "5000", 10);
58
+ else if (!arg.startsWith("--"))
59
+ positionals.push(arg);
60
+ }
61
+ return { positionals, failOn, format, maxFiles };
62
+ }
63
+ function shouldFail(findings, failOn) {
64
+ if (failOn === "none")
65
+ return false;
66
+ if (failOn === "any")
67
+ return findings.length > 0;
68
+ const RANK = { critical: 0, high: 1, medium: 2, low: 3 };
69
+ const threshold = RANK[failOn] ?? 1;
70
+ return findings.some((f) => (RANK[f.severity] ?? 3) <= threshold);
71
+ }
72
+ async function runCli(rawArgs) {
73
+ const { positionals, failOn: cliFail, format, maxFiles: cliMax } = parseArgs(rawArgs);
74
+ const target = positionals[0];
75
+ if (!target) {
76
+ console.error("Usage: guardbee-mcp-server-auditor scan <path> [--fail-on=any] [--format=text|json|sarif]");
77
+ process.exit(2);
78
+ }
79
+ const cfg = loadConfig(target, {
80
+ ...(cliFail !== "any" ? { failOn: cliFail } : {}),
81
+ ...(cliMax !== 5000 ? { maxFiles: cliMax } : {}),
82
+ });
83
+ const cfgPath = configFilePath(target);
84
+ if (cfgPath && format === "text")
85
+ process.stderr.write(`[guardbee] Using config: ${cfgPath}\n`);
86
+ const { failOn, maxFiles } = cfg;
87
+ let stat;
88
+ try {
89
+ stat = statSync(target);
90
+ }
91
+ catch {
92
+ console.error(`Path not found: ${target}`);
93
+ process.exit(2);
94
+ }
95
+ let findings;
96
+ let scannedFiles;
97
+ let durationMs;
98
+ if (stat.isDirectory()) {
99
+ const result = scanDirectory(target, { maxFiles, exclude: cfg.exclude });
100
+ findings = result.findings;
101
+ scannedFiles = result.scannedFiles;
102
+ durationMs = result.durationMs;
103
+ }
104
+ else {
105
+ const start = Date.now();
106
+ const result = scanFile(target);
107
+ findings = result.findings;
108
+ scannedFiles = result.skipped ? 0 : 1;
109
+ durationMs = Date.now() - start;
110
+ }
111
+ if (format === "json") {
112
+ console.log(JSON.stringify({ findings, scannedFiles, durationMs }, null, 2));
113
+ }
114
+ else if (format === "sarif") {
115
+ console.log(JSON.stringify(buildSarif(getVersion(), findings), null, 2));
116
+ }
117
+ else {
118
+ printText(findings, scannedFiles, durationMs);
119
+ }
120
+ process.exit(shouldFail(findings, failOn) ? 1 : 0);
121
+ }
122
+ function printHelp() {
123
+ console.log(`@guardbee/mcp-server-auditor
124
+
125
+ Usage (MCP server):
126
+ guardbee-mcp-server-auditor [serve]
127
+
128
+ Usage (CLI):
129
+ guardbee-mcp-server-auditor scan <path> Scan an MCP server's codebase for insecure tool-definition patterns
130
+
131
+ Options:
132
+ --fail-on=<level> Exit 1 if issues at this severity or above are found
133
+ Levels: any (default) | critical | high | medium | low | none
134
+ --format=<fmt> Output format: text (default) | json | sarif
135
+ --max-files=<n> Max files to scan (default: 5000)
136
+
137
+ Exit codes:
138
+ 0 No issues found (or none above --fail-on threshold)
139
+ 1 Issues found at or above threshold
140
+ 2 Error / bad arguments
141
+ `);
142
+ }
143
+ const [, , firstArg, ...rest] = process.argv;
144
+ if (!firstArg || firstArg === "serve") {
145
+ startServer().catch((err) => {
146
+ process.stderr.write(`[guardbee-mcp-server-auditor] Fatal error: ${err instanceof Error ? err.message : String(err)}\n`);
147
+ process.exit(1);
148
+ });
149
+ }
150
+ else if (firstArg === "--help" || firstArg === "-h") {
151
+ printHelp();
152
+ process.exit(0);
153
+ }
154
+ else if (firstArg === "scan") {
155
+ runCli(rest).catch((err) => {
156
+ console.error("Error:", err.message);
157
+ process.exit(2);
158
+ });
159
+ }
160
+ else {
161
+ console.error(`Unknown command: ${firstArg}`);
162
+ console.error("Run with --help for usage.");
163
+ process.exit(2);
164
+ }
165
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export interface McpServerAuditorConfig {
2
+ failOn: string;
3
+ maxFiles: number;
4
+ exclude: string[];
5
+ }
6
+ export declare function loadConfig(searchDir: string, cliOverrides?: Partial<McpServerAuditorConfig>): McpServerAuditorConfig;
7
+ export declare function configFilePath(searchDir: string): string | null;
8
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAkFD,wBAAgB,UAAU,CACxB,SAAS,EAAE,MAAM,EACjB,YAAY,GAAE,OAAO,CAAC,sBAAsB,CAAM,GACjD,sBAAsB,CAmBxB;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAE/D"}
package/dist/config.js ADDED
@@ -0,0 +1,102 @@
1
+ import { readFileSync, existsSync } from "fs";
2
+ import { resolve, join } from "path";
3
+ const DEFAULTS = {
4
+ failOn: "any",
5
+ maxFiles: 5000,
6
+ exclude: [],
7
+ };
8
+ function findConfigFile(startDir) {
9
+ const names = ["guardbee.yml", "guardbee.yaml", ".guardbee.yml"];
10
+ let dir = resolve(startDir);
11
+ for (let i = 0; i < 5; i++) {
12
+ for (const name of names) {
13
+ const p = join(dir, name);
14
+ if (existsSync(p))
15
+ return p;
16
+ }
17
+ const parent = resolve(dir, "..");
18
+ if (parent === dir)
19
+ break;
20
+ dir = parent;
21
+ }
22
+ return null;
23
+ }
24
+ // Minimal YAML parser — only handles the flat key: value and list items we need
25
+ function parseYaml(content) {
26
+ const root = {};
27
+ let currentSection = null;
28
+ let currentKey = null;
29
+ let currentList = null;
30
+ for (const rawLine of content.split("\n")) {
31
+ const line = rawLine.replace(/#.*$/, "");
32
+ if (!line.trim())
33
+ continue;
34
+ const indent = line.match(/^(\s*)/)?.[1].length ?? 0;
35
+ if (indent === 0 && line.trim().endsWith(":")) {
36
+ if (currentKey && currentList) {
37
+ root[currentSection][currentKey] = currentList;
38
+ currentList = null;
39
+ currentKey = null;
40
+ }
41
+ currentSection = line.trim().slice(0, -1);
42
+ root[currentSection] = {};
43
+ continue;
44
+ }
45
+ if (indent === 2 && currentSection) {
46
+ if (currentKey && currentList) {
47
+ root[currentSection][currentKey] = currentList;
48
+ currentList = null;
49
+ currentKey = null;
50
+ }
51
+ const colonIdx = line.indexOf(":");
52
+ if (colonIdx === -1)
53
+ continue;
54
+ const key = line.slice(0, colonIdx).trim();
55
+ const value = line.slice(colonIdx + 1).trim();
56
+ if (value === "") {
57
+ currentKey = key;
58
+ currentList = [];
59
+ }
60
+ else {
61
+ root[currentSection][key] = value;
62
+ }
63
+ continue;
64
+ }
65
+ if (indent === 4 && currentList !== null) {
66
+ const item = line.trim().replace(/^-\s*/, "").replace(/^['"]|['"]$/g, "");
67
+ currentList.push(item);
68
+ continue;
69
+ }
70
+ }
71
+ if (currentKey && currentList && currentSection) {
72
+ root[currentSection][currentKey] = currentList;
73
+ }
74
+ return root;
75
+ }
76
+ export function loadConfig(searchDir, cliOverrides = {}) {
77
+ const configPath = findConfigFile(searchDir);
78
+ if (!configPath)
79
+ return { ...DEFAULTS, ...cliOverrides };
80
+ let fileConfig = {};
81
+ try {
82
+ const raw = readFileSync(configPath, "utf8");
83
+ const parsed = parseYaml(raw);
84
+ const section = parsed["mcp-server-auditor"];
85
+ if (section) {
86
+ if (typeof section["fail-on"] === "string")
87
+ fileConfig.failOn = section["fail-on"];
88
+ if (typeof section["max-files"] === "string")
89
+ fileConfig.maxFiles = parseInt(section["max-files"], 10);
90
+ if (Array.isArray(section["exclude"]))
91
+ fileConfig.exclude = section["exclude"];
92
+ }
93
+ }
94
+ catch {
95
+ // ignore parse errors, use defaults
96
+ }
97
+ return { ...DEFAULTS, ...fileConfig, ...cliOverrides };
98
+ }
99
+ export function configFilePath(searchDir) {
100
+ return findConfigFile(searchDir);
101
+ }
102
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export { scanText, scanFile, scanDirectory } from "./scanner.js";
2
+ export { MCP_AUDITOR_PATTERNS } from "./patterns.js";
3
+ export type { Finding, ScanResult } from "./scanner.js";
4
+ export type { McpAuditPattern, AuditCategory } from "./patterns.js";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AACxD,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { scanText, scanFile, scanDirectory } from "./scanner.js";
2
+ export { MCP_AUDITOR_PATTERNS } from "./patterns.js";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,20 @@
1
+ export type AuditCategory = "excessive-agency" | "unsafe-input" | "loose-schema" | "secrets-exposure" | "network-exposure";
2
+ export interface McpAuditPattern {
3
+ id: string;
4
+ name: string;
5
+ category: AuditCategory;
6
+ pattern: RegExp;
7
+ severity: "critical" | "high" | "medium" | "low";
8
+ /** Neden riskli olduğu ve ne yapılması gerektiği — bulgu ile birlikte gösterilir. */
9
+ recommendation: string;
10
+ }
11
+ /**
12
+ * `ai-code-scanner`'ın aksine bu paket "LLM entegrasyon kodu"na değil,
13
+ * **MCP server'ın kendisine** bakıyor: bir tool tanımı (`server.tool(...)`)
14
+ * ne kadar yetkili, parametreleri ne kadar gevşek, handler'ı hangi
15
+ * sink'lere (shell/fs/http/sql) doğrudan tool girdisi geçiriyor. Regex'ler
16
+ * heuristic'tir — tam bir AST/tip analizi yapmaz, düşük yanlış-pozitifli
17
+ * kalıplara odaklanır (secret-scanner ve ai-code-scanner'la aynı felsefe).
18
+ */
19
+ export declare const MCP_AUDITOR_PATTERNS: McpAuditPattern[];
20
+ //# sourceMappingURL=patterns.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patterns.d.ts","sourceRoot":"","sources":["../src/patterns.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GACrB,kBAAkB,GAClB,cAAc,GACd,cAAc,GACd,kBAAkB,GAClB,kBAAkB,CAAC;AAEvB,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,aAAa,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IACjD,qFAAqF;IACrF,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,EAAE,eAAe,EAqGjD,CAAC"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * `ai-code-scanner`'ın aksine bu paket "LLM entegrasyon kodu"na değil,
3
+ * **MCP server'ın kendisine** bakıyor: bir tool tanımı (`server.tool(...)`)
4
+ * ne kadar yetkili, parametreleri ne kadar gevşek, handler'ı hangi
5
+ * sink'lere (shell/fs/http/sql) doğrudan tool girdisi geçiriyor. Regex'ler
6
+ * heuristic'tir — tam bir AST/tip analizi yapmaz, düşük yanlış-pozitifli
7
+ * kalıplara odaklanır (secret-scanner ve ai-code-scanner'la aynı felsefe).
8
+ */
9
+ export const MCP_AUDITOR_PATTERNS = [
10
+ // ── Excessive agency ───────────────────────────────────────────────────────
11
+ {
12
+ id: "shell_exec_from_tool_input",
13
+ name: "Tool handler passes raw tool input to a shell/process exec call",
14
+ category: "excessive-agency",
15
+ pattern: /\b(?:execSync|spawnSync|exec|spawn)\s*\(\s*(?:input|params|args)\s*\.\s*\w+/g,
16
+ severity: "critical",
17
+ recommendation: "A tool parameter is passed straight into a shell/process exec call. Any caller of this tool — including a prompt-injected LLM upstream — can run arbitrary commands. Validate against a strict allowlist of commands/args instead of executing the parameter directly.",
18
+ },
19
+ {
20
+ id: "eval_of_tool_input",
21
+ name: "Tool handler evaluates raw tool input as code",
22
+ category: "excessive-agency",
23
+ pattern: /\b(?:eval|new\s+Function)\s*\(\s*(?:input|params|args)\s*\.\s*\w+/g,
24
+ severity: "critical",
25
+ recommendation: "Executing a tool parameter as code turns any caller of this tool into a remote code execution vector. Never eval() input; parse and validate it as data instead.",
26
+ },
27
+ {
28
+ id: "unrestricted_shell_tool_name",
29
+ name: "Tool name grants shell/arbitrary code or SQL execution",
30
+ category: "excessive-agency",
31
+ pattern: /\.tool\(\s*["'](?:run_shell|execute_command|run_command|execute_shell|eval_code|execute_code|run_script|shell_exec|run_sql|execute_sql|run_query)["']/gi,
32
+ severity: "high",
33
+ recommendation: "A tool named like this typically hands the calling LLM arbitrary shell/code/SQL execution. If intentional, gate it behind an explicit opt-in config flag (off by default) and a strict allowlist — not just a cautious-sounding tool description.",
34
+ },
35
+ // ── Unsafe input handling ───────────────────────────────────────────────────
36
+ {
37
+ id: "fs_write_from_raw_tool_input",
38
+ name: "Filesystem write/delete uses a raw tool input path",
39
+ category: "unsafe-input",
40
+ pattern: /\b(?:writeFileSync|unlinkSync|rmSync|appendFileSync|renameSync)\s*\(\s*(?:input|params|args)\s*\.\s*\w+/g,
41
+ severity: "high",
42
+ recommendation: "A path taken directly from tool input is used in a filesystem write/delete call with no visible sanitization — a caller can supply '../'-style paths (path traversal). Resolve the path and verify it stays inside an allowed base directory before touching the filesystem.",
43
+ },
44
+ {
45
+ id: "ssrf_fetch_from_tool_input",
46
+ name: "Outbound HTTP request target comes directly from tool input",
47
+ category: "unsafe-input",
48
+ pattern: /\b(?:fetch|axios\.get|axios\.post|axios\.request|http\.get|https\.get)\s*\(\s*(?:input|params|args)\s*\.\s*\w+/g,
49
+ severity: "high",
50
+ recommendation: "A request URL/host taken directly from tool input, with no visible allowlist, lets a caller make this server request internal or private URLs (SSRF) — e.g. a cloud metadata endpoint. Validate the host against an allowlist before making the request.",
51
+ },
52
+ {
53
+ id: "sql_injection_via_tool_input",
54
+ name: "SQL statement built by interpolating raw tool input",
55
+ category: "unsafe-input",
56
+ pattern: /\b(?:SELECT|INSERT|UPDATE|DELETE)\b[\s\S]{0,200}?\$\{\s*(?:input|params|args)\s*\.\s*\w+/gi,
57
+ severity: "critical",
58
+ recommendation: "A SQL statement is built with a template-literal interpolation of a raw tool parameter — classic SQL injection, now reachable by anything that can call this tool. Use parameterized queries; never interpolate tool input into SQL text.",
59
+ },
60
+ // ── Loose schema ────────────────────────────────────────────────────────────
61
+ {
62
+ id: "overly_permissive_tool_schema",
63
+ name: "Tool parameter typed z.any()/z.unknown()",
64
+ category: "loose-schema",
65
+ pattern: /\.tool\(\s*["'][\w-]+["'][\s\S]{0,300}?:\s*z\.(?:any|unknown)\(\)/g,
66
+ severity: "medium",
67
+ recommendation: "A parameter typed z.any()/z.unknown() accepts anything, including shapes the handler doesn't expect — this often becomes an injection point downstream (a NoSQL/SQL filter, a shell arg). Give every parameter the narrowest schema that covers legitimate input.",
68
+ },
69
+ // ── Secrets exposure ────────────────────────────────────────────────────────
70
+ {
71
+ id: "hardcoded_secret_in_tool_schema",
72
+ name: "Credential-shaped tool parameter has a hardcoded default",
73
+ category: "secrets-exposure",
74
+ pattern: /\b(?:apiKey|token|secret|password|accessKey)\s*:\s*z\.string\(\)[^,\n]*\.default\(\s*["'][^"']{8,}["']\s*\)/gi,
75
+ severity: "critical",
76
+ recommendation: "A tool schema's default value for a credential-shaped field is a hardcoded literal. Defaults ship in the published server/manifest and are visible to anyone who inspects it. Never default a secret field — require it to be supplied via environment/config.",
77
+ },
78
+ {
79
+ id: "full_env_exposed_to_tool_caller",
80
+ name: "The whole process.env is spread, stringified, or returned",
81
+ category: "secrets-exposure",
82
+ pattern: /(?:\.\.\.\s*process\.env\b)|(?:JSON\.stringify\(\s*process\.env\s*\))|(?:return\s+process\.env\s*[;\n])/g,
83
+ severity: "critical",
84
+ recommendation: "The entire process.env object is being spread, serialized, or returned instead of reading one named variable. If this happens inside a tool handler, the calling LLM — and thus any prompt-injected instruction upstream — can potentially read every secret in this process's environment. Only read specific, named variables.",
85
+ },
86
+ // ── Network exposure ─────────────────────────────────────────────────────────
87
+ {
88
+ id: "permissive_cors_on_server",
89
+ name: "Wildcard or default-open CORS on the server's HTTP transport",
90
+ category: "network-exposure",
91
+ pattern: /\bAccess-Control-Allow-Origin["']?\s*[:,=]\s*["']\*["']|\bcors\(\s*\)/g,
92
+ severity: "medium",
93
+ recommendation: "A wildcard CORS origin (or the cors() middleware called with no options, which defaults to allow-all) lets any website make requests to this MCP server's HTTP transport from a victim's browser. Restrict Access-Control-Allow-Origin to a known allowlist.",
94
+ },
95
+ ];
96
+ //# sourceMappingURL=patterns.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patterns.js","sourceRoot":"","sources":["../src/patterns.ts"],"names":[],"mappings":"AAiBA;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAsB;IACrD,8EAA8E;IAC9E;QACE,EAAE,EAAE,4BAA4B;QAChC,IAAI,EAAE,iEAAiE;QACvE,QAAQ,EAAE,kBAAkB;QAC5B,OAAO,EAAE,8EAA8E;QACvF,QAAQ,EAAE,UAAU;QACpB,cAAc,EACZ,wQAAwQ;KAC3Q;IACD;QACE,EAAE,EAAE,oBAAoB;QACxB,IAAI,EAAE,+CAA+C;QACrD,QAAQ,EAAE,kBAAkB;QAC5B,OAAO,EAAE,oEAAoE;QAC7E,QAAQ,EAAE,UAAU;QACpB,cAAc,EACZ,kKAAkK;KACrK;IACD;QACE,EAAE,EAAE,8BAA8B;QAClC,IAAI,EAAE,wDAAwD;QAC9D,QAAQ,EAAE,kBAAkB;QAC5B,OAAO,EACL,yJAAyJ;QAC3J,QAAQ,EAAE,MAAM;QAChB,cAAc,EACZ,mPAAmP;KACtP;IAED,+EAA+E;IAC/E;QACE,EAAE,EAAE,8BAA8B;QAClC,IAAI,EAAE,oDAAoD;QAC1D,QAAQ,EAAE,cAAc;QACxB,OAAO,EAAE,0GAA0G;QACnH,QAAQ,EAAE,MAAM;QAChB,cAAc,EACZ,8QAA8Q;KACjR;IACD;QACE,EAAE,EAAE,4BAA4B;QAChC,IAAI,EAAE,6DAA6D;QACnE,QAAQ,EAAE,cAAc;QACxB,OAAO,EAAE,iHAAiH;QAC1H,QAAQ,EAAE,MAAM;QAChB,cAAc,EACZ,0PAA0P;KAC7P;IACD;QACE,EAAE,EAAE,8BAA8B;QAClC,IAAI,EAAE,qDAAqD;QAC3D,QAAQ,EAAE,cAAc;QACxB,OAAO,EAAE,4FAA4F;QACrG,QAAQ,EAAE,UAAU;QACpB,cAAc,EACZ,2OAA2O;KAC9O;IAED,+EAA+E;IAC/E;QACE,EAAE,EAAE,+BAA+B;QACnC,IAAI,EAAE,0CAA0C;QAChD,QAAQ,EAAE,cAAc;QACxB,OAAO,EAAE,oEAAoE;QAC7E,QAAQ,EAAE,QAAQ;QAClB,cAAc,EACZ,mQAAmQ;KACtQ;IAED,+EAA+E;IAC/E;QACE,EAAE,EAAE,iCAAiC;QACrC,IAAI,EAAE,0DAA0D;QAChE,QAAQ,EAAE,kBAAkB;QAC5B,OAAO,EAAE,+GAA+G;QACxH,QAAQ,EAAE,UAAU;QACpB,cAAc,EACZ,gQAAgQ;KACnQ;IACD;QACE,EAAE,EAAE,iCAAiC;QACrC,IAAI,EAAE,2DAA2D;QACjE,QAAQ,EAAE,kBAAkB;QAC5B,OAAO,EAAE,0GAA0G;QACnH,QAAQ,EAAE,UAAU;QACpB,cAAc,EACZ,kUAAkU;KACrU;IAED,gFAAgF;IAChF;QACE,EAAE,EAAE,2BAA2B;QAC/B,IAAI,EAAE,8DAA8D;QACpE,QAAQ,EAAE,kBAAkB;QAC5B,OAAO,EAAE,wEAAwE;QACjF,QAAQ,EAAE,QAAQ;QAClB,cAAc,EACZ,8PAA8P;KACjQ;CACF,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Finding } from "./scanner.js";
2
+ export declare function buildSarif(toolVersion: string, findings: Finding[]): object;
3
+ //# sourceMappingURL=sarif.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sarif.d.ts","sourceRoot":"","sources":["../src/sarif.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AA6B5C,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,CAyD3E"}
package/dist/sarif.js ADDED
@@ -0,0 +1,60 @@
1
+ function severityToLevel(sev) {
2
+ if (sev === "critical" || sev === "high")
3
+ return "error";
4
+ if (sev === "medium")
5
+ return "warning";
6
+ return "note";
7
+ }
8
+ export function buildSarif(toolVersion, findings) {
9
+ const rulesMap = new Map();
10
+ const results = [];
11
+ for (const f of findings) {
12
+ if (!rulesMap.has(f.patternId)) {
13
+ rulesMap.set(f.patternId, {
14
+ id: f.patternId,
15
+ name: f.patternName.replace(/[^a-zA-Z0-9]/g, ""),
16
+ shortDescription: { text: f.patternName },
17
+ fullDescription: { text: f.recommendation },
18
+ helpUri: "https://guardbee.ai/docs/mcp-server-auditor",
19
+ properties: {
20
+ "problem.severity": f.severity,
21
+ tags: ["security", "mcp-security", f.category],
22
+ },
23
+ });
24
+ }
25
+ const result = {
26
+ ruleId: f.patternId,
27
+ level: severityToLevel(f.severity),
28
+ message: { text: `${f.patternName} — ${f.recommendation}` },
29
+ };
30
+ if (f.file) {
31
+ result.locations = [
32
+ {
33
+ physicalLocation: {
34
+ artifactLocation: { uri: f.file, uriBaseId: "%SRCROOT%" },
35
+ region: { startLine: f.line, startColumn: f.column },
36
+ },
37
+ },
38
+ ];
39
+ }
40
+ results.push(result);
41
+ }
42
+ return {
43
+ $schema: "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
44
+ version: "2.1.0",
45
+ runs: [
46
+ {
47
+ tool: {
48
+ driver: {
49
+ name: "@guardbee/mcp-server-auditor",
50
+ version: toolVersion,
51
+ informationUri: "https://guardbee.ai",
52
+ rules: Array.from(rulesMap.values()),
53
+ },
54
+ },
55
+ results,
56
+ },
57
+ ],
58
+ };
59
+ }
60
+ //# sourceMappingURL=sarif.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sarif.js","sourceRoot":"","sources":["../src/sarif.ts"],"names":[],"mappings":"AAuBA,SAAS,eAAe,CAAC,GAAW;IAClC,IAAI,GAAG,KAAK,UAAU,IAAI,GAAG,KAAK,MAAM;QAAE,OAAO,OAAO,CAAC;IACzD,IAAI,GAAG,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IACvC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,WAAmB,EAAE,QAAmB;IACjE,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAqB,CAAC;IAC9C,MAAM,OAAO,GAAkB,EAAE,CAAC;IAElC,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC;YAC/B,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,EAAE;gBACxB,EAAE,EAAE,CAAC,CAAC,SAAS;gBACf,IAAI,EAAE,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC;gBAChD,gBAAgB,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE;gBACzC,eAAe,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,cAAc,EAAE;gBAC3C,OAAO,EAAE,6CAA6C;gBACtD,UAAU,EAAE;oBACV,kBAAkB,EAAE,CAAC,CAAC,QAAQ;oBAC9B,IAAI,EAAE,CAAC,UAAU,EAAE,cAAc,EAAE,CAAC,CAAC,QAAQ,CAAC;iBAC/C;aACF,CAAC,CAAC;QACL,CAAC;QAED,MAAM,MAAM,GAAgB;YAC1B,MAAM,EAAE,CAAC,CAAC,SAAS;YACnB,KAAK,EAAE,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC;YAClC,OAAO,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,WAAW,MAAM,CAAC,CAAC,cAAc,EAAE,EAAE;SAC5D,CAAC;QAEF,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;YACX,MAAM,CAAC,SAAS,GAAG;gBACjB;oBACE,gBAAgB,EAAE;wBAChB,gBAAgB,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE;wBACzD,MAAM,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;qBACrD;iBACF;aACF,CAAC;QACJ,CAAC;QAED,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACvB,CAAC;IAED,OAAO;QACL,OAAO,EACL,gGAAgG;QAClG,OAAO,EAAE,OAAO;QAChB,IAAI,EAAE;YACJ;gBACE,IAAI,EAAE;oBACJ,MAAM,EAAE;wBACN,IAAI,EAAE,8BAA8B;wBACpC,OAAO,EAAE,WAAW;wBACpB,cAAc,EAAE,qBAAqB;wBACrC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;qBACrC;iBACF;gBACD,OAAO;aACR;SACF;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,32 @@
1
+ import { type McpAuditPattern } from "./patterns.js";
2
+ export interface Finding {
3
+ patternId: string;
4
+ patternName: string;
5
+ category: McpAuditPattern["category"];
6
+ severity: McpAuditPattern["severity"];
7
+ recommendation: string;
8
+ file?: string;
9
+ line: number;
10
+ column: number;
11
+ /** Eşleşen kod parçası — bir secret değil bir kalıp olduğu için redakte edilmez. */
12
+ match: string;
13
+ context: string;
14
+ }
15
+ export interface ScanResult {
16
+ scannedFiles: number;
17
+ skippedFiles: number;
18
+ totalFindings: number;
19
+ findings: Finding[];
20
+ durationMs: number;
21
+ }
22
+ export declare function scanText(text: string, filePath?: string): Finding[];
23
+ export declare function scanFile(filePath: string): {
24
+ findings: Finding[];
25
+ skipped: boolean;
26
+ };
27
+ export declare function scanDirectory(dirPath: string, options?: {
28
+ maxFiles?: number;
29
+ include?: string[];
30
+ exclude?: string[];
31
+ }): ScanResult;
32
+ //# sourceMappingURL=scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AAEA,OAAO,EAAwB,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAE3E,MAAM,WAAW,OAAO;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,eAAe,CAAC,UAAU,CAAC,CAAC;IACtC,QAAQ,EAAE,eAAe,CAAC,UAAU,CAAC,CAAC;IACtC,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,oFAAoF;IACpF,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAoBD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,EAAE,CAoCnE;AAED,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG;IAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAqBpF;AAED,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;CAAO,GAC1E,UAAU,CAuDZ"}
@@ -0,0 +1,128 @@
1
+ import { readFileSync, statSync, readdirSync } from "fs";
2
+ import { join, relative, extname } from "path";
3
+ import { MCP_AUDITOR_PATTERNS } from "./patterns.js";
4
+ const SKIP_EXTENSIONS = new Set([
5
+ ".png", ".jpg", ".jpeg", ".gif", ".svg", ".ico", ".webp", ".bmp",
6
+ ".pdf", ".zip", ".tar", ".gz", ".bz2", ".rar", ".7z",
7
+ ".exe", ".dll", ".so", ".dylib", ".bin", ".wasm",
8
+ ".mp3", ".mp4", ".avi", ".mov", ".wav",
9
+ ".ttf", ".woff", ".woff2", ".eot",
10
+ ".lock",
11
+ ]);
12
+ const SKIP_DIRS = new Set([
13
+ "node_modules", ".git", ".svn", "dist", "build", ".next",
14
+ "__pycache__", ".mypy_cache", ".pytest_cache", "venv", ".venv",
15
+ "coverage", ".nyc_output",
16
+ ]);
17
+ const MAX_FILE_SIZE = 1 * 1024 * 1024; // 1 MB
18
+ const MAX_CONTEXT_LENGTH = 240;
19
+ export function scanText(text, filePath) {
20
+ const findings = [];
21
+ const lines = text.split("\n");
22
+ for (const p of MCP_AUDITOR_PATTERNS) {
23
+ const re = new RegExp(p.pattern.source, p.pattern.flags);
24
+ let m;
25
+ while ((m = re.exec(text)) !== null) {
26
+ const matchStr = m[0];
27
+ const before = text.slice(0, m.index);
28
+ const line = before.split("\n").length;
29
+ const lastNl = before.lastIndexOf("\n");
30
+ const column = m.index - (lastNl === -1 ? 0 : lastNl + 1) + 1;
31
+ const contextLine = lines[line - 1] ?? "";
32
+ findings.push({
33
+ patternId: p.id,
34
+ patternName: p.name,
35
+ category: p.category,
36
+ severity: p.severity,
37
+ recommendation: p.recommendation,
38
+ file: filePath,
39
+ line,
40
+ column,
41
+ match: matchStr.trim().slice(0, MAX_CONTEXT_LENGTH),
42
+ context: contextLine.trim().slice(0, MAX_CONTEXT_LENGTH),
43
+ });
44
+ // Sıfır genişlikli eşleşmelerde sonsuz döngüyü önle
45
+ if (m.index === re.lastIndex)
46
+ re.lastIndex++;
47
+ }
48
+ }
49
+ return findings;
50
+ }
51
+ export function scanFile(filePath) {
52
+ const ext = extname(filePath).toLowerCase();
53
+ if (SKIP_EXTENSIONS.has(ext))
54
+ return { findings: [], skipped: true };
55
+ let stat;
56
+ try {
57
+ stat = statSync(filePath);
58
+ }
59
+ catch {
60
+ return { findings: [], skipped: true };
61
+ }
62
+ if (!stat.isFile() || stat.size > MAX_FILE_SIZE)
63
+ return { findings: [], skipped: true };
64
+ let content;
65
+ try {
66
+ content = readFileSync(filePath, "utf8");
67
+ }
68
+ catch {
69
+ return { findings: [], skipped: true };
70
+ }
71
+ return { findings: scanText(content, filePath), skipped: false };
72
+ }
73
+ export function scanDirectory(dirPath, options = {}) {
74
+ const start = Date.now();
75
+ const { maxFiles = 5000, include, exclude } = options;
76
+ const allFindings = [];
77
+ let scannedFiles = 0;
78
+ let skippedFiles = 0;
79
+ function walk(dir) {
80
+ if (scannedFiles + skippedFiles >= maxFiles)
81
+ return;
82
+ let entries;
83
+ try {
84
+ entries = readdirSync(dir, { withFileTypes: true });
85
+ }
86
+ catch {
87
+ return;
88
+ }
89
+ for (const entry of entries) {
90
+ const fullPath = join(dir, entry.name);
91
+ if (entry.isDirectory()) {
92
+ if (SKIP_DIRS.has(entry.name) || entry.name.startsWith("."))
93
+ continue;
94
+ if (exclude?.some((ex) => entry.name === ex || fullPath.includes(ex)))
95
+ continue;
96
+ walk(fullPath);
97
+ }
98
+ else if (entry.isFile()) {
99
+ const relPath = relative(dirPath, fullPath);
100
+ if (exclude?.some((ex) => relPath.includes(ex))) {
101
+ skippedFiles++;
102
+ continue;
103
+ }
104
+ if (include && !include.some((inc) => relPath.includes(inc))) {
105
+ skippedFiles++;
106
+ continue;
107
+ }
108
+ const { findings, skipped } = scanFile(fullPath);
109
+ if (skipped) {
110
+ skippedFiles++;
111
+ }
112
+ else {
113
+ scannedFiles++;
114
+ allFindings.push(...findings);
115
+ }
116
+ }
117
+ }
118
+ }
119
+ walk(dirPath);
120
+ return {
121
+ scannedFiles,
122
+ skippedFiles,
123
+ totalFindings: allFindings.length,
124
+ findings: allFindings,
125
+ durationMs: Date.now() - start,
126
+ };
127
+ }
128
+ //# sourceMappingURL=scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function startServer(): Promise<void>;
2
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAkCA,wBAAsB,WAAW,kBAmFhC"}
package/dist/server.js ADDED
@@ -0,0 +1,87 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import { instrumentServer } from "@guardbee/mcp-telemetry";
4
+ import { z } from "zod";
5
+ import { scanText, scanFile, scanDirectory } from "./scanner.js";
6
+ import { MCP_AUDITOR_PATTERNS } from "./patterns.js";
7
+ function formatFindings(findings, scannedFiles, durationMs) {
8
+ if (findings.length === 0) {
9
+ return `✅ No MCP server security issues found. Scanned ${scannedFiles} file(s) in ${durationMs}ms.`;
10
+ }
11
+ const bySeverity = { critical: 0, high: 0, medium: 0, low: 0 };
12
+ for (const f of findings)
13
+ bySeverity[f.severity]++;
14
+ const lines = [
15
+ `⚠️ Found ${findings.length} MCP server security issue(s) in ${scannedFiles} file(s) (${durationMs}ms)`,
16
+ ` Critical: ${bySeverity.critical} High: ${bySeverity.high} Medium: ${bySeverity.medium} Low: ${bySeverity.low}`,
17
+ "",
18
+ ];
19
+ for (const f of findings) {
20
+ const loc = f.file ? `${f.file}:${f.line}:${f.column}` : `line ${f.line}:${f.column}`;
21
+ lines.push(`[${f.severity.toUpperCase()}] ${f.patternName} (${f.category})`);
22
+ lines.push(` Location : ${loc}`);
23
+ lines.push(` Match : ${f.match}`);
24
+ lines.push(` Recommendation : ${f.recommendation}`);
25
+ lines.push("");
26
+ }
27
+ return lines.join("\n");
28
+ }
29
+ export async function startServer() {
30
+ const server = new McpServer({
31
+ name: "guardbee-mcp-server-auditor",
32
+ version: "0.1.0",
33
+ });
34
+ instrumentServer(server, "mcp-server-auditor");
35
+ server.tool("scan_text", "Scan a text string or code snippet for insecure MCP server/tool-definition patterns (excessive-agency tool names, shell/eval/SQL/SSRF sinks fed by raw tool input, overly permissive schemas, hardcoded secrets, wildcard CORS).", {
36
+ content: z.string().describe("The code content to scan"),
37
+ label: z.string().optional().describe("Optional label shown in findings (e.g. filename)"),
38
+ }, async ({ content, label }) => {
39
+ const findings = scanText(content, label);
40
+ return { content: [{ type: "text", text: formatFindings(findings, 1, 0) }] };
41
+ });
42
+ server.tool("scan_file", "Scan a single file for insecure MCP server/tool-definition patterns", {
43
+ path: z.string().describe("Absolute or relative path to the file to scan"),
44
+ }, async ({ path: filePath }) => {
45
+ const { findings, skipped } = scanFile(filePath);
46
+ if (skipped) {
47
+ return {
48
+ content: [{ type: "text", text: `⏭️ File skipped (binary, too large, or unreadable): ${filePath}` }],
49
+ };
50
+ }
51
+ return { content: [{ type: "text", text: formatFindings(findings, 1, 0) }] };
52
+ });
53
+ server.tool("scan_directory", "Recursively scan an MCP server's codebase for insecure tool-definition patterns. Automatically skips node_modules, .git, dist, and binary files.", {
54
+ path: z.string().describe("Absolute or relative path to the directory to scan"),
55
+ maxFiles: z.number().optional().describe("Maximum number of files to scan (default: 5000)"),
56
+ include: z
57
+ .array(z.string())
58
+ .optional()
59
+ .describe("Only scan files whose path contains one of these strings (e.g. [\".ts\", \"src/tools\"])"),
60
+ exclude: z
61
+ .array(z.string())
62
+ .optional()
63
+ .describe("Skip files/dirs whose path contains one of these strings"),
64
+ }, async ({ path: dirPath, maxFiles, include, exclude }) => {
65
+ const result = scanDirectory(dirPath, { maxFiles, include, exclude });
66
+ return { content: [{ type: "text", text: formatFindings(result.findings, result.scannedFiles, result.durationMs) }] };
67
+ });
68
+ server.tool("list_patterns", "List all MCP server security patterns that the auditor can detect, grouped by category", {}, async () => {
69
+ const lines = ["Supported MCP server security patterns:\n"];
70
+ const byCategory = new Map();
71
+ for (const p of MCP_AUDITOR_PATTERNS) {
72
+ const list = byCategory.get(p.category) ?? [];
73
+ list.push(p);
74
+ byCategory.set(p.category, list);
75
+ }
76
+ for (const [category, patterns] of byCategory) {
77
+ lines.push(`[${category}]`);
78
+ for (const p of patterns)
79
+ lines.push(` • ${p.name} (${p.id}, ${p.severity})`);
80
+ lines.push("");
81
+ }
82
+ return { content: [{ type: "text", text: lines.join("\n") }] };
83
+ });
84
+ const transport = new StdioServerTransport();
85
+ await server.connect(transport);
86
+ }
87
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@guardbee/mcp-server-auditor",
3
+ "version": "0.1.0",
4
+ "description": "MCP server that audits other MCP servers' tool definitions for insecure patterns — excessive-agency tool names, shell/eval/SQL/SSRF sinks fed by raw tool input, overly permissive schemas, hardcoded secrets, and wildcard CORS",
5
+ "type": "module",
6
+ "bin": {
7
+ "guardbee-mcp-server-auditor": "./dist/cli.js"
8
+ },
9
+ "main": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "import": "./dist/index.js",
14
+ "types": "./dist/index.d.ts"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist",
19
+ "README.md"
20
+ ],
21
+ "dependencies": {
22
+ "@modelcontextprotocol/sdk": "^1.0.0",
23
+ "zod": "^4.5.4",
24
+ "@guardbee/mcp-telemetry": "^0.1.0"
25
+ },
26
+ "keywords": [
27
+ "mcp",
28
+ "security",
29
+ "mcp-security",
30
+ "ai-security",
31
+ "sast",
32
+ "guardbee",
33
+ "devtools"
34
+ ],
35
+ "license": "MIT",
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "https://github.com/GuardBee/guardbee-mcp.git"
39
+ },
40
+ "scripts": {
41
+ "build": "tsc",
42
+ "dev": "tsc --watch",
43
+ "start": "node dist/cli.js",
44
+ "test": "vitest run"
45
+ }
46
+ }