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,80 @@
|
|
|
1
|
+
import { findCallExpressions, getCallName, getQualifiedCallName, getLocation, containsUserInput, SyntaxKind } from "../ast-engine.js";
|
|
2
|
+
import { getCallEvidence } from "../taint-tracker.js";
|
|
3
|
+
export function analyzePrototypePollution(sourceFiles) {
|
|
4
|
+
const findings = [];
|
|
5
|
+
let counter = 0;
|
|
6
|
+
for (const sf of sourceFiles) {
|
|
7
|
+
const calls = findCallExpressions(sf);
|
|
8
|
+
for (const call of calls) {
|
|
9
|
+
const qname = getQualifiedCallName(call);
|
|
10
|
+
// Object.assign with user input
|
|
11
|
+
if (qname === "Object.assign") {
|
|
12
|
+
const args = call.getArguments();
|
|
13
|
+
if (args.length >= 2 && containsUserInput(args[args.length - 1])) {
|
|
14
|
+
const loc = getLocation(call);
|
|
15
|
+
counter++;
|
|
16
|
+
findings.push({
|
|
17
|
+
id: `SAST-PROTO-${String(counter).padStart(3, "0")}`,
|
|
18
|
+
title: "Prototype Pollution via Object.assign()",
|
|
19
|
+
severity: "high",
|
|
20
|
+
owasp_mcp: "MCP05",
|
|
21
|
+
owasp_mcp_title: "Command Injection & Code Execution",
|
|
22
|
+
category: "static",
|
|
23
|
+
file: loc.file,
|
|
24
|
+
line: loc.line,
|
|
25
|
+
column: loc.column,
|
|
26
|
+
evidence: getCallEvidence(call),
|
|
27
|
+
remediation: "Filter __proto__, constructor, and prototype properties from user input before passing to Object.assign(). Use a safe merge utility.",
|
|
28
|
+
cwe: "CWE-1321",
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// JSON.parse followed by spread/assign
|
|
33
|
+
if (getCallName(call) === "parse" && qname === "JSON.parse") {
|
|
34
|
+
if (containsUserInput(call)) {
|
|
35
|
+
const loc = getLocation(call);
|
|
36
|
+
counter++;
|
|
37
|
+
findings.push({
|
|
38
|
+
id: `SAST-PROTO-${String(counter).padStart(3, "0")}`,
|
|
39
|
+
title: "JSON.parse() with Untrusted Input",
|
|
40
|
+
severity: "medium",
|
|
41
|
+
owasp_mcp: "MCP05",
|
|
42
|
+
owasp_mcp_title: "Command Injection & Code Execution",
|
|
43
|
+
category: "static",
|
|
44
|
+
file: loc.file,
|
|
45
|
+
line: loc.line,
|
|
46
|
+
column: loc.column,
|
|
47
|
+
evidence: getCallEvidence(call),
|
|
48
|
+
remediation: "Validate JSON.parse output before using in Object.assign/spread. Filter __proto__ and constructor keys.",
|
|
49
|
+
cwe: "CWE-1321",
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// Check for bracket notation with user input: obj[userInput]
|
|
55
|
+
const elementAccess = sf.getDescendantsOfKind(SyntaxKind.ElementAccessExpression);
|
|
56
|
+
for (const ea of elementAccess) {
|
|
57
|
+
const arg = ea.getArgumentExpression();
|
|
58
|
+
if (arg && containsUserInput(arg)) {
|
|
59
|
+
const loc = getLocation(ea);
|
|
60
|
+
counter++;
|
|
61
|
+
findings.push({
|
|
62
|
+
id: `SAST-PROTO-${String(counter).padStart(3, "0")}`,
|
|
63
|
+
title: "Dynamic Property Access with User Input",
|
|
64
|
+
severity: "medium",
|
|
65
|
+
owasp_mcp: "MCP05",
|
|
66
|
+
owasp_mcp_title: "Command Injection & Code Execution",
|
|
67
|
+
category: "static",
|
|
68
|
+
file: loc.file,
|
|
69
|
+
line: loc.line,
|
|
70
|
+
column: loc.column,
|
|
71
|
+
evidence: ea.getText().substring(0, 200),
|
|
72
|
+
remediation: "Validate property names against an allowlist before using bracket notation with user input. Block __proto__, constructor, prototype.",
|
|
73
|
+
cwe: "CWE-1321",
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return findings;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=prototype-pollution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prototype-pollution.js","sourceRoot":"","sources":["../../../src/static/analyzers/prototype-pollution.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"regex-dos.d.ts","sourceRoot":"","sources":["../../../src/static/analyzers/regex-dos.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAWvD,wBAAgB,eAAe,CAAC,WAAW,EAAE,UAAU,EAAE,GAAG,OAAO,EAAE,CAuEpE"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { getLocation, SyntaxKind } from "../ast-engine.js";
|
|
2
|
+
// Patterns that indicate ReDoS vulnerability
|
|
3
|
+
const REDOS_PATTERNS = [
|
|
4
|
+
/\(.*[+*].*\)[+*]/, // Nested quantifiers: (a+)+
|
|
5
|
+
/\(.*\|.*\)[+*]/, // Alternation in quantified group: (a|b)+
|
|
6
|
+
/\([^)]*[+*][^)]*[+*][^)]*\)/, // Multiple quantifiers in group
|
|
7
|
+
/(.)\+\1\+/, // Overlapping quantifiers like a+a+
|
|
8
|
+
];
|
|
9
|
+
export function analyzeRegexDos(sourceFiles) {
|
|
10
|
+
const findings = [];
|
|
11
|
+
let counter = 0;
|
|
12
|
+
for (const sf of sourceFiles) {
|
|
13
|
+
// Check RegExp literals
|
|
14
|
+
const regexLiterals = sf.getDescendantsOfKind(SyntaxKind.RegularExpressionLiteral);
|
|
15
|
+
for (const regex of regexLiterals) {
|
|
16
|
+
const text = regex.getText();
|
|
17
|
+
// Remove the /flags part to get pattern
|
|
18
|
+
const pattern = text.slice(1, text.lastIndexOf("/"));
|
|
19
|
+
for (const redos of REDOS_PATTERNS) {
|
|
20
|
+
if (redos.test(pattern)) {
|
|
21
|
+
const loc = getLocation(regex);
|
|
22
|
+
counter++;
|
|
23
|
+
findings.push({
|
|
24
|
+
id: `SAST-REDOS-${String(counter).padStart(3, "0")}`,
|
|
25
|
+
title: "Potential ReDoS Pattern",
|
|
26
|
+
severity: "medium",
|
|
27
|
+
owasp_mcp: "MCP05",
|
|
28
|
+
owasp_mcp_title: "Command Injection & Code Execution",
|
|
29
|
+
category: "static",
|
|
30
|
+
file: loc.file,
|
|
31
|
+
line: loc.line,
|
|
32
|
+
column: loc.column,
|
|
33
|
+
evidence: `Regex literal with potential catastrophic backtracking: ${text.substring(0, 100)}`,
|
|
34
|
+
remediation: "Refactor regex to avoid nested quantifiers and overlapping alternations. Consider using a regex engine with backtracking limits.",
|
|
35
|
+
cwe: "CWE-1333",
|
|
36
|
+
});
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// Check new RegExp() with string arguments for same patterns
|
|
42
|
+
const newExprs = sf.getDescendantsOfKind(SyntaxKind.NewExpression);
|
|
43
|
+
for (const expr of newExprs) {
|
|
44
|
+
if (expr.getExpression().getText() !== "RegExp")
|
|
45
|
+
continue;
|
|
46
|
+
const args = expr.getArguments();
|
|
47
|
+
if (args.length === 0)
|
|
48
|
+
continue;
|
|
49
|
+
const firstArg = args[0];
|
|
50
|
+
if (firstArg.getKind() === SyntaxKind.StringLiteral) {
|
|
51
|
+
const pattern = firstArg.getText().replace(/^['"]|['"]$/g, "");
|
|
52
|
+
for (const redos of REDOS_PATTERNS) {
|
|
53
|
+
if (redos.test(pattern)) {
|
|
54
|
+
const loc = getLocation(expr);
|
|
55
|
+
counter++;
|
|
56
|
+
findings.push({
|
|
57
|
+
id: `SAST-REDOS-${String(counter).padStart(3, "0")}`,
|
|
58
|
+
title: "Potential ReDoS in new RegExp()",
|
|
59
|
+
severity: "medium",
|
|
60
|
+
owasp_mcp: "MCP05",
|
|
61
|
+
owasp_mcp_title: "Command Injection & Code Execution",
|
|
62
|
+
category: "static",
|
|
63
|
+
file: loc.file,
|
|
64
|
+
line: loc.line,
|
|
65
|
+
column: loc.column,
|
|
66
|
+
evidence: `new RegExp() with potential backtracking: ${expr.getText().substring(0, 100)}`,
|
|
67
|
+
remediation: "Refactor regex pattern to avoid nested quantifiers. Consider using a safe regex library.",
|
|
68
|
+
cwe: "CWE-1333",
|
|
69
|
+
});
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return findings;
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=regex-dos.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"regex-dos.js","sourceRoot":"","sources":["../../../src/static/analyzers/regex-dos.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secret-hardcoded.d.ts","sourceRoot":"","sources":["../../../src/static/analyzers/secret-hardcoded.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAIvD,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,UAAU,EAAE,GAAG,OAAO,EAAE,CAuE5E"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { findStringLiterals, findTemplateExpressions, getLocation } from "../ast-engine.js";
|
|
2
|
+
import { SECRET_PATTERNS } from "../../data/secret-patterns.js";
|
|
3
|
+
export function analyzeHardcodedSecrets(sourceFiles) {
|
|
4
|
+
const findings = [];
|
|
5
|
+
let counter = 0;
|
|
6
|
+
for (const sf of sourceFiles) {
|
|
7
|
+
// Skip test files
|
|
8
|
+
const filePath = sf.getFilePath();
|
|
9
|
+
if (filePath.includes(".test.") || filePath.includes(".spec.") || filePath.includes("__test__"))
|
|
10
|
+
continue;
|
|
11
|
+
// Check string literals
|
|
12
|
+
const strings = findStringLiterals(sf);
|
|
13
|
+
for (const str of strings) {
|
|
14
|
+
const value = str.getLiteralText();
|
|
15
|
+
if (value.length < 8)
|
|
16
|
+
continue; // Skip short strings
|
|
17
|
+
for (const pattern of SECRET_PATTERNS) {
|
|
18
|
+
if (pattern.pattern.test(value)) {
|
|
19
|
+
const loc = getLocation(str);
|
|
20
|
+
counter++;
|
|
21
|
+
// Mask the secret in evidence
|
|
22
|
+
const masked = value.substring(0, 8) + "..." + value.substring(value.length - 4);
|
|
23
|
+
findings.push({
|
|
24
|
+
id: `SAST-SECRET-${String(counter).padStart(3, "0")}`,
|
|
25
|
+
title: `Hardcoded ${pattern.name}`,
|
|
26
|
+
severity: pattern.severity,
|
|
27
|
+
owasp_mcp: "MCP01",
|
|
28
|
+
owasp_mcp_title: "Excessive Privilege & Token Mismanagement",
|
|
29
|
+
category: "static",
|
|
30
|
+
file: loc.file,
|
|
31
|
+
line: loc.line,
|
|
32
|
+
column: loc.column,
|
|
33
|
+
evidence: `${pattern.name} found in string literal: "${masked}"`,
|
|
34
|
+
remediation: "Move secrets to environment variables. Use process.env to read them at runtime. Never commit secrets to source code.",
|
|
35
|
+
cwe: "CWE-798",
|
|
36
|
+
});
|
|
37
|
+
break; // One finding per string
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// Check template literals
|
|
42
|
+
const templates = findTemplateExpressions(sf);
|
|
43
|
+
for (const tmpl of templates) {
|
|
44
|
+
const text = tmpl.getText();
|
|
45
|
+
for (const pattern of SECRET_PATTERNS) {
|
|
46
|
+
if (pattern.pattern.test(text)) {
|
|
47
|
+
const loc = getLocation(tmpl);
|
|
48
|
+
counter++;
|
|
49
|
+
findings.push({
|
|
50
|
+
id: `SAST-SECRET-${String(counter).padStart(3, "0")}`,
|
|
51
|
+
title: `Hardcoded ${pattern.name} in Template Literal`,
|
|
52
|
+
severity: pattern.severity,
|
|
53
|
+
owasp_mcp: "MCP01",
|
|
54
|
+
owasp_mcp_title: "Excessive Privilege & Token Mismanagement",
|
|
55
|
+
category: "static",
|
|
56
|
+
file: loc.file,
|
|
57
|
+
line: loc.line,
|
|
58
|
+
column: loc.column,
|
|
59
|
+
evidence: `${pattern.name} found in template literal`,
|
|
60
|
+
remediation: "Move secrets to environment variables. Use process.env to read them at runtime.",
|
|
61
|
+
cwe: "CWE-798",
|
|
62
|
+
});
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return findings;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=secret-hardcoded.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secret-hardcoded.js","sourceRoot":"","sources":["../../../src/static/analyzers/secret-hardcoded.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,WAAW,EAAoB,MAAM,kBAAkB,CAAC;AAC9G,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAEhE,MAAM,UAAU,uBAAuB,CAAC,WAAyB;IAC/D,MAAM,QAAQ,GAAc,EAAE,CAAC;IAC/B,IAAI,OAAO,GAAG,CAAC,CAAC;IAEhB,KAAK,MAAM,EAAE,IAAI,WAAW,EAAE,CAAC;QAC7B,kBAAkB;QAClB,MAAM,QAAQ,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC;QAClC,IAAI,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC;YAAE,SAAS;QAE1G,wBAAwB;QACxB,MAAM,OAAO,GAAG,kBAAkB,CAAC,EAAE,CAAC,CAAC;QACvC,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;YAC1B,MAAM,KAAK,GAAG,GAAG,CAAC,cAAc,EAAE,CAAC;YACnC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;gBAAE,SAAS,CAAC,qBAAqB;YAErD,KAAK,MAAM,OAAO,IAAI,eAAe,EAAE,CAAC;gBACtC,IAAI,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;oBAChC,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;oBAC7B,OAAO,EAAE,CAAC;oBAEV,8BAA8B;oBAC9B,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK,GAAG,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;oBAEjF,QAAQ,CAAC,IAAI,CAAC;wBACZ,EAAE,EAAE,eAAe,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;wBACrD,KAAK,EAAE,aAAa,OAAO,CAAC,IAAI,EAAE;wBAClC,QAAQ,EAAE,OAAO,CAAC,QAAQ;wBAC1B,SAAS,EAAE,OAAO;wBAClB,eAAe,EAAE,2CAA2C;wBAC5D,QAAQ,EAAE,QAAQ;wBAClB,IAAI,EAAE,GAAG,CAAC,IAAI;wBACd,IAAI,EAAE,GAAG,CAAC,IAAI;wBACd,MAAM,EAAE,GAAG,CAAC,MAAM;wBAClB,QAAQ,EAAE,GAAG,OAAO,CAAC,IAAI,8BAA8B,MAAM,GAAG;wBAChE,WAAW,EAAE,sHAAsH;wBACnI,GAAG,EAAE,SAAS;qBACf,CAAC,CAAC;oBACH,MAAM,CAAC,yBAAyB;gBAClC,CAAC;YACH,CAAC;QACH,CAAC;QAED,0BAA0B;QAC1B,MAAM,SAAS,GAAG,uBAAuB,CAAC,EAAE,CAAC,CAAC;QAC9C,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;YAC7B,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;YAC5B,KAAK,MAAM,OAAO,IAAI,eAAe,EAAE,CAAC;gBACtC,IAAI,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC/B,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;oBAC9B,OAAO,EAAE,CAAC;oBACV,QAAQ,CAAC,IAAI,CAAC;wBACZ,EAAE,EAAE,eAAe,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;wBACrD,KAAK,EAAE,aAAa,OAAO,CAAC,IAAI,sBAAsB;wBACtD,QAAQ,EAAE,OAAO,CAAC,QAAQ;wBAC1B,SAAS,EAAE,OAAO;wBAClB,eAAe,EAAE,2CAA2C;wBAC5D,QAAQ,EAAE,QAAQ;wBAClB,IAAI,EAAE,GAAG,CAAC,IAAI;wBACd,IAAI,EAAE,GAAG,CAAC,IAAI;wBACd,MAAM,EAAE,GAAG,CAAC,MAAM;wBAClB,QAAQ,EAAE,GAAG,OAAO,CAAC,IAAI,4BAA4B;wBACrD,WAAW,EAAE,iFAAiF;wBAC9F,GAAG,EAAE,SAAS;qBACf,CAAC,CAAC;oBACH,MAAM;gBACR,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssrf.d.ts","sourceRoot":"","sources":["../../../src/static/analyzers/ssrf.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAMvD,wBAAgB,WAAW,CAAC,WAAW,EAAE,UAAU,EAAE,GAAG,OAAO,EAAE,CAqChE"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { findCallExpressions, getCallName, getLocation, containsUserInput } from "../ast-engine.js";
|
|
2
|
+
import { getCallEvidence } from "../taint-tracker.js";
|
|
3
|
+
const SSRF_NAMES = new Set(["fetch", "get", "post", "put", "delete", "patch", "request"]);
|
|
4
|
+
export function analyzeSsrf(sourceFiles) {
|
|
5
|
+
const findings = [];
|
|
6
|
+
let counter = 0;
|
|
7
|
+
for (const sf of sourceFiles) {
|
|
8
|
+
const calls = findCallExpressions(sf);
|
|
9
|
+
for (const call of calls) {
|
|
10
|
+
const name = getCallName(call);
|
|
11
|
+
if (!SSRF_NAMES.has(name))
|
|
12
|
+
continue;
|
|
13
|
+
const args = call.getArguments();
|
|
14
|
+
if (args.length === 0)
|
|
15
|
+
continue;
|
|
16
|
+
const firstArg = args[0];
|
|
17
|
+
if (!containsUserInput(firstArg))
|
|
18
|
+
continue;
|
|
19
|
+
const loc = getLocation(call);
|
|
20
|
+
counter++;
|
|
21
|
+
findings.push({
|
|
22
|
+
id: `SAST-SSRF-${String(counter).padStart(3, "0")}`,
|
|
23
|
+
title: `Potential SSRF via ${name}()`,
|
|
24
|
+
severity: "high",
|
|
25
|
+
owasp_mcp: "MCP05",
|
|
26
|
+
owasp_mcp_title: "Command Injection & Code Execution",
|
|
27
|
+
category: "static",
|
|
28
|
+
file: loc.file,
|
|
29
|
+
line: loc.line,
|
|
30
|
+
column: loc.column,
|
|
31
|
+
evidence: getCallEvidence(call),
|
|
32
|
+
remediation: "Validate and allowlist URLs before making requests. Never pass user-controlled input directly as request URLs.",
|
|
33
|
+
cwe: "CWE-918",
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return findings;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=ssrf.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssrf.js","sourceRoot":"","sources":["../../../src/static/analyzers/ssrf.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACpG,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEtD,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC;AAE1F,MAAM,UAAU,WAAW,CAAC,WAAyB;IACnD,MAAM,QAAQ,GAAc,EAAE,CAAC;IAC/B,IAAI,OAAO,GAAG,CAAC,CAAC;IAEhB,KAAK,MAAM,EAAE,IAAI,WAAW,EAAE,CAAC;QAC7B,MAAM,KAAK,GAAG,mBAAmB,CAAC,EAAE,CAAC,CAAC;QACtC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;YAC/B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC;gBAAE,SAAS;YAEpC,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;YACjC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;gBAAE,SAAS;YAEhC,MAAM,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;YACzB,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC;gBAAE,SAAS;YAE3C,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;YAC9B,OAAO,EAAE,CAAC;YAEV,QAAQ,CAAC,IAAI,CAAC;gBACZ,EAAE,EAAE,aAAa,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;gBACnD,KAAK,EAAE,sBAAsB,IAAI,IAAI;gBACrC,QAAQ,EAAE,MAAM;gBAChB,SAAS,EAAE,OAAO;gBAClB,eAAe,EAAE,oCAAoC;gBACrD,QAAQ,EAAE,QAAQ;gBAClB,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,QAAQ,EAAE,eAAe,CAAC,IAAI,CAAC;gBAC/B,WAAW,EAAE,gHAAgH;gBAC7H,GAAG,EAAE,SAAS;aACf,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unsafe-regex.d.ts","sourceRoot":"","sources":["../../../src/static/analyzers/unsafe-regex.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAGvD,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,UAAU,EAAE,GAAG,OAAO,EAAE,CAoCvE"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { findNewRegExpCalls, getLocation, containsUserInput } from "../ast-engine.js";
|
|
2
|
+
export function analyzeUnsafeRegex(sourceFiles) {
|
|
3
|
+
const findings = [];
|
|
4
|
+
let counter = 0;
|
|
5
|
+
for (const sf of sourceFiles) {
|
|
6
|
+
const regexpCalls = findNewRegExpCalls(sf);
|
|
7
|
+
for (const call of regexpCalls) {
|
|
8
|
+
const args = call.getChildrenOfKind(18); // SyntaxList children
|
|
9
|
+
// Get first argument
|
|
10
|
+
const firstArg = call.getChildren().find(c => {
|
|
11
|
+
const kind = c.getKindName();
|
|
12
|
+
return kind === "SyntaxList";
|
|
13
|
+
});
|
|
14
|
+
if (containsUserInput(call)) {
|
|
15
|
+
const loc = getLocation(call);
|
|
16
|
+
counter++;
|
|
17
|
+
findings.push({
|
|
18
|
+
id: `SAST-REGEX-${String(counter).padStart(3, "0")}`,
|
|
19
|
+
title: "User Input in new RegExp()",
|
|
20
|
+
severity: "high",
|
|
21
|
+
owasp_mcp: "MCP05",
|
|
22
|
+
owasp_mcp_title: "Command Injection & Code Execution",
|
|
23
|
+
category: "static",
|
|
24
|
+
file: loc.file,
|
|
25
|
+
line: loc.line,
|
|
26
|
+
column: loc.column,
|
|
27
|
+
evidence: call.getText().substring(0, 200),
|
|
28
|
+
remediation: "Escape user input before passing to new RegExp(). Use a function like escapeRegExp(str) { return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'); }",
|
|
29
|
+
cwe: "CWE-185",
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return findings;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=unsafe-regex.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unsafe-regex.js","sourceRoot":"","sources":["../../../src/static/analyzers/unsafe-regex.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAEtF,MAAM,UAAU,kBAAkB,CAAC,WAAyB;IAC1D,MAAM,QAAQ,GAAc,EAAE,CAAC;IAC/B,IAAI,OAAO,GAAG,CAAC,CAAC;IAEhB,KAAK,MAAM,EAAE,IAAI,WAAW,EAAE,CAAC;QAC7B,MAAM,WAAW,GAAG,kBAAkB,CAAC,EAAE,CAAC,CAAC;QAC3C,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;YAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC,CAAC,sBAAsB;YAC/D,qBAAqB;YACrB,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;gBAC3C,MAAM,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;gBAC7B,OAAO,IAAI,KAAK,YAAY,CAAC;YAC/B,CAAC,CAAC,CAAC;YAEH,IAAI,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC5B,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;gBAC9B,OAAO,EAAE,CAAC;gBACV,QAAQ,CAAC,IAAI,CAAC;oBACZ,EAAE,EAAE,cAAc,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;oBACpD,KAAK,EAAE,4BAA4B;oBACnC,QAAQ,EAAE,MAAM;oBAChB,SAAS,EAAE,OAAO;oBAClB,eAAe,EAAE,oCAAoC;oBACrD,QAAQ,EAAE,QAAQ;oBAClB,IAAI,EAAE,GAAG,CAAC,IAAI;oBACd,IAAI,EAAE,GAAG,CAAC,IAAI;oBACd,MAAM,EAAE,GAAG,CAAC,MAAM;oBAClB,QAAQ,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC;oBAC1C,WAAW,EAAE,qJAAqJ;oBAClK,GAAG,EAAE,SAAS;iBACf,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Project, SourceFile, SyntaxKind, Node, CallExpression, StringLiteral } from "ts-morph";
|
|
2
|
+
export interface AstProject {
|
|
3
|
+
project: Project;
|
|
4
|
+
sourceFiles: SourceFile[];
|
|
5
|
+
rootDir: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function initProject(path: string, tsconfigPath?: string): AstProject;
|
|
8
|
+
export declare function findCallExpressions(sourceFile: SourceFile): CallExpression[];
|
|
9
|
+
export declare function getCallName(call: CallExpression): string;
|
|
10
|
+
export declare function getQualifiedCallName(call: CallExpression): string;
|
|
11
|
+
export declare function containsUserInput(node: Node): boolean;
|
|
12
|
+
export declare function getLocation(node: Node): {
|
|
13
|
+
file: string;
|
|
14
|
+
line: number;
|
|
15
|
+
column: number;
|
|
16
|
+
};
|
|
17
|
+
export declare function findStringLiterals(sourceFile: SourceFile): StringLiteral[];
|
|
18
|
+
export declare function findTemplateExpressions(sourceFile: SourceFile): Node[];
|
|
19
|
+
export declare function hasShellTrue(call: CallExpression): boolean;
|
|
20
|
+
export declare function findNewRegExpCalls(sourceFile: SourceFile): Node[];
|
|
21
|
+
export { SyntaxKind, Node, type SourceFile, type CallExpression };
|
|
22
|
+
//# sourceMappingURL=ast-engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ast-engine.d.ts","sourceRoot":"","sources":["../../src/static/ast-engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE,cAAc,EAAE,aAAa,EAA4D,MAAM,UAAU,CAAC;AAG1J,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,UAAU,CAoD3E;AAGD,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,UAAU,GAAG,cAAc,EAAE,CAE5E;AAGD,wBAAgB,WAAW,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAcxD;AAGD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAejE;AAGD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CA8BrD;AAGD,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAStF;AAGD,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,UAAU,GAAG,aAAa,EAAE,CAE1E;AAGD,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,UAAU,GAAG,IAAI,EAAE,CAKtE;AAGD,wBAAgB,YAAY,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAO1D;AAGD,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,UAAU,GAAG,IAAI,EAAE,CAYjE;AAED,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,UAAU,EAAE,KAAK,cAAc,EAAE,CAAC"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { Project, SyntaxKind, Node } from "ts-morph";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
export function initProject(path, tsconfigPath) {
|
|
4
|
+
const rootDir = resolve(path);
|
|
5
|
+
const project = new Project({
|
|
6
|
+
compilerOptions: {
|
|
7
|
+
allowJs: true,
|
|
8
|
+
checkJs: false,
|
|
9
|
+
noEmit: true,
|
|
10
|
+
skipLibCheck: true,
|
|
11
|
+
target: 99, // ESNext
|
|
12
|
+
module: 99, // ESNext
|
|
13
|
+
},
|
|
14
|
+
skipAddingFilesFromTsConfig: true,
|
|
15
|
+
skipFileDependencyResolution: true,
|
|
16
|
+
});
|
|
17
|
+
// Discover and add source files
|
|
18
|
+
const globs = [
|
|
19
|
+
`${rootDir}/**/*.ts`,
|
|
20
|
+
`${rootDir}/**/*.js`,
|
|
21
|
+
`${rootDir}/**/*.mts`,
|
|
22
|
+
`${rootDir}/**/*.mjs`,
|
|
23
|
+
];
|
|
24
|
+
const excludeGlobs = [
|
|
25
|
+
`${rootDir}/node_modules/**`,
|
|
26
|
+
`${rootDir}/dist/**`,
|
|
27
|
+
`${rootDir}/.git/**`,
|
|
28
|
+
`${rootDir}/**/*.d.ts`,
|
|
29
|
+
];
|
|
30
|
+
project.addSourceFilesAtPaths(globs);
|
|
31
|
+
// Remove excluded files
|
|
32
|
+
for (const sf of project.getSourceFiles()) {
|
|
33
|
+
const fp = sf.getFilePath();
|
|
34
|
+
if (excludeGlobs.some(g => {
|
|
35
|
+
const base = g.replace("/**", "");
|
|
36
|
+
return fp.includes(base.replace(`${rootDir}/`, ""));
|
|
37
|
+
})) {
|
|
38
|
+
// Simplistic: check if path contains node_modules, dist, .git, or ends with .d.ts
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const sourceFiles = project.getSourceFiles().filter(sf => {
|
|
42
|
+
const fp = sf.getFilePath();
|
|
43
|
+
return !fp.includes("/node_modules/") &&
|
|
44
|
+
!fp.includes("/dist/") &&
|
|
45
|
+
!fp.includes("/.git/") &&
|
|
46
|
+
!fp.endsWith(".d.ts");
|
|
47
|
+
});
|
|
48
|
+
return { project, sourceFiles, rootDir };
|
|
49
|
+
}
|
|
50
|
+
// Helper: find all call expressions in a source file
|
|
51
|
+
export function findCallExpressions(sourceFile) {
|
|
52
|
+
return sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);
|
|
53
|
+
}
|
|
54
|
+
// Helper: get the function/method name from a call expression
|
|
55
|
+
export function getCallName(call) {
|
|
56
|
+
const expr = call.getExpression();
|
|
57
|
+
// Simple call: exec(...)
|
|
58
|
+
if (Node.isIdentifier(expr)) {
|
|
59
|
+
return expr.getText();
|
|
60
|
+
}
|
|
61
|
+
// Property access: child_process.exec(...), fs.readFile(...)
|
|
62
|
+
if (Node.isPropertyAccessExpression(expr)) {
|
|
63
|
+
return expr.getName();
|
|
64
|
+
}
|
|
65
|
+
return expr.getText();
|
|
66
|
+
}
|
|
67
|
+
// Helper: get the full qualified call name like "child_process.exec" or "fs.readFile"
|
|
68
|
+
export function getQualifiedCallName(call) {
|
|
69
|
+
const expr = call.getExpression();
|
|
70
|
+
if (Node.isPropertyAccessExpression(expr)) {
|
|
71
|
+
const obj = expr.getExpression();
|
|
72
|
+
if (Node.isIdentifier(obj)) {
|
|
73
|
+
return `${obj.getText()}.${expr.getName()}`;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (Node.isIdentifier(expr)) {
|
|
77
|
+
return expr.getText();
|
|
78
|
+
}
|
|
79
|
+
return expr.getText();
|
|
80
|
+
}
|
|
81
|
+
// Helper: check if an expression contains user input (function params, args.*, etc)
|
|
82
|
+
export function containsUserInput(node) {
|
|
83
|
+
const text = node.getText();
|
|
84
|
+
// Check for common user input patterns
|
|
85
|
+
const userInputPatterns = [
|
|
86
|
+
/\bargs\b/, // MCP tool args
|
|
87
|
+
/\breq\.query\b/, // Express query
|
|
88
|
+
/\breq\.params\b/, // Express params
|
|
89
|
+
/\breq\.body\b/, // Express body
|
|
90
|
+
/\breq\.headers\b/, // Express headers
|
|
91
|
+
/\bparams\b/, // Generic params
|
|
92
|
+
/\binput\b/, // Generic input
|
|
93
|
+
/\buserInput\b/, // Generic userInput
|
|
94
|
+
];
|
|
95
|
+
if (userInputPatterns.some(p => p.test(text)))
|
|
96
|
+
return true;
|
|
97
|
+
// Check for template literals with interpolations
|
|
98
|
+
if (node.getKind() === SyntaxKind.TemplateExpression)
|
|
99
|
+
return true;
|
|
100
|
+
// Check for identifiers that trace to function parameters
|
|
101
|
+
const identifiers = node.getDescendantsOfKind(SyntaxKind.Identifier);
|
|
102
|
+
for (const id of identifiers) {
|
|
103
|
+
const name = id.getText();
|
|
104
|
+
if (["args", "params", "input", "query", "body", "userInput", "data", "payload"].includes(name)) {
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
// Helper: get location info
|
|
111
|
+
export function getLocation(node) {
|
|
112
|
+
const sf = node.getSourceFile();
|
|
113
|
+
const start = node.getStart();
|
|
114
|
+
const { line, column } = sf.getLineAndColumnAtPos(start);
|
|
115
|
+
return {
|
|
116
|
+
file: sf.getFilePath(),
|
|
117
|
+
line,
|
|
118
|
+
column,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
// Helper: get all string literals in a file
|
|
122
|
+
export function findStringLiterals(sourceFile) {
|
|
123
|
+
return sourceFile.getDescendantsOfKind(SyntaxKind.StringLiteral);
|
|
124
|
+
}
|
|
125
|
+
// Helper: get all template expressions (template literals with interpolation)
|
|
126
|
+
export function findTemplateExpressions(sourceFile) {
|
|
127
|
+
return [
|
|
128
|
+
...sourceFile.getDescendantsOfKind(SyntaxKind.TemplateExpression),
|
|
129
|
+
...sourceFile.getDescendantsOfKind(SyntaxKind.NoSubstitutionTemplateLiteral),
|
|
130
|
+
];
|
|
131
|
+
}
|
|
132
|
+
// Helper: check if a call has shell:true in options
|
|
133
|
+
export function hasShellTrue(call) {
|
|
134
|
+
const args = call.getArguments();
|
|
135
|
+
for (const arg of args) {
|
|
136
|
+
const text = arg.getText();
|
|
137
|
+
if (/shell\s*:\s*true/.test(text))
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
// Helper: find new RegExp() calls
|
|
143
|
+
export function findNewRegExpCalls(sourceFile) {
|
|
144
|
+
const results = [];
|
|
145
|
+
// new RegExp(...)
|
|
146
|
+
const newExprs = sourceFile.getDescendantsOfKind(SyntaxKind.NewExpression);
|
|
147
|
+
for (const expr of newExprs) {
|
|
148
|
+
if (expr.getExpression().getText() === "RegExp") {
|
|
149
|
+
results.push(expr);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return results;
|
|
153
|
+
}
|
|
154
|
+
export { SyntaxKind, Node };
|
|
155
|
+
//# sourceMappingURL=ast-engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ast-engine.js","sourceRoot":"","sources":["../../src/static/ast-engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/static/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAqHjD,eAAO,MAAM,WAAW,EAAE,OAAO,EAyDhC,CAAC"}
|