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.
Files changed (205) hide show
  1. package/LICENSE +21 -0
  2. package/README.ar.md +662 -0
  3. package/README.bn.md +662 -0
  4. package/README.bs.md +662 -0
  5. package/README.da.md +662 -0
  6. package/README.de.md +662 -0
  7. package/README.el.md +662 -0
  8. package/README.es.md +662 -0
  9. package/README.fr.md +663 -0
  10. package/README.hi.md +662 -0
  11. package/README.it.md +662 -0
  12. package/README.ja.md +663 -0
  13. package/README.ko.md +662 -0
  14. package/README.md +662 -0
  15. package/README.no.md +662 -0
  16. package/README.pl.md +662 -0
  17. package/README.pt-BR.md +662 -0
  18. package/README.ru.md +662 -0
  19. package/README.th.md +662 -0
  20. package/README.tr.md +662 -0
  21. package/README.uk.md +663 -0
  22. package/README.vi.md +662 -0
  23. package/README.zh-TW.md +661 -0
  24. package/README.zh.md +661 -0
  25. package/dist/config/env-scanner.d.ts +3 -0
  26. package/dist/config/env-scanner.d.ts.map +1 -0
  27. package/dist/config/env-scanner.js +85 -0
  28. package/dist/config/env-scanner.js.map +1 -0
  29. package/dist/config/index.d.ts +3 -0
  30. package/dist/config/index.d.ts.map +1 -0
  31. package/dist/config/index.js +169 -0
  32. package/dist/config/index.js.map +1 -0
  33. package/dist/config/mcp-config-parser.d.ts +16 -0
  34. package/dist/config/mcp-config-parser.d.ts.map +1 -0
  35. package/dist/config/mcp-config-parser.js +86 -0
  36. package/dist/config/mcp-config-parser.js.map +1 -0
  37. package/dist/config/server-verification.d.ts +5 -0
  38. package/dist/config/server-verification.d.ts.map +1 -0
  39. package/dist/config/server-verification.js +221 -0
  40. package/dist/config/server-verification.js.map +1 -0
  41. package/dist/data/dangerous-sinks.d.ts +13 -0
  42. package/dist/data/dangerous-sinks.d.ts.map +1 -0
  43. package/dist/data/dangerous-sinks.js +45 -0
  44. package/dist/data/dangerous-sinks.js.map +1 -0
  45. package/dist/data/owasp-mcp-top10.d.ts +12 -0
  46. package/dist/data/owasp-mcp-top10.d.ts.map +1 -0
  47. package/dist/data/owasp-mcp-top10.js +95 -0
  48. package/dist/data/owasp-mcp-top10.js.map +1 -0
  49. package/dist/data/poisoning-patterns.d.ts +15 -0
  50. package/dist/data/poisoning-patterns.d.ts.map +1 -0
  51. package/dist/data/poisoning-patterns.js +146 -0
  52. package/dist/data/poisoning-patterns.js.map +1 -0
  53. package/dist/data/popular-packages.d.ts +2 -0
  54. package/dist/data/popular-packages.d.ts.map +1 -0
  55. package/dist/data/popular-packages.js +71 -0
  56. package/dist/data/popular-packages.js.map +1 -0
  57. package/dist/data/secret-patterns.d.ts +8 -0
  58. package/dist/data/secret-patterns.d.ts.map +1 -0
  59. package/dist/data/secret-patterns.js +129 -0
  60. package/dist/data/secret-patterns.js.map +1 -0
  61. package/dist/deps/index.d.ts +3 -0
  62. package/dist/deps/index.d.ts.map +1 -0
  63. package/dist/deps/index.js +308 -0
  64. package/dist/deps/index.js.map +1 -0
  65. package/dist/deps/install-script-detector.d.ts +9 -0
  66. package/dist/deps/install-script-detector.d.ts.map +1 -0
  67. package/dist/deps/install-script-detector.js +98 -0
  68. package/dist/deps/install-script-detector.js.map +1 -0
  69. package/dist/deps/lockfile-parser.d.ts +15 -0
  70. package/dist/deps/lockfile-parser.d.ts.map +1 -0
  71. package/dist/deps/lockfile-parser.js +123 -0
  72. package/dist/deps/lockfile-parser.js.map +1 -0
  73. package/dist/deps/typosquat-checker.d.ts +10 -0
  74. package/dist/deps/typosquat-checker.d.ts.map +1 -0
  75. package/dist/deps/typosquat-checker.js +84 -0
  76. package/dist/deps/typosquat-checker.js.map +1 -0
  77. package/dist/index.d.ts +3 -0
  78. package/dist/index.d.ts.map +1 -0
  79. package/dist/index.js +315 -0
  80. package/dist/index.js.map +1 -0
  81. package/dist/meta/sources.d.ts +3 -0
  82. package/dist/meta/sources.d.ts.map +1 -0
  83. package/dist/meta/sources.js +43 -0
  84. package/dist/meta/sources.js.map +1 -0
  85. package/dist/protocol/mcp-server.d.ts +4 -0
  86. package/dist/protocol/mcp-server.d.ts.map +1 -0
  87. package/dist/protocol/mcp-server.js +32 -0
  88. package/dist/protocol/mcp-server.js.map +1 -0
  89. package/dist/protocol/tools.d.ts +3 -0
  90. package/dist/protocol/tools.d.ts.map +1 -0
  91. package/dist/protocol/tools.js +21 -0
  92. package/dist/protocol/tools.js.map +1 -0
  93. package/dist/report/index.d.ts +3 -0
  94. package/dist/report/index.d.ts.map +1 -0
  95. package/dist/report/index.js +259 -0
  96. package/dist/report/index.js.map +1 -0
  97. package/dist/report/json-report.d.ts +4 -0
  98. package/dist/report/json-report.d.ts.map +1 -0
  99. package/dist/report/json-report.js +61 -0
  100. package/dist/report/json-report.js.map +1 -0
  101. package/dist/report/markdown.d.ts +3 -0
  102. package/dist/report/markdown.d.ts.map +1 -0
  103. package/dist/report/markdown.js +89 -0
  104. package/dist/report/markdown.js.map +1 -0
  105. package/dist/report/sarif.d.ts +3 -0
  106. package/dist/report/sarif.d.ts.map +1 -0
  107. package/dist/report/sarif.js +56 -0
  108. package/dist/report/sarif.js.map +1 -0
  109. package/dist/runtime/client.d.ts +31 -0
  110. package/dist/runtime/client.d.ts.map +1 -0
  111. package/dist/runtime/client.js +53 -0
  112. package/dist/runtime/client.js.map +1 -0
  113. package/dist/runtime/index.d.ts +3 -0
  114. package/dist/runtime/index.d.ts.map +1 -0
  115. package/dist/runtime/index.js +239 -0
  116. package/dist/runtime/index.js.map +1 -0
  117. package/dist/runtime/pinning.d.ts +21 -0
  118. package/dist/runtime/pinning.d.ts.map +1 -0
  119. package/dist/runtime/pinning.js +74 -0
  120. package/dist/runtime/pinning.js.map +1 -0
  121. package/dist/runtime/schema-analyzer.d.ts +14 -0
  122. package/dist/runtime/schema-analyzer.d.ts.map +1 -0
  123. package/dist/runtime/schema-analyzer.js +204 -0
  124. package/dist/runtime/schema-analyzer.js.map +1 -0
  125. package/dist/runtime/tool-analyzer.d.ts +6 -0
  126. package/dist/runtime/tool-analyzer.d.ts.map +1 -0
  127. package/dist/runtime/tool-analyzer.js +92 -0
  128. package/dist/runtime/tool-analyzer.js.map +1 -0
  129. package/dist/static/analyzers/code-execution.d.ts +4 -0
  130. package/dist/static/analyzers/code-execution.d.ts.map +1 -0
  131. package/dist/static/analyzers/code-execution.js +72 -0
  132. package/dist/static/analyzers/code-execution.js.map +1 -0
  133. package/dist/static/analyzers/command-injection.d.ts +4 -0
  134. package/dist/static/analyzers/command-injection.d.ts.map +1 -0
  135. package/dist/static/analyzers/command-injection.js +62 -0
  136. package/dist/static/analyzers/command-injection.js.map +1 -0
  137. package/dist/static/analyzers/info-disclosure.d.ts +4 -0
  138. package/dist/static/analyzers/info-disclosure.d.ts.map +1 -0
  139. package/dist/static/analyzers/info-disclosure.js +65 -0
  140. package/dist/static/analyzers/info-disclosure.js.map +1 -0
  141. package/dist/static/analyzers/insecure-crypto.d.ts +4 -0
  142. package/dist/static/analyzers/insecure-crypto.d.ts.map +1 -0
  143. package/dist/static/analyzers/insecure-crypto.js +65 -0
  144. package/dist/static/analyzers/insecure-crypto.js.map +1 -0
  145. package/dist/static/analyzers/logging-audit.d.ts +4 -0
  146. package/dist/static/analyzers/logging-audit.d.ts.map +1 -0
  147. package/dist/static/analyzers/logging-audit.js +81 -0
  148. package/dist/static/analyzers/logging-audit.js.map +1 -0
  149. package/dist/static/analyzers/path-traversal.d.ts +4 -0
  150. package/dist/static/analyzers/path-traversal.d.ts.map +1 -0
  151. package/dist/static/analyzers/path-traversal.js +42 -0
  152. package/dist/static/analyzers/path-traversal.js.map +1 -0
  153. package/dist/static/analyzers/prototype-pollution.d.ts +4 -0
  154. package/dist/static/analyzers/prototype-pollution.d.ts.map +1 -0
  155. package/dist/static/analyzers/prototype-pollution.js +80 -0
  156. package/dist/static/analyzers/prototype-pollution.js.map +1 -0
  157. package/dist/static/analyzers/regex-dos.d.ts +4 -0
  158. package/dist/static/analyzers/regex-dos.d.ts.map +1 -0
  159. package/dist/static/analyzers/regex-dos.js +78 -0
  160. package/dist/static/analyzers/regex-dos.js.map +1 -0
  161. package/dist/static/analyzers/secret-hardcoded.d.ts +4 -0
  162. package/dist/static/analyzers/secret-hardcoded.d.ts.map +1 -0
  163. package/dist/static/analyzers/secret-hardcoded.js +70 -0
  164. package/dist/static/analyzers/secret-hardcoded.js.map +1 -0
  165. package/dist/static/analyzers/ssrf.d.ts +4 -0
  166. package/dist/static/analyzers/ssrf.d.ts.map +1 -0
  167. package/dist/static/analyzers/ssrf.js +39 -0
  168. package/dist/static/analyzers/ssrf.js.map +1 -0
  169. package/dist/static/analyzers/unsafe-regex.d.ts +4 -0
  170. package/dist/static/analyzers/unsafe-regex.d.ts.map +1 -0
  171. package/dist/static/analyzers/unsafe-regex.js +36 -0
  172. package/dist/static/analyzers/unsafe-regex.js.map +1 -0
  173. package/dist/static/ast-engine.d.ts +22 -0
  174. package/dist/static/ast-engine.d.ts.map +1 -0
  175. package/dist/static/ast-engine.js +155 -0
  176. package/dist/static/ast-engine.js.map +1 -0
  177. package/dist/static/index.d.ts +3 -0
  178. package/dist/static/index.d.ts.map +1 -0
  179. package/dist/static/index.js +114 -0
  180. package/dist/static/index.js.map +1 -0
  181. package/dist/static/taint-tracker.d.ts +15 -0
  182. package/dist/static/taint-tracker.d.ts.map +1 -0
  183. package/dist/static/taint-tracker.js +70 -0
  184. package/dist/static/taint-tracker.js.map +1 -0
  185. package/dist/types/findings.d.ts +60 -0
  186. package/dist/types/findings.d.ts.map +1 -0
  187. package/dist/types/findings.js +9 -0
  188. package/dist/types/findings.js.map +1 -0
  189. package/dist/types/index.d.ts +23 -0
  190. package/dist/types/index.d.ts.map +1 -0
  191. package/dist/types/index.js +8 -0
  192. package/dist/types/index.js.map +1 -0
  193. package/dist/utils/crypto.d.ts +4 -0
  194. package/dist/utils/crypto.d.ts.map +1 -0
  195. package/dist/utils/crypto.js +12 -0
  196. package/dist/utils/crypto.js.map +1 -0
  197. package/dist/utils/fs-helpers.d.ts +7 -0
  198. package/dist/utils/fs-helpers.d.ts.map +1 -0
  199. package/dist/utils/fs-helpers.js +92 -0
  200. package/dist/utils/fs-helpers.js.map +1 -0
  201. package/dist/utils/levenshtein.d.ts +7 -0
  202. package/dist/utils/levenshtein.d.ts.map +1 -0
  203. package/dist/utils/levenshtein.js +89 -0
  204. package/dist/utils/levenshtein.js.map +1 -0
  205. package/package.json +57 -0
