mcp-security-scanner 1.0.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/LICENSE +21 -0
- package/README.ar.md +662 -0
- package/README.bn.md +662 -0
- package/README.bs.md +662 -0
- package/README.da.md +662 -0
- package/README.de.md +662 -0
- package/README.el.md +662 -0
- package/README.es.md +662 -0
- package/README.fr.md +663 -0
- package/README.hi.md +662 -0
- package/README.it.md +662 -0
- package/README.ja.md +663 -0
- package/README.ko.md +662 -0
- package/README.md +662 -0
- package/README.no.md +662 -0
- package/README.pl.md +662 -0
- package/README.pt-BR.md +662 -0
- package/README.ru.md +662 -0
- package/README.th.md +662 -0
- package/README.tr.md +662 -0
- package/README.uk.md +663 -0
- package/README.vi.md +662 -0
- package/README.zh-TW.md +661 -0
- package/README.zh.md +661 -0
- package/dist/config/env-scanner.d.ts +3 -0
- package/dist/config/env-scanner.d.ts.map +1 -0
- package/dist/config/env-scanner.js +85 -0
- package/dist/config/env-scanner.js.map +1 -0
- package/dist/config/index.d.ts +3 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +169 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/mcp-config-parser.d.ts +16 -0
- package/dist/config/mcp-config-parser.d.ts.map +1 -0
- package/dist/config/mcp-config-parser.js +86 -0
- package/dist/config/mcp-config-parser.js.map +1 -0
- package/dist/config/server-verification.d.ts +5 -0
- package/dist/config/server-verification.d.ts.map +1 -0
- package/dist/config/server-verification.js +221 -0
- package/dist/config/server-verification.js.map +1 -0
- package/dist/data/dangerous-sinks.d.ts +13 -0
- package/dist/data/dangerous-sinks.d.ts.map +1 -0
- package/dist/data/dangerous-sinks.js +45 -0
- package/dist/data/dangerous-sinks.js.map +1 -0
- package/dist/data/owasp-mcp-top10.d.ts +12 -0
- package/dist/data/owasp-mcp-top10.d.ts.map +1 -0
- package/dist/data/owasp-mcp-top10.js +95 -0
- package/dist/data/owasp-mcp-top10.js.map +1 -0
- package/dist/data/poisoning-patterns.d.ts +15 -0
- package/dist/data/poisoning-patterns.d.ts.map +1 -0
- package/dist/data/poisoning-patterns.js +146 -0
- package/dist/data/poisoning-patterns.js.map +1 -0
- package/dist/data/popular-packages.d.ts +2 -0
- package/dist/data/popular-packages.d.ts.map +1 -0
- package/dist/data/popular-packages.js +71 -0
- package/dist/data/popular-packages.js.map +1 -0
- package/dist/data/secret-patterns.d.ts +8 -0
- package/dist/data/secret-patterns.d.ts.map +1 -0
- package/dist/data/secret-patterns.js +129 -0
- package/dist/data/secret-patterns.js.map +1 -0
- package/dist/deps/index.d.ts +3 -0
- package/dist/deps/index.d.ts.map +1 -0
- package/dist/deps/index.js +308 -0
- package/dist/deps/index.js.map +1 -0
- package/dist/deps/install-script-detector.d.ts +9 -0
- package/dist/deps/install-script-detector.d.ts.map +1 -0
- package/dist/deps/install-script-detector.js +98 -0
- package/dist/deps/install-script-detector.js.map +1 -0
- package/dist/deps/lockfile-parser.d.ts +15 -0
- package/dist/deps/lockfile-parser.d.ts.map +1 -0
- package/dist/deps/lockfile-parser.js +123 -0
- package/dist/deps/lockfile-parser.js.map +1 -0
- package/dist/deps/typosquat-checker.d.ts +10 -0
- package/dist/deps/typosquat-checker.d.ts.map +1 -0
- package/dist/deps/typosquat-checker.js +84 -0
- package/dist/deps/typosquat-checker.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +315 -0
- package/dist/index.js.map +1 -0
- package/dist/meta/sources.d.ts +3 -0
- package/dist/meta/sources.d.ts.map +1 -0
- package/dist/meta/sources.js +43 -0
- package/dist/meta/sources.js.map +1 -0
- package/dist/protocol/mcp-server.d.ts +4 -0
- package/dist/protocol/mcp-server.d.ts.map +1 -0
- package/dist/protocol/mcp-server.js +32 -0
- package/dist/protocol/mcp-server.js.map +1 -0
- package/dist/protocol/tools.d.ts +3 -0
- package/dist/protocol/tools.d.ts.map +1 -0
- package/dist/protocol/tools.js +21 -0
- package/dist/protocol/tools.js.map +1 -0
- package/dist/report/index.d.ts +3 -0
- package/dist/report/index.d.ts.map +1 -0
- package/dist/report/index.js +259 -0
- package/dist/report/index.js.map +1 -0
- package/dist/report/json-report.d.ts +4 -0
- package/dist/report/json-report.d.ts.map +1 -0
- package/dist/report/json-report.js +61 -0
- package/dist/report/json-report.js.map +1 -0
- package/dist/report/markdown.d.ts +3 -0
- package/dist/report/markdown.d.ts.map +1 -0
- package/dist/report/markdown.js +89 -0
- package/dist/report/markdown.js.map +1 -0
- package/dist/report/sarif.d.ts +3 -0
- package/dist/report/sarif.d.ts.map +1 -0
- package/dist/report/sarif.js +56 -0
- package/dist/report/sarif.js.map +1 -0
- package/dist/runtime/client.d.ts +31 -0
- package/dist/runtime/client.d.ts.map +1 -0
- package/dist/runtime/client.js +53 -0
- package/dist/runtime/client.js.map +1 -0
- package/dist/runtime/index.d.ts +3 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +239 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/pinning.d.ts +21 -0
- package/dist/runtime/pinning.d.ts.map +1 -0
- package/dist/runtime/pinning.js +74 -0
- package/dist/runtime/pinning.js.map +1 -0
- package/dist/runtime/schema-analyzer.d.ts +14 -0
- package/dist/runtime/schema-analyzer.d.ts.map +1 -0
- package/dist/runtime/schema-analyzer.js +204 -0
- package/dist/runtime/schema-analyzer.js.map +1 -0
- package/dist/runtime/tool-analyzer.d.ts +6 -0
- package/dist/runtime/tool-analyzer.d.ts.map +1 -0
- package/dist/runtime/tool-analyzer.js +92 -0
- package/dist/runtime/tool-analyzer.js.map +1 -0
- package/dist/static/analyzers/code-execution.d.ts +4 -0
- package/dist/static/analyzers/code-execution.d.ts.map +1 -0
- package/dist/static/analyzers/code-execution.js +72 -0
- package/dist/static/analyzers/code-execution.js.map +1 -0
- package/dist/static/analyzers/command-injection.d.ts +4 -0
- package/dist/static/analyzers/command-injection.d.ts.map +1 -0
- package/dist/static/analyzers/command-injection.js +62 -0
- package/dist/static/analyzers/command-injection.js.map +1 -0
- package/dist/static/analyzers/info-disclosure.d.ts +4 -0
- package/dist/static/analyzers/info-disclosure.d.ts.map +1 -0
- package/dist/static/analyzers/info-disclosure.js +65 -0
- package/dist/static/analyzers/info-disclosure.js.map +1 -0
- package/dist/static/analyzers/insecure-crypto.d.ts +4 -0
- package/dist/static/analyzers/insecure-crypto.d.ts.map +1 -0
- package/dist/static/analyzers/insecure-crypto.js +65 -0
- package/dist/static/analyzers/insecure-crypto.js.map +1 -0
- package/dist/static/analyzers/logging-audit.d.ts +4 -0
- package/dist/static/analyzers/logging-audit.d.ts.map +1 -0
- package/dist/static/analyzers/logging-audit.js +81 -0
- package/dist/static/analyzers/logging-audit.js.map +1 -0
- package/dist/static/analyzers/path-traversal.d.ts +4 -0
- package/dist/static/analyzers/path-traversal.d.ts.map +1 -0
- package/dist/static/analyzers/path-traversal.js +42 -0
- package/dist/static/analyzers/path-traversal.js.map +1 -0
- package/dist/static/analyzers/prototype-pollution.d.ts +4 -0
- package/dist/static/analyzers/prototype-pollution.d.ts.map +1 -0
- package/dist/static/analyzers/prototype-pollution.js +80 -0
- package/dist/static/analyzers/prototype-pollution.js.map +1 -0
- package/dist/static/analyzers/regex-dos.d.ts +4 -0
- package/dist/static/analyzers/regex-dos.d.ts.map +1 -0
- package/dist/static/analyzers/regex-dos.js +78 -0
- package/dist/static/analyzers/regex-dos.js.map +1 -0
- package/dist/static/analyzers/secret-hardcoded.d.ts +4 -0
- package/dist/static/analyzers/secret-hardcoded.d.ts.map +1 -0
- package/dist/static/analyzers/secret-hardcoded.js +70 -0
- package/dist/static/analyzers/secret-hardcoded.js.map +1 -0
- package/dist/static/analyzers/ssrf.d.ts +4 -0
- package/dist/static/analyzers/ssrf.d.ts.map +1 -0
- package/dist/static/analyzers/ssrf.js +39 -0
- package/dist/static/analyzers/ssrf.js.map +1 -0
- package/dist/static/analyzers/unsafe-regex.d.ts +4 -0
- package/dist/static/analyzers/unsafe-regex.d.ts.map +1 -0
- package/dist/static/analyzers/unsafe-regex.js +36 -0
- package/dist/static/analyzers/unsafe-regex.js.map +1 -0
- package/dist/static/ast-engine.d.ts +22 -0
- package/dist/static/ast-engine.d.ts.map +1 -0
- package/dist/static/ast-engine.js +155 -0
- package/dist/static/ast-engine.js.map +1 -0
- package/dist/static/index.d.ts +3 -0
- package/dist/static/index.d.ts.map +1 -0
- package/dist/static/index.js +114 -0
- package/dist/static/index.js.map +1 -0
- package/dist/static/taint-tracker.d.ts +15 -0
- package/dist/static/taint-tracker.d.ts.map +1 -0
- package/dist/static/taint-tracker.js +70 -0
- package/dist/static/taint-tracker.js.map +1 -0
- package/dist/types/findings.d.ts +60 -0
- package/dist/types/findings.d.ts.map +1 -0
- package/dist/types/findings.js +9 -0
- package/dist/types/findings.js.map +1 -0
- package/dist/types/index.d.ts +23 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +8 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/crypto.d.ts +4 -0
- package/dist/utils/crypto.d.ts.map +1 -0
- package/dist/utils/crypto.js +12 -0
- package/dist/utils/crypto.js.map +1 -0
- package/dist/utils/fs-helpers.d.ts +7 -0
- package/dist/utils/fs-helpers.d.ts.map +1 -0
- package/dist/utils/fs-helpers.js +92 -0
- package/dist/utils/fs-helpers.js.map +1 -0
- package/dist/utils/levenshtein.d.ts +7 -0
- package/dist/utils/levenshtein.d.ts.map +1 -0
- package/dist/utils/levenshtein.js +89 -0
- package/dist/utils/levenshtein.js.map +1 -0
- package/package.json +57 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { discoverFiles, safeReadFile, getFileStat } from "../utils/fs-helpers.js";
|
|
2
|
+
import { SECRET_PATTERNS } from "../data/secret-patterns.js";
|
|
3
|
+
const ENV_FILE_PATTERN = /^\.env(\..+)?$/;
|
|
4
|
+
export async function scanEnvFiles(dirPath) {
|
|
5
|
+
const findings = [];
|
|
6
|
+
let counter = 0;
|
|
7
|
+
const envFiles = await discoverFiles(dirPath, ENV_FILE_PATTERN);
|
|
8
|
+
for (const filePath of envFiles) {
|
|
9
|
+
const content = await safeReadFile(filePath);
|
|
10
|
+
if (!content)
|
|
11
|
+
continue;
|
|
12
|
+
const lines = content.split("\n");
|
|
13
|
+
for (let i = 0; i < lines.length; i++) {
|
|
14
|
+
const line = lines[i].trim();
|
|
15
|
+
if (!line || line.startsWith("#"))
|
|
16
|
+
continue;
|
|
17
|
+
const eqIndex = line.indexOf("=");
|
|
18
|
+
if (eqIndex === -1)
|
|
19
|
+
continue;
|
|
20
|
+
const key = line.substring(0, eqIndex).trim();
|
|
21
|
+
const value = line.substring(eqIndex + 1).trim().replace(/^['"]|['"]$/g, "");
|
|
22
|
+
if (!value || value.length < 4)
|
|
23
|
+
continue;
|
|
24
|
+
// Check against secret patterns
|
|
25
|
+
for (const pattern of SECRET_PATTERNS) {
|
|
26
|
+
if (pattern.pattern.test(value) || pattern.pattern.test(line)) {
|
|
27
|
+
counter++;
|
|
28
|
+
findings.push({
|
|
29
|
+
id: `CFG-ENV-${String(counter).padStart(3, "0")}`,
|
|
30
|
+
title: `${pattern.name} in Environment File`,
|
|
31
|
+
severity: pattern.severity,
|
|
32
|
+
owasp_mcp: "MCP01",
|
|
33
|
+
owasp_mcp_title: "Excessive Privilege & Token Mismanagement",
|
|
34
|
+
category: "config",
|
|
35
|
+
file: filePath,
|
|
36
|
+
line: i + 1,
|
|
37
|
+
evidence: `${key}=${value.substring(0, 4)}${"*".repeat(Math.min(value.length - 4, 20))}`,
|
|
38
|
+
remediation: "Ensure .env files are in .gitignore. Use secret management tools for production. Restrict file permissions to owner-only (chmod 600).",
|
|
39
|
+
cwe: "CWE-522",
|
|
40
|
+
});
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// Check for default/weak credentials
|
|
45
|
+
if (/^(admin|password|pass|root|test|default|changeme|12345|password123|letmein|welcome)$/i.test(value)) {
|
|
46
|
+
counter++;
|
|
47
|
+
findings.push({
|
|
48
|
+
id: `CFG-ENV-${String(counter).padStart(3, "0")}`,
|
|
49
|
+
title: "Default/Weak Credential in Environment File",
|
|
50
|
+
severity: "high",
|
|
51
|
+
owasp_mcp: "MCP01",
|
|
52
|
+
owasp_mcp_title: "Excessive Privilege & Token Mismanagement",
|
|
53
|
+
category: "config",
|
|
54
|
+
file: filePath,
|
|
55
|
+
line: i + 1,
|
|
56
|
+
evidence: `${key}=<default credential>`,
|
|
57
|
+
remediation: "Replace default credentials with strong, unique values. Never use common passwords.",
|
|
58
|
+
cwe: "CWE-798",
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// Check file permissions (Unix/macOS)
|
|
63
|
+
const stat = await getFileStat(filePath);
|
|
64
|
+
if (stat) {
|
|
65
|
+
const mode = stat.mode & 0o777;
|
|
66
|
+
if (mode & 0o044) { // World or group readable
|
|
67
|
+
counter++;
|
|
68
|
+
findings.push({
|
|
69
|
+
id: `CFG-ENV-${String(counter).padStart(3, "0")}`,
|
|
70
|
+
title: "Environment File Has Overly Permissive Permissions",
|
|
71
|
+
severity: "medium",
|
|
72
|
+
owasp_mcp: "MCP01",
|
|
73
|
+
owasp_mcp_title: "Excessive Privilege & Token Mismanagement",
|
|
74
|
+
category: "config",
|
|
75
|
+
file: filePath,
|
|
76
|
+
evidence: `File permissions: ${mode.toString(8)} — readable by group/others`,
|
|
77
|
+
remediation: "Set file permissions to 600 (owner read/write only): chmod 600 " + filePath,
|
|
78
|
+
cwe: "CWE-732",
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return findings;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=env-scanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-scanner.js","sourceRoot":"","sources":["../../src/config/env-scanner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAkLjD,eAAO,MAAM,WAAW,EAAE,OAAO,EAQhC,CAAC"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { text } from "../types/index.js";
|
|
3
|
+
import { discoverConfigs, parseConfigFile } from "./mcp-config-parser.js";
|
|
4
|
+
import { scanEnvFiles } from "./env-scanner.js";
|
|
5
|
+
import { auditServerEntry, checkContextOversharing } from "./server-verification.js";
|
|
6
|
+
import { fileExists, getFileStat } from "../utils/fs-helpers.js";
|
|
7
|
+
function formatFindings(findings) {
|
|
8
|
+
if (findings.length === 0)
|
|
9
|
+
return "No findings.";
|
|
10
|
+
const bySeverity = { critical: 0, high: 0, medium: 0, low: 0, info: 0 };
|
|
11
|
+
for (const f of findings)
|
|
12
|
+
bySeverity[f.severity]++;
|
|
13
|
+
let output = `${findings.length} finding(s): ${bySeverity.critical} critical, ${bySeverity.high} high, ${bySeverity.medium} medium, ${bySeverity.low} low, ${bySeverity.info} info\n\n`;
|
|
14
|
+
for (const f of findings) {
|
|
15
|
+
output += `[${f.severity.toUpperCase()}] ${f.id}: ${f.title}\n`;
|
|
16
|
+
if (f.file)
|
|
17
|
+
output += ` File: ${f.file}${f.line ? `:${f.line}` : ""}\n`;
|
|
18
|
+
output += ` OWASP: ${f.owasp_mcp} — ${f.owasp_mcp_title}\n`;
|
|
19
|
+
output += ` Evidence: ${f.evidence}\n`;
|
|
20
|
+
output += ` Remediation: ${f.remediation}\n\n`;
|
|
21
|
+
}
|
|
22
|
+
return output.trim();
|
|
23
|
+
}
|
|
24
|
+
const cfgAutoDiscover = {
|
|
25
|
+
name: "cfg_auto_discover",
|
|
26
|
+
description: "Auto-discover all MCP configuration files on the system. Checks Claude Desktop, Claude Code, Cursor, VS Code, Windsurf locations. Returns found config files with server counts.",
|
|
27
|
+
schema: {
|
|
28
|
+
scan_home: z.boolean().optional().describe("Scan home directory for configs (default: true)"),
|
|
29
|
+
},
|
|
30
|
+
async execute(args) {
|
|
31
|
+
const configs = await discoverConfigs();
|
|
32
|
+
if (configs.length === 0)
|
|
33
|
+
return text("No MCP configuration files found.");
|
|
34
|
+
let output = `Found ${configs.length} MCP configuration file(s):\n\n`;
|
|
35
|
+
for (const cfg of configs) {
|
|
36
|
+
output += `${cfg.client}: ${cfg.path}\n`;
|
|
37
|
+
output += ` Servers: ${cfg.servers.length}\n`;
|
|
38
|
+
for (const s of cfg.servers) {
|
|
39
|
+
output += ` - ${s.name}: ${s.command ?? s.url ?? "unknown"}\n`;
|
|
40
|
+
}
|
|
41
|
+
output += "\n";
|
|
42
|
+
}
|
|
43
|
+
return text(output.trim());
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
const cfgAuditMcpConfig = {
|
|
47
|
+
name: "cfg_audit_mcp_config",
|
|
48
|
+
description: "Deep audit of a single MCP config file. Checks for: API keys in args, secrets in env, npx -y auto-install, unknown binaries, HTTP without TLS, missing auth headers, wildcard env passthrough.",
|
|
49
|
+
schema: {
|
|
50
|
+
path: z.string().describe("Path to MCP configuration file"),
|
|
51
|
+
},
|
|
52
|
+
async execute(args) {
|
|
53
|
+
const config = await parseConfigFile(args.path);
|
|
54
|
+
if (!config)
|
|
55
|
+
return text(`Could not parse config file: ${args.path}`);
|
|
56
|
+
const allFindings = [];
|
|
57
|
+
for (const server of config.servers) {
|
|
58
|
+
allFindings.push(...auditServerEntry(server, args.path));
|
|
59
|
+
}
|
|
60
|
+
let output = `Config: ${args.path}\nServers: ${config.servers.length}\n\n`;
|
|
61
|
+
output += formatFindings(allFindings);
|
|
62
|
+
return text(output);
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
const cfgScanEnvFiles = {
|
|
66
|
+
name: "cfg_scan_env_files",
|
|
67
|
+
description: "Recursively scan directory for .env files. Detect: high-value API keys, database credentials, private keys, default/weak credentials, overly permissive file permissions.",
|
|
68
|
+
schema: {
|
|
69
|
+
path: z.string().describe("Directory to scan for .env files"),
|
|
70
|
+
},
|
|
71
|
+
async execute(args) {
|
|
72
|
+
const findings = await scanEnvFiles(args.path);
|
|
73
|
+
return text(formatFindings(findings));
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
const cfgCheckShadowServers = {
|
|
77
|
+
name: "cfg_check_shadow_servers",
|
|
78
|
+
description: "Analyze each server in MCP config for shadow server indicators: unverified npm packages via npx -y, binaries in writable directories (/tmp), suspicious command paths.",
|
|
79
|
+
schema: {
|
|
80
|
+
path: z.string().describe("Path to MCP configuration file"),
|
|
81
|
+
},
|
|
82
|
+
async execute(args) {
|
|
83
|
+
const config = await parseConfigFile(args.path);
|
|
84
|
+
if (!config)
|
|
85
|
+
return text(`Could not parse config file: ${args.path}`);
|
|
86
|
+
const findings = [];
|
|
87
|
+
for (const server of config.servers) {
|
|
88
|
+
const serverFindings = auditServerEntry(server, args.path);
|
|
89
|
+
findings.push(...serverFindings.filter(f => f.owasp_mcp === "MCP09"));
|
|
90
|
+
}
|
|
91
|
+
return text(formatFindings(findings));
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
const cfgCheckContextOversharing = {
|
|
95
|
+
name: "cfg_check_context_oversharing",
|
|
96
|
+
description: "Check for excessive context exposure: servers inheriting all env vars, sensitive vars shared across unrelated servers, broad resource access patterns.",
|
|
97
|
+
schema: {
|
|
98
|
+
path: z.string().describe("Path to MCP configuration file"),
|
|
99
|
+
},
|
|
100
|
+
async execute(args) {
|
|
101
|
+
const config = await parseConfigFile(args.path);
|
|
102
|
+
if (!config)
|
|
103
|
+
return text(`Could not parse config file: ${args.path}`);
|
|
104
|
+
const findings = checkContextOversharing(config.servers, args.path);
|
|
105
|
+
return text(formatFindings(findings));
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
const cfgCheckTransportSecurity = {
|
|
109
|
+
name: "cfg_check_transport_security",
|
|
110
|
+
description: "Verify transport security: HTTP vs HTTPS, SSE without TLS, WebSocket without WSS, servers bound to 0.0.0.0, tunnel URLs (ngrok, localtunnel), missing Authorization headers.",
|
|
111
|
+
schema: {
|
|
112
|
+
path: z.string().describe("Path to MCP configuration file"),
|
|
113
|
+
},
|
|
114
|
+
async execute(args) {
|
|
115
|
+
const config = await parseConfigFile(args.path);
|
|
116
|
+
if (!config)
|
|
117
|
+
return text(`Could not parse config file: ${args.path}`);
|
|
118
|
+
const findings = [];
|
|
119
|
+
for (const server of config.servers) {
|
|
120
|
+
const serverFindings = auditServerEntry(server, args.path);
|
|
121
|
+
findings.push(...serverFindings.filter(f => f.owasp_mcp === "MCP07"));
|
|
122
|
+
}
|
|
123
|
+
return text(formatFindings(findings));
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
const cfgCheckFilePermissions = {
|
|
127
|
+
name: "cfg_check_file_permissions",
|
|
128
|
+
description: "Check file permissions on MCP config files and related credential files. Flag configs readable by other users (mode > 600), world-readable .env files.",
|
|
129
|
+
schema: {
|
|
130
|
+
path: z.string().describe("Path to MCP configuration file or directory"),
|
|
131
|
+
},
|
|
132
|
+
async execute(args) {
|
|
133
|
+
const findings = [];
|
|
134
|
+
let counter = 0;
|
|
135
|
+
const exists = await fileExists(args.path);
|
|
136
|
+
if (!exists)
|
|
137
|
+
return text(`Path not found: ${args.path}`);
|
|
138
|
+
const stat = await getFileStat(args.path);
|
|
139
|
+
if (stat && stat.isFile()) {
|
|
140
|
+
const mode = stat.mode & 0o777;
|
|
141
|
+
if (mode & 0o044) {
|
|
142
|
+
counter++;
|
|
143
|
+
findings.push({
|
|
144
|
+
id: `CFG-PERM-${String(counter).padStart(3, "0")}`,
|
|
145
|
+
title: "Config File Has Overly Permissive Permissions",
|
|
146
|
+
severity: "medium",
|
|
147
|
+
owasp_mcp: "MCP01",
|
|
148
|
+
owasp_mcp_title: "Excessive Privilege & Token Mismanagement",
|
|
149
|
+
category: "config",
|
|
150
|
+
file: args.path,
|
|
151
|
+
evidence: `File permissions: ${mode.toString(8)} — readable by group/others`,
|
|
152
|
+
remediation: `Set restrictive permissions: chmod 600 ${args.path}`,
|
|
153
|
+
cwe: "CWE-732",
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return text(formatFindings(findings));
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
export const configTools = [
|
|
161
|
+
cfgAutoDiscover,
|
|
162
|
+
cfgAuditMcpConfig,
|
|
163
|
+
cfgScanEnvFiles,
|
|
164
|
+
cfgCheckShadowServers,
|
|
165
|
+
cfgCheckContextOversharing,
|
|
166
|
+
cfgCheckTransportSecurity,
|
|
167
|
+
cfgCheckFilePermissions,
|
|
168
|
+
];
|
|
169
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface McpConfigFile {
|
|
2
|
+
path: string;
|
|
3
|
+
client: string;
|
|
4
|
+
servers: McpServerEntry[];
|
|
5
|
+
}
|
|
6
|
+
export interface McpServerEntry {
|
|
7
|
+
name: string;
|
|
8
|
+
command?: string;
|
|
9
|
+
args?: string[];
|
|
10
|
+
env?: Record<string, string>;
|
|
11
|
+
url?: string;
|
|
12
|
+
headers?: Record<string, string>;
|
|
13
|
+
}
|
|
14
|
+
export declare function discoverConfigs(): Promise<McpConfigFile[]>;
|
|
15
|
+
export declare function parseConfigFile(path: string): Promise<McpConfigFile | null>;
|
|
16
|
+
//# sourceMappingURL=mcp-config-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-config-parser.d.ts","sourceRoot":"","sources":["../../src/config/mcp-config-parser.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,cAAc,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAkED,wBAAsB,eAAe,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC,CAmBhE;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAQjF"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { safeReadJson, fileExists } from "../utils/fs-helpers.js";
|
|
4
|
+
const CONFIG_LOCATIONS = [
|
|
5
|
+
{
|
|
6
|
+
client: "Claude Desktop",
|
|
7
|
+
paths: [
|
|
8
|
+
join(homedir(), "Library", "Application Support", "Claude", "claude_desktop_config.json"),
|
|
9
|
+
join(homedir(), ".config", "claude", "claude_desktop_config.json"),
|
|
10
|
+
join(homedir(), "AppData", "Roaming", "Claude", "claude_desktop_config.json"),
|
|
11
|
+
],
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
client: "Claude Code",
|
|
15
|
+
paths: [
|
|
16
|
+
join(homedir(), ".claude.json"),
|
|
17
|
+
],
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
client: "Cursor",
|
|
21
|
+
paths: [
|
|
22
|
+
join(homedir(), ".cursor", "mcp.json"),
|
|
23
|
+
],
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
client: "VS Code",
|
|
27
|
+
paths: [
|
|
28
|
+
join(homedir(), ".vscode", "mcp.json"),
|
|
29
|
+
join(homedir(), "Library", "Application Support", "Code", "User", "settings.json"),
|
|
30
|
+
],
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
client: "Windsurf",
|
|
34
|
+
paths: [
|
|
35
|
+
join(homedir(), ".windsurf", "mcp.json"),
|
|
36
|
+
join(homedir(), ".codeium", "windsurf", "mcp_config.json"),
|
|
37
|
+
],
|
|
38
|
+
},
|
|
39
|
+
];
|
|
40
|
+
function parseServers(raw) {
|
|
41
|
+
if (!raw || typeof raw !== "object")
|
|
42
|
+
return [];
|
|
43
|
+
const servers = [];
|
|
44
|
+
const obj = raw;
|
|
45
|
+
for (const [name, value] of Object.entries(obj)) {
|
|
46
|
+
if (!value || typeof value !== "object")
|
|
47
|
+
continue;
|
|
48
|
+
const entry = value;
|
|
49
|
+
servers.push({
|
|
50
|
+
name,
|
|
51
|
+
command: entry.command,
|
|
52
|
+
args: Array.isArray(entry.args) ? entry.args.map(String) : undefined,
|
|
53
|
+
env: entry.env && typeof entry.env === "object" ? entry.env : undefined,
|
|
54
|
+
url: entry.url,
|
|
55
|
+
headers: entry.headers && typeof entry.headers === "object" ? entry.headers : undefined,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
return servers;
|
|
59
|
+
}
|
|
60
|
+
export async function discoverConfigs() {
|
|
61
|
+
const results = [];
|
|
62
|
+
for (const loc of CONFIG_LOCATIONS) {
|
|
63
|
+
for (const path of loc.paths) {
|
|
64
|
+
if (await fileExists(path)) {
|
|
65
|
+
const data = await safeReadJson(path);
|
|
66
|
+
if (data) {
|
|
67
|
+
const serversRaw = data.mcpServers ?? data.mcp_servers ?? data.servers;
|
|
68
|
+
const servers = parseServers(serversRaw);
|
|
69
|
+
if (servers.length > 0) {
|
|
70
|
+
results.push({ path, client: loc.client, servers });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return results;
|
|
77
|
+
}
|
|
78
|
+
export async function parseConfigFile(path) {
|
|
79
|
+
const data = await safeReadJson(path);
|
|
80
|
+
if (!data)
|
|
81
|
+
return null;
|
|
82
|
+
const serversRaw = data.mcpServers ?? data.mcp_servers ?? data.servers;
|
|
83
|
+
const servers = parseServers(serversRaw);
|
|
84
|
+
return { path, client: "unknown", servers };
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=mcp-config-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-config-parser.js","sourceRoot":"","sources":["../../src/config/mcp-config-parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { McpServerEntry } from "./mcp-config-parser.js";
|
|
2
|
+
import type { Finding } from "../types/findings.js";
|
|
3
|
+
export declare function auditServerEntry(server: McpServerEntry, configPath: string): Finding[];
|
|
4
|
+
export declare function checkContextOversharing(servers: McpServerEntry[], configPath: string): Finding[];
|
|
5
|
+
//# sourceMappingURL=server-verification.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-verification.d.ts","sourceRoot":"","sources":["../../src/config/server-verification.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAUpD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,EAAE,CAuKtF;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,cAAc,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,EAAE,CAwDhG"}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { SECRET_PATTERNS } from "../data/secret-patterns.js";
|
|
2
|
+
const SUSPICIOUS_PATHS = ["/tmp", "/var/tmp", "\\temp\\", "\\tmp\\"];
|
|
3
|
+
const KNOWN_NPX_PREFIXES = [
|
|
4
|
+
"@modelcontextprotocol/", "darknet-mcp-server", "supply-chain-mcp-server",
|
|
5
|
+
"osint-mcp-server", "cve-mcp-server", "mcp-security-scanner",
|
|
6
|
+
"@anthropic-ai/", "@cloudflare/", "wrangler",
|
|
7
|
+
];
|
|
8
|
+
export function auditServerEntry(server, configPath) {
|
|
9
|
+
const findings = [];
|
|
10
|
+
let counter = 0;
|
|
11
|
+
// Check for npx -y (auto-install without confirmation)
|
|
12
|
+
if (server.command === "npx" && server.args?.includes("-y")) {
|
|
13
|
+
const pkgName = server.args.find(a => !a.startsWith("-") && a !== "npx") ?? "unknown";
|
|
14
|
+
const isKnown = KNOWN_NPX_PREFIXES.some(p => pkgName.startsWith(p));
|
|
15
|
+
if (!isKnown) {
|
|
16
|
+
counter++;
|
|
17
|
+
findings.push({
|
|
18
|
+
id: `CFG-SRV-${String(counter).padStart(3, "0")}`,
|
|
19
|
+
title: `npx -y Auto-Install for Unverified Package: ${pkgName}`,
|
|
20
|
+
severity: "high",
|
|
21
|
+
owasp_mcp: "MCP09",
|
|
22
|
+
owasp_mcp_title: "Shadow Servers & Unauthorized MCP Endpoints",
|
|
23
|
+
category: "config",
|
|
24
|
+
file: configPath,
|
|
25
|
+
evidence: `Server "${server.name}": npx -y ${pkgName} — auto-installs without confirmation`,
|
|
26
|
+
remediation: "Install the package explicitly with npm install first, then use the installed binary. Verify the package on npmjs.com before use.",
|
|
27
|
+
cwe: "CWE-829",
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// Check for secrets in args (visible in process list)
|
|
32
|
+
if (server.args) {
|
|
33
|
+
for (const arg of server.args) {
|
|
34
|
+
for (const pattern of SECRET_PATTERNS) {
|
|
35
|
+
if (pattern.pattern.test(arg)) {
|
|
36
|
+
counter++;
|
|
37
|
+
findings.push({
|
|
38
|
+
id: `CFG-SRV-${String(counter).padStart(3, "0")}`,
|
|
39
|
+
title: `${pattern.name} Exposed in CLI Arguments`,
|
|
40
|
+
severity: "critical",
|
|
41
|
+
owasp_mcp: "MCP01",
|
|
42
|
+
owasp_mcp_title: "Excessive Privilege & Token Mismanagement",
|
|
43
|
+
category: "config",
|
|
44
|
+
file: configPath,
|
|
45
|
+
evidence: `Server "${server.name}": secret in args visible via process list (ps aux)`,
|
|
46
|
+
remediation: "Move secrets from CLI arguments to the env block or use environment variables. CLI args are visible to all users via ps.",
|
|
47
|
+
cwe: "CWE-214",
|
|
48
|
+
});
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// Check for secrets in env block (acceptable but flag high-value)
|
|
55
|
+
if (server.env) {
|
|
56
|
+
for (const [key, value] of Object.entries(server.env)) {
|
|
57
|
+
for (const pattern of SECRET_PATTERNS) {
|
|
58
|
+
if (pattern.pattern.test(value)) {
|
|
59
|
+
counter++;
|
|
60
|
+
findings.push({
|
|
61
|
+
id: `CFG-SRV-${String(counter).padStart(3, "0")}`,
|
|
62
|
+
title: `${pattern.name} in Server Environment Config`,
|
|
63
|
+
severity: "medium",
|
|
64
|
+
owasp_mcp: "MCP01",
|
|
65
|
+
owasp_mcp_title: "Excessive Privilege & Token Mismanagement",
|
|
66
|
+
category: "config",
|
|
67
|
+
file: configPath,
|
|
68
|
+
evidence: `Server "${server.name}": ${key}=<${pattern.name}> in env block`,
|
|
69
|
+
remediation: "Consider using a secret manager or encrypted env files instead of plaintext in config files.",
|
|
70
|
+
cwe: "CWE-522",
|
|
71
|
+
});
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// Check for suspicious binary paths
|
|
78
|
+
if (server.command) {
|
|
79
|
+
for (const suspicious of SUSPICIOUS_PATHS) {
|
|
80
|
+
if (server.command.includes(suspicious)) {
|
|
81
|
+
counter++;
|
|
82
|
+
findings.push({
|
|
83
|
+
id: `CFG-SRV-${String(counter).padStart(3, "0")}`,
|
|
84
|
+
title: `Server Binary in Writable Directory`,
|
|
85
|
+
severity: "high",
|
|
86
|
+
owasp_mcp: "MCP09",
|
|
87
|
+
owasp_mcp_title: "Shadow Servers & Unauthorized MCP Endpoints",
|
|
88
|
+
category: "config",
|
|
89
|
+
file: configPath,
|
|
90
|
+
evidence: `Server "${server.name}": command "${server.command}" is in a world-writable directory`,
|
|
91
|
+
remediation: "Move server binaries to a protected directory. Writable directories allow binary replacement attacks.",
|
|
92
|
+
cwe: "CWE-427",
|
|
93
|
+
});
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// Check for HTTP URLs (no TLS)
|
|
99
|
+
if (server.url) {
|
|
100
|
+
if (server.url.startsWith("http://")) {
|
|
101
|
+
counter++;
|
|
102
|
+
findings.push({
|
|
103
|
+
id: `CFG-SRV-${String(counter).padStart(3, "0")}`,
|
|
104
|
+
title: "Remote Server Using HTTP (No TLS)",
|
|
105
|
+
severity: "high",
|
|
106
|
+
owasp_mcp: "MCP07",
|
|
107
|
+
owasp_mcp_title: "Insufficient Authentication & Transport Security",
|
|
108
|
+
category: "config",
|
|
109
|
+
file: configPath,
|
|
110
|
+
evidence: `Server "${server.name}": ${server.url} — unencrypted transport`,
|
|
111
|
+
remediation: "Use HTTPS for all remote MCP server connections. HTTP allows eavesdropping and MITM attacks.",
|
|
112
|
+
cwe: "CWE-319",
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
// Check for tunnel URLs
|
|
116
|
+
if (/ngrok|localtunnel|serveo|bore\.pub|loca\.lt/.test(server.url)) {
|
|
117
|
+
counter++;
|
|
118
|
+
findings.push({
|
|
119
|
+
id: `CFG-SRV-${String(counter).padStart(3, "0")}`,
|
|
120
|
+
title: "Remote Server Using Tunnel URL",
|
|
121
|
+
severity: "medium",
|
|
122
|
+
owasp_mcp: "MCP07",
|
|
123
|
+
owasp_mcp_title: "Insufficient Authentication & Transport Security",
|
|
124
|
+
category: "config",
|
|
125
|
+
file: configPath,
|
|
126
|
+
evidence: `Server "${server.name}": ${server.url} — tunnel URL that could be hijacked`,
|
|
127
|
+
remediation: "Avoid using tunnel URLs for production MCP servers. Tunnel URLs can be hijacked when they expire.",
|
|
128
|
+
cwe: "CWE-346",
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
// Check for missing auth headers on remote servers
|
|
132
|
+
if (!server.headers?.Authorization && !server.headers?.authorization) {
|
|
133
|
+
counter++;
|
|
134
|
+
findings.push({
|
|
135
|
+
id: `CFG-SRV-${String(counter).padStart(3, "0")}`,
|
|
136
|
+
title: "Remote Server Without Authorization Header",
|
|
137
|
+
severity: "medium",
|
|
138
|
+
owasp_mcp: "MCP07",
|
|
139
|
+
owasp_mcp_title: "Insufficient Authentication & Transport Security",
|
|
140
|
+
category: "config",
|
|
141
|
+
file: configPath,
|
|
142
|
+
evidence: `Server "${server.name}": no Authorization header configured for remote server`,
|
|
143
|
+
remediation: "Add an Authorization header with a bearer token or API key for remote MCP servers.",
|
|
144
|
+
cwe: "CWE-287",
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
// Check for 0.0.0.0 binding
|
|
148
|
+
if (/0\.0\.0\.0|::/.test(server.url)) {
|
|
149
|
+
counter++;
|
|
150
|
+
findings.push({
|
|
151
|
+
id: `CFG-SRV-${String(counter).padStart(3, "0")}`,
|
|
152
|
+
title: "Server Bound to All Interfaces",
|
|
153
|
+
severity: "high",
|
|
154
|
+
owasp_mcp: "MCP07",
|
|
155
|
+
owasp_mcp_title: "Insufficient Authentication & Transport Security",
|
|
156
|
+
category: "config",
|
|
157
|
+
file: configPath,
|
|
158
|
+
evidence: `Server "${server.name}": bound to 0.0.0.0 — accessible from network`,
|
|
159
|
+
remediation: "Bind to localhost (127.0.0.1) for local-only servers. Use 0.0.0.0 only with proper authentication and firewall rules.",
|
|
160
|
+
cwe: "CWE-668",
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return findings;
|
|
165
|
+
}
|
|
166
|
+
export function checkContextOversharing(servers, configPath) {
|
|
167
|
+
const findings = [];
|
|
168
|
+
let counter = 0;
|
|
169
|
+
// Check for servers with no explicit env (inherits everything)
|
|
170
|
+
for (const server of servers) {
|
|
171
|
+
if (!server.env && server.command) {
|
|
172
|
+
// Stdio servers without explicit env inherit ALL env vars
|
|
173
|
+
counter++;
|
|
174
|
+
findings.push({
|
|
175
|
+
id: `CFG-CTX-${String(counter).padStart(3, "0")}`,
|
|
176
|
+
title: "Server Inherits All Environment Variables",
|
|
177
|
+
severity: "medium",
|
|
178
|
+
owasp_mcp: "MCP10",
|
|
179
|
+
owasp_mcp_title: "Context Over-sharing & Data Exposure",
|
|
180
|
+
category: "config",
|
|
181
|
+
file: configPath,
|
|
182
|
+
evidence: `Server "${server.name}": no explicit env block — inherits all parent process env vars`,
|
|
183
|
+
remediation: "Add an explicit env block listing only the environment variables this server needs.",
|
|
184
|
+
cwe: "CWE-200",
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
// Check for high-value secrets shared across multiple servers
|
|
189
|
+
const secretServers = {};
|
|
190
|
+
for (const server of servers) {
|
|
191
|
+
if (!server.env)
|
|
192
|
+
continue;
|
|
193
|
+
for (const [key] of Object.entries(server.env)) {
|
|
194
|
+
const lk = key.toLowerCase();
|
|
195
|
+
if (/key|secret|token|password|credential/.test(lk)) {
|
|
196
|
+
if (!secretServers[key])
|
|
197
|
+
secretServers[key] = [];
|
|
198
|
+
secretServers[key].push(server.name);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
for (const [key, serverNames] of Object.entries(secretServers)) {
|
|
203
|
+
if (serverNames.length > 1) {
|
|
204
|
+
counter++;
|
|
205
|
+
findings.push({
|
|
206
|
+
id: `CFG-CTX-${String(counter).padStart(3, "0")}`,
|
|
207
|
+
title: `Secret Shared Across ${serverNames.length} Servers`,
|
|
208
|
+
severity: "medium",
|
|
209
|
+
owasp_mcp: "MCP10",
|
|
210
|
+
owasp_mcp_title: "Context Over-sharing & Data Exposure",
|
|
211
|
+
category: "config",
|
|
212
|
+
file: configPath,
|
|
213
|
+
evidence: `${key} is configured in servers: ${serverNames.join(", ")}`,
|
|
214
|
+
remediation: "Each server should have its own unique credentials. Sharing secrets increases blast radius if one server is compromised.",
|
|
215
|
+
cwe: "CWE-200",
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return findings;
|
|
220
|
+
}
|
|
221
|
+
//# sourceMappingURL=server-verification.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-verification.js","sourceRoot":"","sources":["../../src/config/server-verification.ts"],"names":[],"mappings":"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"}
|