@sigildev/sigil 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.
Files changed (99) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +246 -0
  3. package/dist/analyzers/ast/python.d.ts +14 -0
  4. package/dist/analyzers/ast/python.d.ts.map +1 -0
  5. package/dist/analyzers/ast/python.js +15 -0
  6. package/dist/analyzers/ast/python.js.map +1 -0
  7. package/dist/analyzers/ast/taint.d.ts +45 -0
  8. package/dist/analyzers/ast/taint.d.ts.map +1 -0
  9. package/dist/analyzers/ast/taint.js +32 -0
  10. package/dist/analyzers/ast/taint.js.map +1 -0
  11. package/dist/analyzers/ast/typescript.d.ts +15 -0
  12. package/dist/analyzers/ast/typescript.d.ts.map +1 -0
  13. package/dist/analyzers/ast/typescript.js +16 -0
  14. package/dist/analyzers/ast/typescript.js.map +1 -0
  15. package/dist/analyzers/deps.d.ts +13 -0
  16. package/dist/analyzers/deps.d.ts.map +1 -0
  17. package/dist/analyzers/deps.js +14 -0
  18. package/dist/analyzers/deps.js.map +1 -0
  19. package/dist/analyzers/pattern.d.ts +12 -0
  20. package/dist/analyzers/pattern.d.ts.map +1 -0
  21. package/dist/analyzers/pattern.js +13 -0
  22. package/dist/analyzers/pattern.js.map +1 -0
  23. package/dist/analyzers/types.d.ts +111 -0
  24. package/dist/analyzers/types.d.ts.map +1 -0
  25. package/dist/analyzers/types.js +3 -0
  26. package/dist/analyzers/types.js.map +1 -0
  27. package/dist/discovery/config-parser.d.ts +7 -0
  28. package/dist/discovery/config-parser.d.ts.map +1 -0
  29. package/dist/discovery/config-parser.js +23 -0
  30. package/dist/discovery/config-parser.js.map +1 -0
  31. package/dist/discovery/files.d.ts +6 -0
  32. package/dist/discovery/files.d.ts.map +1 -0
  33. package/dist/discovery/files.js +43 -0
  34. package/dist/discovery/files.js.map +1 -0
  35. package/dist/discovery/manifest.d.ts +6 -0
  36. package/dist/discovery/manifest.d.ts.map +1 -0
  37. package/dist/discovery/manifest.js +82 -0
  38. package/dist/discovery/manifest.js.map +1 -0
  39. package/dist/index.d.ts +3 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +60 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/reporters/json.d.ts +3 -0
  44. package/dist/reporters/json.d.ts.map +1 -0
  45. package/dist/reporters/json.js +4 -0
  46. package/dist/reporters/json.js.map +1 -0
  47. package/dist/reporters/sarif.d.ts +3 -0
  48. package/dist/reporters/sarif.d.ts.map +1 -0
  49. package/dist/reporters/sarif.js +57 -0
  50. package/dist/reporters/sarif.js.map +1 -0
  51. package/dist/reporters/text.d.ts +7 -0
  52. package/dist/reporters/text.d.ts.map +1 -0
  53. package/dist/reporters/text.js +89 -0
  54. package/dist/reporters/text.js.map +1 -0
  55. package/dist/rules/auth.d.ts +4 -0
  56. package/dist/rules/auth.d.ts.map +1 -0
  57. package/dist/rules/auth.js +88 -0
  58. package/dist/rules/auth.js.map +1 -0
  59. package/dist/rules/config.d.ts +5 -0
  60. package/dist/rules/config.d.ts.map +1 -0
  61. package/dist/rules/config.js +123 -0
  62. package/dist/rules/config.js.map +1 -0
  63. package/dist/rules/data.d.ts +4 -0
  64. package/dist/rules/data.d.ts.map +1 -0
  65. package/dist/rules/data.js +79 -0
  66. package/dist/rules/data.js.map +1 -0
  67. package/dist/rules/deps.d.ts +3 -0
  68. package/dist/rules/deps.d.ts.map +1 -0
  69. package/dist/rules/deps.js +68 -0
  70. package/dist/rules/deps.js.map +1 -0
  71. package/dist/rules/description.d.ts +3 -0
  72. package/dist/rules/description.d.ts.map +1 -0
  73. package/dist/rules/description.js +91 -0
  74. package/dist/rules/description.js.map +1 -0
  75. package/dist/rules/index.d.ts +3 -0
  76. package/dist/rules/index.d.ts.map +1 -0
  77. package/dist/rules/index.js +154 -0
  78. package/dist/rules/index.js.map +1 -0
  79. package/dist/rules/injection.d.ts +5 -0
  80. package/dist/rules/injection.d.ts.map +1 -0
  81. package/dist/rules/injection.js +213 -0
  82. package/dist/rules/injection.js.map +1 -0
  83. package/dist/rules/permissions.d.ts +5 -0
  84. package/dist/rules/permissions.d.ts.map +1 -0
  85. package/dist/rules/permissions.js +170 -0
  86. package/dist/rules/permissions.js.map +1 -0
  87. package/dist/rules/validation.d.ts +3 -0
  88. package/dist/rules/validation.d.ts.map +1 -0
  89. package/dist/rules/validation.js +67 -0
  90. package/dist/rules/validation.js.map +1 -0
  91. package/dist/scanner.d.ts +9 -0
  92. package/dist/scanner.d.ts.map +1 -0
  93. package/dist/scanner.js +149 -0
  94. package/dist/scanner.js.map +1 -0
  95. package/dist/scoring.d.ts +3 -0
  96. package/dist/scoring.d.ts.map +1 -0
  97. package/dist/scoring.js +35 -0
  98. package/dist/scoring.js.map +1 -0
  99. package/package.json +57 -0