@@ -0,0 +1,114 @@
1
+ import { z } from "zod";
2
+ import { text } from "../types/index.js";
3
+ import { initProject } from "./ast-engine.js";
4
+ import { analyzeCommandInjection } from "./analyzers/command-injection.js";
5
+ import { analyzeSsrf } from "./analyzers/ssrf.js";
6
+ import { analyzePathTraversal } from "./analyzers/path-traversal.js";
7
+ import { analyzeCodeExecution } from "./analyzers/code-execution.js";
8
+ import { analyzeHardcodedSecrets } from "./analyzers/secret-hardcoded.js";
9
+ import { analyzeLogging } from "./analyzers/logging-audit.js";
10
+ import { analyzeInsecureCrypto } from "./analyzers/insecure-crypto.js";
11
+ import { analyzePrototypePollution } from "./analyzers/prototype-pollution.js";
12
+ import { analyzeRegexDos } from "./analyzers/regex-dos.js";
13
+ import { analyzeUnsafeRegex } from "./analyzers/unsafe-regex.js";
14
+ import { analyzeInfoDisclosure } from "./analyzers/info-disclosure.js";
15
+ const pathSchema = {
16
+ path: z.string().describe("Directory path containing TypeScript/JavaScript source files to analyze"),
17
+ include_node_modules: z.boolean().optional().describe("Include node_modules in scan (default: false)"),
18
+ tsconfig_path: z.string().optional().describe("Path to tsconfig.json (optional)"),
19
+ };
20
+ function formatFindings(findings) {
21
+ if (findings.length === 0)
22
+ return "No findings.";
23
+ const bySeverity = { critical: 0, high: 0, medium: 0, low: 0, info: 0 };
24
+ for (const f of findings)
25
+ bySeverity[f.severity]++;
26
+ let output = `${findings.length} finding(s): ${bySeverity.critical} critical, ${bySeverity.high} high, ${bySeverity.medium} medium, ${bySeverity.low} low, ${bySeverity.info} info\n\n`;
27
+ for (const f of findings) {
28
+ output += `[${f.severity.toUpperCase()}] ${f.id}: ${f.title}\n`;
29
+ if (f.file)
30
+ output += ` File: ${f.file}:${f.line ?? 0}:${f.column ?? 0}\n`;
31
+ output += ` OWASP: ${f.owasp_mcp} — ${f.owasp_mcp_title}\n`;
32
+ output += ` Evidence: ${f.evidence}\n`;
33
+ output += ` Remediation: ${f.remediation}\n\n`;
34
+ }
35
+ return output.trim();
36
+ }
37
+ const allAnalyzers = [
38
+ { name: "command-injection", fn: analyzeCommandInjection },
39
+ { name: "ssrf", fn: analyzeSsrf },
40
+ { name: "path-traversal", fn: analyzePathTraversal },
41
+ { name: "code-execution", fn: analyzeCodeExecution },
42
+ { name: "hardcoded-secrets", fn: analyzeHardcodedSecrets },
43
+ { name: "logging-audit", fn: analyzeLogging },
44
+ { name: "insecure-crypto", fn: analyzeInsecureCrypto },
45
+ { name: "prototype-pollution", fn: analyzePrototypePollution },
46
+ { name: "regex-dos", fn: analyzeRegexDos },
47
+ { name: "unsafe-regex", fn: analyzeUnsafeRegex },
48
+ { name: "info-disclosure", fn: analyzeInfoDisclosure },
49
+ ];
50
+ const sastScanDirectory = {
51
+ name: "sast_scan_directory",
52
+ description: "Run ALL static analysis checks on a TypeScript/JavaScript source directory. Initializes AST project, discovers source files, runs all 11 analyzers, and returns aggregated findings sorted by severity.",
53
+ schema: pathSchema,
54
+ async execute(args) {
55
+ const { project, sourceFiles, rootDir } = initProject(args.path, args.tsconfig_path);
56
+ if (sourceFiles.length === 0) {
57
+ return text(`No source files found in ${args.path}`);
58
+ }
59
+ const allFindings = [];
60
+ for (const analyzer of allAnalyzers) {
61
+ try {
62
+ const findings = analyzer.fn(sourceFiles);
63
+ allFindings.push(...findings);
64
+ }
65
+ catch (err) {
66
+ allFindings.push({
67
+ id: `SAST-ERR-${analyzer.name}`,
68
+ title: `Analyzer Error: ${analyzer.name}`,
69
+ severity: "info",
70
+ owasp_mcp: "MCP05",
71
+ owasp_mcp_title: "Command Injection & Code Execution",
72
+ category: "static",
73
+ evidence: `${analyzer.name} analyzer threw: ${err instanceof Error ? err.message : String(err)}`,
74
+ remediation: "This is an internal scanner error, not a finding in your code.",
75
+ });
76
+ }
77
+ }
78
+ // Sort by severity
79
+ const order = { critical: 0, high: 1, medium: 2, low: 3, info: 4 };
80
+ allFindings.sort((a, b) => order[a.severity] - order[b.severity]);
81
+ let header = `Scanned ${sourceFiles.length} files in ${rootDir}\n\n`;
82
+ return text(header + formatFindings(allFindings));
83
+ },
84
+ };
85
+ function makeSingleAnalyzerTool(name, description, analyzerFn) {
86
+ return {
87
+ name,
88
+ description,
89
+ schema: { path: z.string().describe("Directory path containing source files to analyze") },
90
+ async execute(args) {
91
+ const { sourceFiles, rootDir } = initProject(args.path);
92
+ if (sourceFiles.length === 0)
93
+ return text(`No source files found in ${args.path}`);
94
+ const findings = analyzerFn(sourceFiles);
95
+ let header = `Scanned ${sourceFiles.length} files in ${rootDir}\n\n`;
96
+ return text(header + formatFindings(findings));
97
+ },
98
+ };
99
+ }
100
+ export const staticTools = [
101
+ sastScanDirectory,
102
+ makeSingleAnalyzerTool("sast_command_injection", "AST-scan for command injection: child_process.exec(), execSync(), spawn() with shell:true — where arguments include user-controlled input. Reports file, line, column, and the exact dangerous expression.", analyzeCommandInjection),
103
+ makeSingleAnalyzerTool("sast_ssrf", "AST-scan for SSRF: fetch(), axios.get/post(), http.request() — where the URL argument contains user-controlled input without domain validation.", analyzeSsrf),
104
+ makeSingleAnalyzerTool("sast_path_traversal", "AST-scan for path traversal: fs.readFile(), writeFile(), readdir(), unlink() — where path argument includes user input without path.resolve() validation.", analyzePathTraversal),
105
+ makeSingleAnalyzerTool("sast_code_execution", "AST-scan for dangerous code execution: eval(), new Function(), vm.runInNewContext(), setTimeout(string). Any occurrence is flagged regardless of input source.", analyzeCodeExecution),
106
+ makeSingleAnalyzerTool("sast_hardcoded_secrets", "Scan all string literals and template literals for hardcoded secrets using 20+ regex patterns: AWS keys, GitHub tokens, Slack tokens, Stripe keys, private keys, JWTs, database URLs, and more.", analyzeHardcodedSecrets),
107
+ makeSingleAnalyzerTool("sast_missing_logging", "Detect missing security controls: tool handlers without try-catch, empty catch blocks, stack trace exposure in responses, missing audit logging.", analyzeLogging),
108
+ makeSingleAnalyzerTool("sast_insecure_crypto", "Detect weak cryptography: createHash('md5'), createHash('sha1'), Math.random() for token generation, DES/RC4 usage.", analyzeInsecureCrypto),
109
+ makeSingleAnalyzerTool("sast_prototype_pollution", "Detect prototype pollution: Object.assign() with user input, JSON.parse() on untrusted data, bracket notation with user-controlled keys.", analyzePrototypePollution),
110
+ makeSingleAnalyzerTool("sast_regex_dos", "Detect ReDoS patterns: nested quantifiers (a+)+, alternation with overlap, backreferences in quantified groups.", analyzeRegexDos),
111
+ makeSingleAnalyzerTool("sast_unsafe_regex", "Detect new RegExp() with user-controlled input without proper escaping. Attacker-controlled regex can cause ReDoS or bypass validation.", analyzeUnsafeRegex),
112
+ makeSingleAnalyzerTool("sast_info_disclosure", "Detect information disclosure: sensitive data in console.log, process.env serialization, stack traces in responses, file paths in error messages.", analyzeInfoDisclosure),
113
+ ];
114
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/static/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { Node, type SourceFile, type CallExpression } from "ts-morph";
2
+ export interface TaintFlow {
3
+ source: string;
4
+ sink: string;
5
+ file: string;
6
+ line: number;
7
+ column: number;
8
+ evidence: string;
9
+ }
10
+ export declare function isCallTainted(call: CallExpression): boolean;
11
+ export declare function getCallEvidence(call: CallExpression): string;
12
+ export declare function findToolHandlers(sourceFile: SourceFile): Node[];
13
+ export declare function isInsideTryCatch(node: Node): boolean;
14
+ export declare function isEmptyCatch(node: Node): boolean;
15
+ //# sourceMappingURL=taint-tracker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"taint-tracker.d.ts","sourceRoot":"","sources":["../../src/static/taint-tracker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAc,KAAK,UAAU,EAAE,KAAK,cAAc,EAAE,MAAM,UAAU,CAAC;AAGlF,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAGD,wBAAgB,aAAa,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAG3D;AAGD,wBAAgB,eAAe,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAI5D;AAGD,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,UAAU,GAAG,IAAI,EAAE,CAwC/D;AAGD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAOpD;AAGD,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAKhD"}
@@ -0,0 +1,70 @@
1
+ import { SyntaxKind } from "ts-morph";
2
+ import { containsUserInput } from "./ast-engine.js";
3
+ // Check if any argument to a call expression contains tainted data
4
+ export function isCallTainted(call) {
5
+ const args = call.getArguments();
6
+ return args.some(arg => containsUserInput(arg));
7
+ }
8
+ // Get a human-readable evidence string for a call
9
+ export function getCallEvidence(call) {
10
+ const text = call.getText();
11
+ // Truncate very long call expressions
12
+ return text.length > 200 ? text.substring(0, 200) + "..." : text;
13
+ }
14
+ // Find all function declarations that look like MCP tool handlers
15
+ export function findToolHandlers(sourceFile) {
16
+ const handlers = [];
17
+ // Look for: async execute(args, ...) { ... }
18
+ const methods = sourceFile.getDescendantsOfKind(SyntaxKind.MethodDeclaration);
19
+ for (const m of methods) {
20
+ const name = m.getName();
21
+ if (name === "execute" || name === "handler" || name === "run") {
22
+ handlers.push(m);
23
+ }
24
+ }
25
+ // Look for: execute: async (args) => { ... }
26
+ // These are property assignments in object literals
27
+ const propAssignments = sourceFile.getDescendantsOfKind(SyntaxKind.PropertyAssignment);
28
+ for (const pa of propAssignments) {
29
+ const name = pa.getName();
30
+ if (name === "execute" || name === "handler" || name === "run") {
31
+ handlers.push(pa);
32
+ }
33
+ }
34
+ // Also look for async functions that take (args, ctx) pattern
35
+ const funcs = sourceFile.getDescendantsOfKind(SyntaxKind.FunctionDeclaration);
36
+ for (const f of funcs) {
37
+ const params = f.getParameters();
38
+ if (params.some(p => p.getName() === "args" || p.getName() === "ctx")) {
39
+ handlers.push(f);
40
+ }
41
+ }
42
+ const arrowFuncs = sourceFile.getDescendantsOfKind(SyntaxKind.ArrowFunction);
43
+ for (const f of arrowFuncs) {
44
+ const params = f.getParameters();
45
+ if (params.some(p => p.getName() === "args")) {
46
+ handlers.push(f);
47
+ }
48
+ }
49
+ return handlers;
50
+ }
51
+ // Check if a node is inside a try-catch block
52
+ export function isInsideTryCatch(node) {
53
+ let current = node.getParent();
54
+ while (current) {
55
+ if (current.getKind() === SyntaxKind.TryStatement)
56
+ return true;
57
+ current = current.getParent();
58
+ }
59
+ return false;
60
+ }
61
+ // Check if a catch clause is empty (swallows errors)
62
+ export function isEmptyCatch(node) {
63
+ if (node.getKind() !== SyntaxKind.CatchClause)
64
+ return false;
65
+ const block = node.getChildrenOfKind(SyntaxKind.Block)[0];
66
+ if (!block)
67
+ return true;
68
+ return block.getStatements().length === 0;
69
+ }
70
+ //# sourceMappingURL=taint-tracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"taint-tracker.js","sourceRoot":"","sources":["../../src/static/taint-tracker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ export type OwaspMcpId = "MCP01" | "MCP02" | "MCP03" | "MCP04" | "MCP05" | "MCP06" | "MCP07" | "MCP08" | "MCP09" | "MCP10";
2
+ export type Severity = "critical" | "high" | "medium" | "low" | "info";
3
+ export type FindingCategory = "runtime" | "static" | "config" | "deps" | "report";
4
+ export interface Finding {
5
+ id: string;
6
+ title: string;
7
+ severity: Severity;
8
+ owasp_mcp: OwaspMcpId;
9
+ owasp_mcp_title: string;
10
+ category: FindingCategory;
11
+ file?: string;
12
+ line?: number;
13
+ column?: number;
14
+ evidence: string;
15
+ remediation: string;
16
+ cwe?: string;
17
+ references?: string[];
18
+ }
19
+ export interface ToolPin {
20
+ name: string;
21
+ hash: string;
22
+ description_preview: string;
23
+ }
24
+ export interface PinFile {
25
+ pin_name: string;
26
+ server_command: string;
27
+ server_args?: string[];
28
+ timestamp: string;
29
+ tool_count: number;
30
+ manifest_hash: string;
31
+ tools: ToolPin[];
32
+ }
33
+ export interface ScanReport {
34
+ scanner: string;
35
+ version: string;
36
+ timestamp: string;
37
+ target: string;
38
+ duration_ms: number;
39
+ summary: {
40
+ total: number;
41
+ critical: number;
42
+ high: number;
43
+ medium: number;
44
+ low: number;
45
+ info: number;
46
+ };
47
+ owasp_compliance: OwaspComplianceEntry[];
48
+ findings: Finding[];
49
+ }
50
+ export interface OwaspComplianceEntry {
51
+ id: OwaspMcpId;
52
+ title: string;
53
+ status: "pass" | "fail" | "not_tested";
54
+ finding_count: number;
55
+ highest_severity: Severity | null;
56
+ }
57
+ export declare function createFinding(partial: Omit<Finding, "id"> & {
58
+ id?: string;
59
+ }, idPrefix: string, counter: number): Finding;
60
+ //# sourceMappingURL=findings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"findings.d.ts","sourceRoot":"","sources":["../../src/types/findings.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,UAAU,GAClB,OAAO,GACP,OAAO,GACP,OAAO,GACP,OAAO,GACP,OAAO,GACP,OAAO,GACP,OAAO,GACP,OAAO,GACP,OAAO,GACP,OAAO,CAAC;AAEZ,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;AAEvE,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;AAIlF,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,QAAQ,CAAC;IACnB,SAAS,EAAE,UAAU,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,eAAe,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAID,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,OAAO;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,OAAO,EAAE,CAAC;CAClB;AAID,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE;QACP,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,gBAAgB,EAAE,oBAAoB,EAAE,CAAC;IACzC,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,UAAU,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,YAAY,CAAC;IACvC,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,QAAQ,GAAG,IAAI,CAAC;CACnC;AAID,wBAAgB,aAAa,CAC3B,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG;IAAE,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,EAC9C,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GACd,OAAO,CAKT"}
@@ -0,0 +1,9 @@
1
+ // ─── OWASP MCP Top 10 Categories ───
2
+ // ─── Helper to create findings ───
3
+ export function createFinding(partial, idPrefix, counter) {
4
+ return {
5
+ ...partial,
6
+ id: partial.id ?? `${idPrefix}-${String(counter).padStart(3, "0")}`,
7
+ };
8
+ }
9
+ //# sourceMappingURL=findings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"findings.js","sourceRoot":"","sources":["../../src/types/findings.ts"],"names":[],"mappings":"AAAA,sCAAsC;AAkFtC,oCAAoC;AAEpC,MAAM,UAAU,aAAa,CAC3B,OAA8C,EAC9C,QAAgB,EAChB,OAAe;IAEf,OAAO;QACL,GAAG,OAAO;QACV,EAAE,EAAE,OAAO,CAAC,EAAE,IAAI,GAAG,QAAQ,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;KACpE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,23 @@
1
+ import type { z } from "zod";
2
+ export interface ToolDef {
3
+ name: string;
4
+ description: string;
5
+ schema: Record<string, z.ZodType>;
6
+ execute: (args: Record<string, unknown>, ctx: ToolContext) => Promise<ToolResult>;
7
+ }
8
+ export interface ToolContext {
9
+ config: ScannerConfig;
10
+ }
11
+ export interface ScannerConfig {
12
+ pinDir: string;
13
+ }
14
+ export interface ToolResult {
15
+ [key: string]: unknown;
16
+ content: {
17
+ type: "text";
18
+ text: string;
19
+ }[];
20
+ }
21
+ export declare function text(msg: string): ToolResult;
22
+ export declare function json(data: unknown): ToolResult;
23
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAI7B,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;IAClC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,WAAW,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;CACnF;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,aAAa,CAAC;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,UAAU;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC3C;AAID,wBAAgB,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAE5C;AAED,wBAAgB,IAAI,CAAC,IAAI,EAAE,OAAO,GAAG,UAAU,CAE9C"}
@@ -0,0 +1,8 @@
1
+ // ─── Response Helpers ───
2
+ export function text(msg) {
3
+ return { content: [{ type: "text", text: msg }] };
4
+ }
5
+ export function json(data) {
6
+ return text(JSON.stringify(data, null, 2));
7
+ }
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAwBA,2BAA2B;AAE3B,MAAM,UAAU,IAAI,CAAC,GAAW;IAC9B,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,IAAa;IAChC,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAC7C,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare function sha256(input: string): string;
2
+ export declare function hashToolDefinition(name: string, description: string, schema: unknown): string;
3
+ export declare function hashManifest(toolHashes: string[]): string;
4
+ //# sourceMappingURL=crypto.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../../src/utils/crypto.ts"],"names":[],"mappings":"AAEA,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE5C;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,CAG7F;AAED,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,CAEzD"}
@@ -0,0 +1,12 @@
1
+ import { createHash } from "node:crypto";
2
+ export function sha256(input) {
3
+ return createHash("sha256").update(input, "utf8").digest("hex");
4
+ }
5
+ export function hashToolDefinition(name, description, schema) {
6
+ const payload = JSON.stringify({ name, description, schema });
7
+ return sha256(payload);
8
+ }
9
+ export function hashManifest(toolHashes) {
10
+ return sha256(toolHashes.sort().join(":"));
11
+ }
12
+ //# sourceMappingURL=crypto.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto.js","sourceRoot":"","sources":["../../src/utils/crypto.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,UAAU,MAAM,CAAC,KAAa;IAClC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAClE,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,IAAY,EAAE,WAAmB,EAAE,MAAe;IACnF,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,CAAC;IAC9D,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC;AACzB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,UAAoB;IAC/C,OAAO,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC7C,CAAC"}
@@ -0,0 +1,7 @@
1
+ export declare function safeReadFile(filePath: string): Promise<string | null>;
2
+ export declare function safeReadJson<T = unknown>(filePath: string): Promise<T | null>;
3
+ export declare function fileExists(filePath: string): Promise<boolean>;
4
+ export declare function getFileStat(filePath: string): Promise<import("fs").Stats | null>;
5
+ export declare function discoverSourceFiles(dir: string, includeNodeModules?: boolean): Promise<string[]>;
6
+ export declare function discoverFiles(dir: string, pattern: RegExp): Promise<string[]>;
7
+ //# sourceMappingURL=fs-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs-helpers.d.ts","sourceRoot":"","sources":["../../src/utils/fs-helpers.ts"],"names":[],"mappings":"AAGA,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAM3E;AAED,wBAAsB,YAAY,CAAC,CAAC,GAAG,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAQnF;AAED,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOnE;AAED,wBAAsB,WAAW,CAAC,QAAQ,EAAE,MAAM,sCAMjD;AAID,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,MAAM,EACX,kBAAkB,UAAQ,GACzB,OAAO,CAAC,MAAM,EAAE,CAAC,CA0BnB;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAwBnF"}
@@ -0,0 +1,92 @@
1
+ import { readFile, readdir, stat, access } from "node:fs/promises";
2
+ import { join, resolve, extname } from "node:path";
3
+ export async function safeReadFile(filePath) {
4
+ try {
5
+ return await readFile(filePath, "utf8");
6
+ }
7
+ catch {
8
+ return null;
9
+ }
10
+ }
11
+ export async function safeReadJson(filePath) {
12
+ const content = await safeReadFile(filePath);
13
+ if (!content)
14
+ return null;
15
+ try {
16
+ return JSON.parse(content);
17
+ }
18
+ catch {
19
+ return null;
20
+ }
21
+ }
22
+ export async function fileExists(filePath) {
23
+ try {
24
+ await access(filePath);
25
+ return true;
26
+ }
27
+ catch {
28
+ return false;
29
+ }
30
+ }
31
+ export async function getFileStat(filePath) {
32
+ try {
33
+ return await stat(filePath);
34
+ }
35
+ catch {
36
+ return null;
37
+ }
38
+ }
39
+ const TS_JS_EXTENSIONS = new Set([".ts", ".js", ".mts", ".mjs", ".cts", ".cjs"]);
40
+ export async function discoverSourceFiles(dir, includeNodeModules = false) {
41
+ const results = [];
42
+ async function walk(currentDir) {
43
+ let entries;
44
+ try {
45
+ entries = await readdir(currentDir, { withFileTypes: true });
46
+ }
47
+ catch {
48
+ return;
49
+ }
50
+ for (const entry of entries) {
51
+ const fullPath = join(currentDir, entry.name);
52
+ if (entry.isDirectory()) {
53
+ if (entry.name === "node_modules" && !includeNodeModules)
54
+ continue;
55
+ if (entry.name === "dist" || entry.name === ".git")
56
+ continue;
57
+ await walk(fullPath);
58
+ }
59
+ else if (entry.isFile() && TS_JS_EXTENSIONS.has(extname(entry.name))) {
60
+ results.push(fullPath);
61
+ }
62
+ }
63
+ }
64
+ await walk(resolve(dir));
65
+ return results.sort();
66
+ }
67
+ export async function discoverFiles(dir, pattern) {
68
+ const results = [];
69
+ async function walk(currentDir) {
70
+ let entries;
71
+ try {
72
+ entries = await readdir(currentDir, { withFileTypes: true });
73
+ }
74
+ catch {
75
+ return;
76
+ }
77
+ for (const entry of entries) {
78
+ const fullPath = join(currentDir, entry.name);
79
+ if (entry.isDirectory()) {
80
+ if (entry.name === "node_modules" || entry.name === ".git")
81
+ continue;
82
+ await walk(fullPath);
83
+ }
84
+ else if (entry.isFile() && pattern.test(entry.name)) {
85
+ results.push(fullPath);
86
+ }
87
+ }
88
+ }
89
+ await walk(resolve(dir));
90
+ return results.sort();
91
+ }
92
+ //# sourceMappingURL=fs-helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs-helpers.js","sourceRoot":"","sources":["../../src/utils/fs-helpers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export declare function levenshtein(a: string, b: string): number;
2
+ export declare function isKeyboardAdjacent(a: string, b: string): boolean;
3
+ export declare function isVowelSwap(a: string, b: string): boolean;
4
+ export declare function normalizeSeparators(name: string): string;
5
+ export declare function isSeparatorConfusion(a: string, b: string): boolean;
6
+ export declare function isScopeSquatting(a: string, b: string): boolean;
7
+ //# sourceMappingURL=levenshtein.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"levenshtein.d.ts","sourceRoot":"","sources":["../../src/utils/levenshtein.ts"],"names":[],"mappings":"AAAA,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAwBxD;AAkBD,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAYhE;AAID,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAWzD;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAGlE;AAED,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAS9D"}
@@ -0,0 +1,89 @@
1
+ export function levenshtein(a, b) {
2
+ const m = a.length;
3
+ const n = b.length;
4
+ if (m === 0)
5
+ return n;
6
+ if (n === 0)
7
+ return m;
8
+ const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));
9
+ for (let i = 0; i <= m; i++)
10
+ dp[i][0] = i;
11
+ for (let j = 0; j <= n; j++)
12
+ dp[0][j] = j;
13
+ for (let i = 1; i <= m; i++) {
14
+ for (let j = 1; j <= n; j++) {
15
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
16
+ dp[i][j] = Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1, dp[i - 1][j - 1] + cost);
17
+ }
18
+ }
19
+ return dp[m][n];
20
+ }
21
+ // Keyboard adjacency map (QWERTY layout)
22
+ const KEYBOARD_ADJACENT = {
23
+ q: ["w", "a"], w: ["q", "e", "s", "a"], e: ["w", "r", "d", "s"],
24
+ r: ["e", "t", "f", "d"], t: ["r", "y", "g", "f"], y: ["t", "u", "h", "g"],
25
+ u: ["y", "i", "j", "h"], i: ["u", "o", "k", "j"], o: ["i", "p", "l", "k"],
26
+ p: ["o", "l"],
27
+ a: ["q", "w", "s", "z"], s: ["a", "w", "e", "d", "z", "x"],
28
+ d: ["s", "e", "r", "f", "x", "c"], f: ["d", "r", "t", "g", "c", "v"],
29
+ g: ["f", "t", "y", "h", "v", "b"], h: ["g", "y", "u", "j", "b", "n"],
30
+ j: ["h", "u", "i", "k", "n", "m"], k: ["j", "i", "o", "l", "m"],
31
+ l: ["k", "o", "p"],
32
+ z: ["a", "s", "x"], x: ["z", "s", "d", "c"],
33
+ c: ["x", "d", "f", "v"], v: ["c", "f", "g", "b"],
34
+ b: ["v", "g", "h", "n"], n: ["b", "h", "j", "m"], m: ["n", "j", "k"],
35
+ };
36
+ export function isKeyboardAdjacent(a, b) {
37
+ if (a.length !== b.length)
38
+ return false;
39
+ let diffs = 0;
40
+ for (let i = 0; i < a.length; i++) {
41
+ if (a[i] !== b[i]) {
42
+ diffs++;
43
+ if (diffs > 1)
44
+ return false;
45
+ const adj = KEYBOARD_ADJACENT[a[i].toLowerCase()];
46
+ if (!adj || !adj.includes(b[i].toLowerCase()))
47
+ return false;
48
+ }
49
+ }
50
+ return diffs === 1;
51
+ }
52
+ const VOWELS = new Set(["a", "e", "i", "o", "u"]);
53
+ export function isVowelSwap(a, b) {
54
+ if (a.length !== b.length)
55
+ return false;
56
+ let diffs = 0;
57
+ for (let i = 0; i < a.length; i++) {
58
+ if (a[i] !== b[i]) {
59
+ diffs++;
60
+ if (diffs > 1)
61
+ return false;
62
+ if (!VOWELS.has(a[i].toLowerCase()) || !VOWELS.has(b[i].toLowerCase()))
63
+ return false;
64
+ }
65
+ }
66
+ return diffs === 1;
67
+ }
68
+ export function normalizeSeparators(name) {
69
+ return name.replace(/[-._]/g, "-").toLowerCase();
70
+ }
71
+ export function isSeparatorConfusion(a, b) {
72
+ if (a === b)
73
+ return false;
74
+ return normalizeSeparators(a) === normalizeSeparators(b);
75
+ }
76
+ export function isScopeSquatting(a, b) {
77
+ const scopeA = a.match(/^@([^/]+)\//);
78
+ const scopeB = b.match(/^@([^/]+)\//);
79
+ if (!scopeA || !scopeB)
80
+ return false;
81
+ if (scopeA[1] === scopeB[1])
82
+ return false;
83
+ const nameA = a.replace(/^@[^/]+\//, "");
84
+ const nameB = b.replace(/^@[^/]+\//, "");
85
+ if (nameA !== nameB)
86
+ return false;
87
+ return levenshtein(scopeA[1], scopeB[1]) <= 2;
88
+ }
89
+ //# sourceMappingURL=levenshtein.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"levenshtein.js","sourceRoot":"","sources":["../../src/utils/levenshtein.ts"],"names":[],"mappings":"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"}