@@ -0,0 +1,23 @@
1
+ import { readFile } from "node:fs/promises";
2
+ /**
3
+ * Parse an MCP configuration file (claude_desktop_config.json, .mcp.json)
4
+ * and extract server entries.
5
+ */
6
+ export async function parseConfig(configPath) {
7
+ const raw = await readFile(configPath, "utf-8");
8
+ const config = JSON.parse(raw);
9
+ const entries = [];
10
+ // Handle both { mcpServers: {...} } and { servers: {...} } formats
11
+ const servers = config.mcpServers ?? config.servers ?? {};
12
+ for (const [name, value] of Object.entries(servers)) {
13
+ const server = value;
14
+ entries.push({
15
+ name,
16
+ command: server.command ?? "",
17
+ args: server.args,
18
+ env: server.env,
19
+ });
20
+ }
21
+ return entries;
22
+ }
23
+ //# sourceMappingURL=config-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-parser.js","sourceRoot":"","sources":["../../src/discovery/config-parser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAG5C;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,UAAkB;IAClD,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IAChD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAE/B,MAAM,OAAO,GAAkB,EAAE,CAAC;IAElC,mEAAmE;IACnE,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC;IAE1D,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACpD,MAAM,MAAM,GAAG,KAAgC,CAAC;QAChD,OAAO,CAAC,IAAI,CAAC;YACX,IAAI;YACJ,OAAO,EAAG,MAAM,CAAC,OAAkB,IAAI,EAAE;YACzC,IAAI,EAAE,MAAM,CAAC,IAA4B;YACzC,GAAG,EAAE,MAAM,CAAC,GAAyC;SACtD,CAAC,CAAC;IACL,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Discover source files in the target directory based on detected language.
3
+ * Returns paths relative to rootDir.
4
+ */
5
+ export declare function discoverFiles(rootDir: string, language: "typescript" | "python" | "unknown"): Promise<string[]>;
6
+ //# sourceMappingURL=files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../src/discovery/files.ts"],"names":[],"mappings":"AAsBA;;;GAGG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,YAAY,GAAG,QAAQ,GAAG,SAAS,GAC5C,OAAO,CAAC,MAAM,EAAE,CAAC,CAoBnB"}
@@ -0,0 +1,43 @@
1
+ import fg from "fast-glob";
2
+ const TS_PATTERNS = ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.mjs"];
3
+ const PY_PATTERNS = ["**/*.py"];
4
+ const IGNORE_PATTERNS = [
5
+ "**/node_modules/**",
6
+ "**/dist/**",
7
+ "**/build/**",
8
+ "**/__pycache__/**",
9
+ "**/.venv/**",
10
+ "**/venv/**",
11
+ "**/.git/**",
12
+ "**/coverage/**",
13
+ "**/*.test.ts",
14
+ "**/*.test.js",
15
+ "**/*.spec.ts",
16
+ "**/*.spec.js",
17
+ "**/test/**",
18
+ "**/tests/**",
19
+ ];
20
+ /**
21
+ * Discover source files in the target directory based on detected language.
22
+ * Returns paths relative to rootDir.
23
+ */
24
+ export async function discoverFiles(rootDir, language) {
25
+ let patterns;
26
+ switch (language) {
27
+ case "typescript":
28
+ patterns = TS_PATTERNS;
29
+ break;
30
+ case "python":
31
+ patterns = PY_PATTERNS;
32
+ break;
33
+ case "unknown":
34
+ patterns = [...TS_PATTERNS, ...PY_PATTERNS];
35
+ break;
36
+ }
37
+ return fg(patterns, {
38
+ cwd: rootDir,
39
+ ignore: IGNORE_PATTERNS,
40
+ dot: false,
41
+ });
42
+ }
43
+ //# sourceMappingURL=files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/discovery/files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,WAAW,CAAC;AAE3B,MAAM,WAAW,GAAG,CAAC,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;AACnE,MAAM,WAAW,GAAG,CAAC,SAAS,CAAC,CAAC;AAEhC,MAAM,eAAe,GAAG;IACtB,oBAAoB;IACpB,YAAY;IACZ,aAAa;IACb,mBAAmB;IACnB,aAAa;IACb,YAAY;IACZ,YAAY;IACZ,gBAAgB;IAChB,cAAc;IACd,cAAc;IACd,cAAc;IACd,cAAc;IACd,YAAY;IACZ,aAAa;CACd,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,OAAe,EACf,QAA6C;IAE7C,IAAI,QAAkB,CAAC;IAEvB,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,YAAY;YACf,QAAQ,GAAG,WAAW,CAAC;YACvB,MAAM;QACR,KAAK,QAAQ;YACX,QAAQ,GAAG,WAAW,CAAC;YACvB,MAAM;QACR,KAAK,SAAS;YACZ,QAAQ,GAAG,CAAC,GAAG,WAAW,EAAE,GAAG,WAAW,CAAC,CAAC;YAC5C,MAAM;IACV,CAAC;IAED,OAAO,EAAE,CAAC,QAAQ,EAAE;QAClB,GAAG,EAAE,OAAO;QACZ,MAAM,EAAE,eAAe;QACvB,GAAG,EAAE,KAAK;KACX,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { ManifestInfo } from "../analyzers/types.js";
2
+ /**
3
+ * Parse package.json or pyproject.toml to extract manifest info.
4
+ */
5
+ export declare function parseManifest(rootDir: string): Promise<ManifestInfo | undefined>;
6
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/discovery/manifest.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1D;;GAEG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,CAiFnC"}
@@ -0,0 +1,82 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { resolve } from "node:path";
3
+ /**
4
+ * Parse package.json or pyproject.toml to extract manifest info.
5
+ */
6
+ export async function parseManifest(rootDir) {
7
+ // Try package.json first
8
+ try {
9
+ const pkgPath = resolve(rootDir, "package.json");
10
+ const raw = await readFile(pkgPath, "utf-8");
11
+ const pkg = JSON.parse(raw);
12
+ // Check for lockfile
13
+ let lockfilePath;
14
+ for (const lockfile of [
15
+ "package-lock.json",
16
+ "yarn.lock",
17
+ "pnpm-lock.yaml",
18
+ ]) {
19
+ try {
20
+ const lp = resolve(rootDir, lockfile);
21
+ await readFile(lp, "utf-8"); // just check it exists
22
+ lockfilePath = lp;
23
+ break;
24
+ }
25
+ catch {
26
+ // try next
27
+ }
28
+ }
29
+ return {
30
+ name: pkg.name,
31
+ version: pkg.version,
32
+ dependencies: pkg.dependencies ?? {},
33
+ devDependencies: pkg.devDependencies ?? {},
34
+ lockfilePath,
35
+ };
36
+ }
37
+ catch {
38
+ // No package.json
39
+ }
40
+ // Try pyproject.toml
41
+ try {
42
+ const pyPath = resolve(rootDir, "pyproject.toml");
43
+ const raw = await readFile(pyPath, "utf-8");
44
+ // Basic TOML parsing for name/version — just regex for MVP
45
+ const nameMatch = raw.match(/^name\s*=\s*"([^"]+)"/m);
46
+ const versionMatch = raw.match(/^version\s*=\s*"([^"]+)"/m);
47
+ // Extract dependencies from [project.dependencies] or [tool.poetry.dependencies]
48
+ const deps = {};
49
+ const depSection = raw.match(/\[(?:project\.)?dependencies\]\n([\s\S]*?)(?:\n\[|$)/);
50
+ if (depSection) {
51
+ const depLines = depSection[1].matchAll(/^(\S+)\s*=\s*"([^"]+)"/gm);
52
+ for (const match of depLines) {
53
+ deps[match[1]] = match[2];
54
+ }
55
+ }
56
+ // Check for lockfile
57
+ let lockfilePath;
58
+ for (const lockfile of ["poetry.lock", "uv.lock"]) {
59
+ try {
60
+ const lp = resolve(rootDir, lockfile);
61
+ await readFile(lp, "utf-8");
62
+ lockfilePath = lp;
63
+ break;
64
+ }
65
+ catch {
66
+ // try next
67
+ }
68
+ }
69
+ return {
70
+ name: nameMatch?.[1],
71
+ version: versionMatch?.[1],
72
+ dependencies: deps,
73
+ devDependencies: {},
74
+ lockfilePath,
75
+ };
76
+ }
77
+ catch {
78
+ // No pyproject.toml
79
+ }
80
+ return undefined;
81
+ }
82
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/discovery/manifest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,60 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from "commander";
3
+ import { scan } from "./scanner.js";
4
+ import { formatText } from "./reporters/text.js";
5
+ import { formatJson } from "./reporters/json.js";
6
+ import { formatSarif } from "./reporters/sarif.js";
7
+ const program = new Command();
8
+ program
9
+ .name("sigil")
10
+ .description("Security scanner for MCP (Model Context Protocol) servers")
11
+ .version("0.1.0")
12
+ .argument("<target>", "Path to MCP server directory, file, or config")
13
+ .option("-o, --output <format>", "Output format: text, json, sarif", "text")
14
+ .option("-s, --severity <level>", "Minimum severity to report: low, medium, high, critical", "low")
15
+ .option("--no-color", "Disable colored output")
16
+ .option("--config <path>", "Path to scanner config file (.mcp-scanner.yml)")
17
+ .option("--ignore <rules>", "Comma-separated rule IDs to ignore")
18
+ .option("-q, --quiet", "Only output findings (no banner, no summary)")
19
+ .option("-v, --verbose", "Show detailed analysis trace")
20
+ .action(async (target, opts) => {
21
+ const format = opts.output;
22
+ const minSeverity = opts.severity;
23
+ const ignoreRules = opts.ignore
24
+ ? opts.ignore.split(",").map((r) => r.trim())
25
+ : [];
26
+ try {
27
+ const result = await scan(target, {
28
+ minSeverity,
29
+ ignoreRules,
30
+ configPath: opts.config,
31
+ verbose: opts.verbose,
32
+ });
33
+ let output;
34
+ switch (format) {
35
+ case "json":
36
+ output = formatJson(result);
37
+ break;
38
+ case "sarif":
39
+ output = formatSarif(result);
40
+ break;
41
+ case "text":
42
+ default:
43
+ output = formatText(result, {
44
+ color: opts.color !== false,
45
+ quiet: opts.quiet,
46
+ });
47
+ break;
48
+ }
49
+ process.stdout.write(output + "\n");
50
+ // Exit code: 0 if PASS, 1 if FAIL/WARN
51
+ process.exit(result.score.value >= 70 ? 0 : 1);
52
+ }
53
+ catch (err) {
54
+ const message = err instanceof Error ? err.message : String(err);
55
+ process.stderr.write(`Error: ${message}\n`);
56
+ process.exit(2);
57
+ }
58
+ });
59
+ program.parse();
60
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAGnD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,OAAO,CAAC;KACb,WAAW,CAAC,2DAA2D,CAAC;KACxE,OAAO,CAAC,OAAO,CAAC;KAChB,QAAQ,CAAC,UAAU,EAAE,+CAA+C,CAAC;KACrE,MAAM,CAAC,uBAAuB,EAAE,kCAAkC,EAAE,MAAM,CAAC;KAC3E,MAAM,CACL,wBAAwB,EACxB,yDAAyD,EACzD,KAAK,CACN;KACA,MAAM,CAAC,YAAY,EAAE,wBAAwB,CAAC;KAC9C,MAAM,CAAC,iBAAiB,EAAE,gDAAgD,CAAC;KAC3E,MAAM,CAAC,kBAAkB,EAAE,oCAAoC,CAAC;KAChE,MAAM,CAAC,aAAa,EAAE,8CAA8C,CAAC;KACrE,MAAM,CAAC,eAAe,EAAE,8BAA8B,CAAC;KACvD,MAAM,CAAC,KAAK,EAAE,MAAc,EAAE,IAAI,EAAE,EAAE;IACrC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAsB,CAAC;IAC3C,MAAM,WAAW,GAAG,IAAI,CAAC,QAAoB,CAAC;IAC9C,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM;QAC7B,CAAC,CAAE,IAAI,CAAC,MAAiB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACjE,CAAC,CAAC,EAAE,CAAC;IAEP,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE;YAChC,WAAW;YACX,WAAW;YACX,UAAU,EAAE,IAAI,CAAC,MAA4B;YAC7C,OAAO,EAAE,IAAI,CAAC,OAAkB;SACjC,CAAC,CAAC;QAEH,IAAI,MAAc,CAAC;QACnB,QAAQ,MAAM,EAAE,CAAC;YACf,KAAK,MAAM;gBACT,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;gBAC5B,MAAM;YACR,KAAK,OAAO;gBACV,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;gBAC7B,MAAM;YACR,KAAK,MAAM,CAAC;YACZ;gBACE,MAAM,GAAG,UAAU,CAAC,MAAM,EAAE;oBAC1B,KAAK,EAAE,IAAI,CAAC,KAAK,KAAK,KAAK;oBAC3B,KAAK,EAAE,IAAI,CAAC,KAAgB;iBAC7B,CAAC,CAAC;gBACH,MAAM;QACV,CAAC;QAED,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;QAEpC,uCAAuC;QACvC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACjD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,OAAO,IAAI,CAAC,CAAC;QAC5C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { ScanResult } from "../analyzers/types.js";
2
+ export declare function formatJson(result: ScanResult): string;
3
+ //# sourceMappingURL=json.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../../src/reporters/json.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAExD,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAErD"}
@@ -0,0 +1,4 @@
1
+ export function formatJson(result) {
2
+ return JSON.stringify(result, null, 2);
3
+ }
4
+ //# sourceMappingURL=json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json.js","sourceRoot":"","sources":["../../src/reporters/json.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,UAAU,CAAC,MAAkB;IAC3C,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AACzC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { ScanResult } from "../analyzers/types.js";
2
+ export declare function formatSarif(result: ScanResult): string;
3
+ //# sourceMappingURL=sarif.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sarif.d.ts","sourceRoot":"","sources":["../../src/reporters/sarif.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAY,MAAM,uBAAuB,CAAC;AAkDlE,wBAAgB,WAAW,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAoDtD"}
@@ -0,0 +1,57 @@
1
+ const SEVERITY_TO_SARIF_LEVEL = {
2
+ critical: "error",
3
+ high: "error",
4
+ medium: "warning",
5
+ low: "note",
6
+ };
7
+ export function formatSarif(result) {
8
+ // Collect unique rules
9
+ const ruleMap = new Map();
10
+ for (const finding of result.findings) {
11
+ if (!ruleMap.has(finding.ruleId)) {
12
+ ruleMap.set(finding.ruleId, {
13
+ id: finding.ruleId,
14
+ name: finding.ruleId.replace(/[^a-zA-Z0-9]/g, ""),
15
+ shortDescription: { text: finding.title },
16
+ defaultConfiguration: {
17
+ level: SEVERITY_TO_SARIF_LEVEL[finding.severity],
18
+ },
19
+ });
20
+ }
21
+ }
22
+ const sarif = {
23
+ $schema: "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/main/sarif-2.1/schema/sarif-schema-2.1.0.json",
24
+ version: "2.1.0",
25
+ runs: [
26
+ {
27
+ tool: {
28
+ driver: {
29
+ name: "mcp-scanner",
30
+ version: result.scanner.version,
31
+ rules: Array.from(ruleMap.values()),
32
+ },
33
+ },
34
+ results: result.findings.map((f) => ({
35
+ ruleId: f.ruleId,
36
+ level: SEVERITY_TO_SARIF_LEVEL[f.severity],
37
+ message: { text: f.message },
38
+ locations: [
39
+ {
40
+ physicalLocation: {
41
+ artifactLocation: { uri: f.location.file },
42
+ region: {
43
+ startLine: f.location.startLine,
44
+ startColumn: f.location.startColumn,
45
+ endLine: f.location.endLine,
46
+ endColumn: f.location.endColumn,
47
+ },
48
+ },
49
+ },
50
+ ],
51
+ })),
52
+ },
53
+ ],
54
+ };
55
+ return JSON.stringify(sarif, null, 2);
56
+ }
57
+ //# sourceMappingURL=sarif.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sarif.js","sourceRoot":"","sources":["../../src/reporters/sarif.ts"],"names":[],"mappings":"AA2CA,MAAM,uBAAuB,GAA6B;IACxD,QAAQ,EAAE,OAAO;IACjB,IAAI,EAAE,OAAO;IACb,MAAM,EAAE,SAAS;IACjB,GAAG,EAAE,MAAM;CACZ,CAAC;AAEF,MAAM,UAAU,WAAW,CAAC,MAAkB;IAC5C,uBAAuB;IACvB,MAAM,OAAO,GAAG,IAAI,GAAG,EAA+B,CAAC;IACvD,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACtC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YACjC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE;gBAC1B,EAAE,EAAE,OAAO,CAAC,MAAM;gBAClB,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC;gBACjD,gBAAgB,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,EAAE;gBACzC,oBAAoB,EAAE;oBACpB,KAAK,EAAE,uBAAuB,CAAC,OAAO,CAAC,QAAQ,CAAC;iBACjD;aACF,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,MAAM,KAAK,GAAgB;QACzB,OAAO,EACL,sGAAsG;QACxG,OAAO,EAAE,OAAO;QAChB,IAAI,EAAE;YACJ;gBACE,IAAI,EAAE;oBACJ,MAAM,EAAE;wBACN,IAAI,EAAE,aAAa;wBACnB,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,OAAO;wBAC/B,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;qBACpC;iBACF;gBACD,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;oBACnC,MAAM,EAAE,CAAC,CAAC,MAAM;oBAChB,KAAK,EAAE,uBAAuB,CAAC,CAAC,CAAC,QAAQ,CAAC;oBAC1C,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE;oBAC5B,SAAS,EAAE;wBACT;4BACE,gBAAgB,EAAE;gCAChB,gBAAgB,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE;gCAC1C,MAAM,EAAE;oCACN,SAAS,EAAE,CAAC,CAAC,QAAQ,CAAC,SAAS;oCAC/B,WAAW,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW;oCACnC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,OAAO;oCAC3B,SAAS,EAAE,CAAC,CAAC,QAAQ,CAAC,SAAS;iCAChC;6BACF;yBACF;qBACF;iBACF,CAAC,CAAC;aACJ;SACF;KACF,CAAC;IAEF,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AACxC,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { ScanResult } from "../analyzers/types.js";
2
+ export interface TextFormatOptions {
3
+ color?: boolean;
4
+ quiet?: boolean;
5
+ }
6
+ export declare function formatText(result: ScanResult, options?: TextFormatOptions): string;
7
+ //# sourceMappingURL=text.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../src/reporters/text.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAqB,MAAM,uBAAuB,CAAC;AAE3E,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,wBAAgB,UAAU,CACxB,MAAM,EAAE,UAAU,EAClB,OAAO,GAAE,iBAAsB,GAC9B,MAAM,CAoER"}
@@ -0,0 +1,89 @@
1
+ import chalk, { Chalk } from "chalk";
2
+ export function formatText(result, options = {}) {
3
+ const { color = true, quiet = false } = options;
4
+ const c = color ? chalk : new Chalk({ level: 0 });
5
+ const lines = [];
6
+ // ─── Banner ───
7
+ if (!quiet) {
8
+ lines.push("");
9
+ lines.push(c.dim(` Sigil v${result.scanner.version}`));
10
+ lines.push("");
11
+ lines.push(` Scanning: ${c.bold(result.target.path)}`);
12
+ lines.push(` Language: ${result.target.language}` +
13
+ (result.target.name ? ` (${result.target.name})` : ""));
14
+ lines.push(` Tools: ${result.server.tools.length} detected` +
15
+ ` | Resources: ${result.server.resources.length} detected` +
16
+ ` | Prompts: ${result.server.prompts.length} detected`);
17
+ lines.push("");
18
+ }
19
+ // ─── Findings ───
20
+ if (result.findings.length === 0) {
21
+ lines.push(c.green(" No security findings detected."));
22
+ lines.push("");
23
+ }
24
+ else {
25
+ for (const finding of result.findings) {
26
+ lines.push(formatFinding(finding, c));
27
+ lines.push("");
28
+ }
29
+ }
30
+ // ─── Summary ───
31
+ if (!quiet) {
32
+ const sep = c.dim(" " + "─".repeat(50));
33
+ lines.push(sep);
34
+ const counts = countBySeverity(result.findings);
35
+ const countParts = [];
36
+ if (counts.critical > 0)
37
+ countParts.push(c.red.bold(`${counts.critical} critical`));
38
+ if (counts.high > 0)
39
+ countParts.push(c.yellow(`${counts.high} high`));
40
+ if (counts.medium > 0)
41
+ countParts.push(c.blue(`${counts.medium} medium`));
42
+ if (counts.low > 0)
43
+ countParts.push(c.dim(`${counts.low} low`));
44
+ const total = result.findings.length;
45
+ lines.push(` ${total} finding${total !== 1 ? "s" : ""}: ${countParts.join(", ")}`);
46
+ const scoreColor = result.score.label === "PASS"
47
+ ? c.green
48
+ : result.score.label === "WARN"
49
+ ? c.yellow
50
+ : c.red;
51
+ lines.push(` Trust Score: ${scoreColor.bold(`${result.score.value}/100`)} (${scoreColor(result.score.label)})`);
52
+ lines.push(sep);
53
+ lines.push("");
54
+ }
55
+ return lines.join("\n");
56
+ }
57
+ function formatFinding(finding, c) {
58
+ const badge = severityBadge(finding.severity, c);
59
+ const lines = [];
60
+ lines.push(` ${badge} ${c.bold(finding.ruleId)} ${finding.title}`);
61
+ lines.push(c.dim(` │ `) + `${finding.location.file}:${finding.location.startLine}`);
62
+ lines.push(c.dim(` │ `) + finding.message);
63
+ return lines.join("\n");
64
+ }
65
+ function severityBadge(severity, c) {
66
+ switch (severity) {
67
+ case "critical":
68
+ return c.bgRed.white.bold(` CRITICAL `);
69
+ case "high":
70
+ return c.bgYellow.black.bold(` HIGH `);
71
+ case "medium":
72
+ return c.bgBlue.white(` MEDIUM `);
73
+ case "low":
74
+ return c.dim(` LOW `);
75
+ }
76
+ }
77
+ function countBySeverity(findings) {
78
+ const counts = {
79
+ critical: 0,
80
+ high: 0,
81
+ medium: 0,
82
+ low: 0,
83
+ };
84
+ for (const f of findings) {
85
+ counts[f.severity]++;
86
+ }
87
+ return counts;
88
+ }
89
+ //# sourceMappingURL=text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/reporters/text.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { AnalysisContext, Finding } from "../analyzers/types.js";
2
+ export declare function detectHardcodedCredentials(context: AnalysisContext): Finding[];
3
+ export declare function detectSecretsInConfig(context: AnalysisContext): Finding[];
4
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/rules/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AA2BtE,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,EAAE,CAmC9E;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,EAAE,CAkCzE"}
@@ -0,0 +1,88 @@
1
+ const CREDENTIAL_PATTERNS = [
2
+ { pattern: /["'`](sk-[a-zA-Z0-9_-]{20,})["'`]/g, label: "OpenAI API key" },
3
+ { pattern: /["'`](sk-proj-[a-zA-Z0-9_-]{20,})["'`]/g, label: "OpenAI project key" },
4
+ { pattern: /["'`](sk-ant-[a-zA-Z0-9_-]{20,})["'`]/g, label: "Anthropic API key" },
5
+ { pattern: /["'`](ghp_[a-zA-Z0-9]{36,})["'`]/g, label: "GitHub personal access token" },
6
+ { pattern: /["'`](gho_[a-zA-Z0-9]{36,})["'`]/g, label: "GitHub OAuth token" },
7
+ { pattern: /["'`](github_pat_[a-zA-Z0-9_]{22,})["'`]/g, label: "GitHub PAT" },
8
+ { pattern: /["'`](glpat-[a-zA-Z0-9_-]{20,})["'`]/g, label: "GitLab access token" },
9
+ { pattern: /["'`](xoxb-[a-zA-Z0-9-]+)["'`]/g, label: "Slack bot token" },
10
+ { pattern: /["'`](xoxp-[a-zA-Z0-9-]+)["'`]/g, label: "Slack user token" },
11
+ { pattern: /["'`](AKIA[A-Z0-9]{16})["'`]/g, label: "AWS access key ID" },
12
+ { pattern: /["'`](AIza[a-zA-Z0-9_-]{35})["'`]/g, label: "Google API key" },
13
+ // Connection strings with embedded passwords
14
+ { pattern: /["'`](mongodb(?:\+srv)?:\/\/[^"'`\s]*:[^"'`\s]*@[^"'`\s]+)["'`]/g, label: "MongoDB connection string with credentials" },
15
+ { pattern: /["'`](postgres(?:ql)?:\/\/[^"'`\s]*:[^"'`\s]*@[^"'`\s]+)["'`]/g, label: "PostgreSQL connection string with credentials" },
16
+ { pattern: /["'`](mysql:\/\/[^"'`\s]*:[^"'`\s]*@[^"'`\s]+)["'`]/g, label: "MySQL connection string with credentials" },
17
+ { pattern: /["'`](redis:\/\/[^"'`\s]*:[^"'`\s]*@[^"'`\s]+)["'`]/g, label: "Redis connection string with credentials" },
18
+ // Private keys
19
+ { pattern: /-----BEGIN (?:RSA |EC |DSA )?PRIVATE KEY-----/g, label: "Private key" },
20
+ ];
21
+ function findLineNumber(content, index) {
22
+ return content.slice(0, index).split("\n").length;
23
+ }
24
+ export function detectHardcodedCredentials(context) {
25
+ const findings = [];
26
+ for (const [file, content] of context.sources) {
27
+ const lines = content.split("\n");
28
+ for (const { pattern, label } of CREDENTIAL_PATTERNS) {
29
+ pattern.lastIndex = 0;
30
+ let match;
31
+ while ((match = pattern.exec(content)) !== null) {
32
+ const lineNumber = findLineNumber(content, match.index);
33
+ const line = lines[lineNumber - 1] || "";
34
+ const trimmed = line.trimStart();
35
+ // Skip comments
36
+ if (trimmed.startsWith("//") || trimmed.startsWith("#") || trimmed.startsWith("*"))
37
+ continue;
38
+ // Skip env var references
39
+ if (/process\.env|os\.environ|getenv|ENV\[/.test(line))
40
+ continue;
41
+ findings.push({
42
+ ruleId: "MCS-AUTH-001",
43
+ severity: "critical",
44
+ title: "Hardcoded Credentials",
45
+ message: `${label} found hardcoded in source code. Use environment variables instead.`,
46
+ location: { file, startLine: lineNumber, endLine: lineNumber },
47
+ fix: {
48
+ description: "Move the credential to an environment variable and reference it via process.env or os.environ.",
49
+ },
50
+ });
51
+ }
52
+ }
53
+ }
54
+ return findings;
55
+ }
56
+ export function detectSecretsInConfig(context) {
57
+ const findings = [];
58
+ if (!context.configEntries)
59
+ return findings;
60
+ for (const entry of context.configEntries) {
61
+ if (!entry.env)
62
+ continue;
63
+ for (const [key, value] of Object.entries(entry.env)) {
64
+ const looksLikeSecret = /key|token|secret|password|credential|auth/i.test(key) &&
65
+ !value.startsWith("$") &&
66
+ !value.startsWith("${") &&
67
+ value.length > 8;
68
+ const isKnownKey = CREDENTIAL_PATTERNS.some((p) => {
69
+ p.pattern.lastIndex = 0;
70
+ return p.pattern.test(`"${value}"`);
71
+ });
72
+ if (looksLikeSecret || isKnownKey) {
73
+ findings.push({
74
+ ruleId: "MCS-AUTH-002",
75
+ severity: "high",
76
+ title: "Secrets in MCP Configuration",
77
+ message: `MCP config for "${entry.name}" has a hardcoded secret in env var "${key}".`,
78
+ location: { file: "mcp-config", startLine: 1, endLine: 1 },
79
+ fix: {
80
+ description: "Reference the secret from your shell environment instead of hardcoding it in the config file.",
81
+ },
82
+ });
83
+ }
84
+ }
85
+ }
86
+ return findings;
87
+ }
88
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/rules/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { AnalysisContext, Finding } from "../analyzers/types.js";
2
+ export declare function detectDebugMode(context: AnalysisContext): Finding[];
3
+ export declare function detectVerboseErrors(context: AnalysisContext): Finding[];
4
+ export declare function detectInsecureTransport(context: AnalysisContext): Finding[];
5
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/rules/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAMtE,wBAAgB,eAAe,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,EAAE,CAyCnE;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,EAAE,CA0DvE;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,EAAE,CAmC3E"}