@securecode-ai/mcp 0.1.0 → 0.2.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 (49) hide show
  1. package/README.md +5 -3
  2. package/dist/api/client.d.ts +4 -0
  3. package/dist/api/client.js +49 -0
  4. package/dist/api/client.js.map +1 -1
  5. package/dist/api/types.d.ts +40 -0
  6. package/dist/index.js +64 -7
  7. package/dist/index.js.map +1 -1
  8. package/dist/poc/httpPocExecutor.d.ts +20 -0
  9. package/dist/poc/httpPocExecutor.js +247 -0
  10. package/dist/poc/httpPocExecutor.js.map +1 -0
  11. package/dist/poc/lightpandaExecutor.d.ts +41 -0
  12. package/dist/poc/lightpandaExecutor.js +263 -0
  13. package/dist/poc/lightpandaExecutor.js.map +1 -0
  14. package/dist/poc/pocExecutor.d.ts +46 -0
  15. package/dist/poc/pocExecutor.js +74 -0
  16. package/dist/poc/pocExecutor.js.map +1 -0
  17. package/dist/poc/pocRouter.d.ts +20 -0
  18. package/dist/poc/pocRouter.js +40 -0
  19. package/dist/poc/pocRouter.js.map +1 -0
  20. package/dist/poc/pocTypes.d.ts +54 -0
  21. package/dist/poc/pocTypes.js +16 -0
  22. package/dist/poc/pocTypes.js.map +1 -0
  23. package/dist/project-map/fixTester.d.ts +55 -0
  24. package/dist/project-map/fixTester.js +338 -0
  25. package/dist/project-map/fixTester.js.map +1 -0
  26. package/dist/project-map/guardEvaluator.d.ts +40 -0
  27. package/dist/project-map/guardEvaluator.js +216 -0
  28. package/dist/project-map/guardEvaluator.js.map +1 -0
  29. package/dist/project-map/guardPatterns.d.ts +43 -0
  30. package/dist/project-map/guardPatterns.js +173 -0
  31. package/dist/project-map/guardPatterns.js.map +1 -0
  32. package/dist/project-map/sanitizers.d.ts +34 -0
  33. package/dist/project-map/sanitizers.js +76 -0
  34. package/dist/project-map/sanitizers.js.map +1 -0
  35. package/dist/project-map/sinkFinder.d.ts +48 -0
  36. package/dist/project-map/sinkFinder.js +340 -0
  37. package/dist/project-map/sinkFinder.js.map +1 -0
  38. package/dist/project-map/sinkRegistry.d.ts +60 -0
  39. package/dist/project-map/sinkRegistry.js +246 -0
  40. package/dist/project-map/sinkRegistry.js.map +1 -0
  41. package/dist/project-map/taintSources.d.ts +30 -0
  42. package/dist/project-map/taintSources.js +77 -0
  43. package/dist/project-map/taintSources.js.map +1 -0
  44. package/dist/project-map/taintTracker.d.ts +42 -0
  45. package/dist/project-map/taintTracker.js +571 -0
  46. package/dist/project-map/taintTracker.js.map +1 -0
  47. package/dist/tools/scan.js +44 -0
  48. package/dist/tools/scan.js.map +1 -1
  49. package/package.json +1 -1
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Phase E — guard pattern library.
3
+ *
4
+ * Maps guard types to the attacks they do and don't stop. The guard
5
+ * evaluator uses this to answer "does this guard actually defend against
6
+ * this attack?" — a question the Juror would otherwise have to guess at.
7
+ *
8
+ * The patterns are conservative: when we can't determine effectiveness, we
9
+ * return `unknown` rather than `effective` (a false "effective" is far more
10
+ * dangerous than a false "unknown" — it would let the Juror mark a real
11
+ * vulnerability as SAFE).
12
+ */
13
+ /** Attack types that guards are evaluated against (matches canonical vuln types). */
14
+ export type AttackType = 'sql_injection' | 'nosql_injection' | 'command_injection' | 'xss' | 'ssrf' | 'path_traversal' | 'open_redirect' | 'prototype_pollution' | 'insecure_deserialization' | 'broken_access_control';
15
+ /** Guard types we can identify and evaluate. */
16
+ export type GuardType = 'sanitizer-numeric' | 'sanitizer-html' | 'sanitizer-url' | 'parameterized-query' | 'allowlist-literal' | 'allowlist-dynamic' | 'auth-jwt-verify' | 'auth-jwt-verify-noalg' | 'auth-session' | 'auth-api-key' | 'auth-none' | 'rate-limit' | 'helmet' | 'cors-strict' | 'cors-permissive' | 'validator' | 'unknown';
17
+ export interface GuardEvaluation {
18
+ /** The guard's display name. */
19
+ guardName: string;
20
+ /** Type of guard identified. */
21
+ guardType: GuardType;
22
+ /** The attack type being evaluated against. */
23
+ attackType: AttackType;
24
+ /** Does this guard stop this attack? */
25
+ effective: boolean;
26
+ /** Why it is or isn't effective. */
27
+ reason: string;
28
+ /** Example bypass when not effective. */
29
+ bypassExample?: string;
30
+ }
31
+ /**
32
+ * Pattern: which GuardType stops which AttackType.
33
+ *
34
+ * `true` = effective, `false` = NOT effective, `undefined` = unknown.
35
+ * When unknown, the evaluator returns `effective: false` with a reason
36
+ * explaining the guard was detected but its effectiveness against this
37
+ * attack is not determinable.
38
+ */
39
+ export declare const GUARD_EFFECTIVENESS: Record<GuardType, Partial<Record<AttackType, boolean>>>;
40
+ /** Bypass examples for known ineffective guard×attack pairs. */
41
+ export declare const GUARD_BYPASS_EXAMPLES: Partial<Record<GuardType, Partial<Record<AttackType, string>>>>;
42
+ /** Reasons explaining why a guard is effective. */
43
+ export declare const GUARD_EFFECTIVE_REASONS: Partial<Record<GuardType, Partial<Record<AttackType, string>>>>;
@@ -0,0 +1,173 @@
1
+ "use strict";
2
+ /**
3
+ * Phase E — guard pattern library.
4
+ *
5
+ * Maps guard types to the attacks they do and don't stop. The guard
6
+ * evaluator uses this to answer "does this guard actually defend against
7
+ * this attack?" — a question the Juror would otherwise have to guess at.
8
+ *
9
+ * The patterns are conservative: when we can't determine effectiveness, we
10
+ * return `unknown` rather than `effective` (a false "effective" is far more
11
+ * dangerous than a false "unknown" — it would let the Juror mark a real
12
+ * vulnerability as SAFE).
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.GUARD_EFFECTIVE_REASONS = exports.GUARD_BYPASS_EXAMPLES = exports.GUARD_EFFECTIVENESS = void 0;
16
+ /**
17
+ * Pattern: which GuardType stops which AttackType.
18
+ *
19
+ * `true` = effective, `false` = NOT effective, `undefined` = unknown.
20
+ * When unknown, the evaluator returns `effective: false` with a reason
21
+ * explaining the guard was detected but its effectiveness against this
22
+ * attack is not determinable.
23
+ */
24
+ exports.GUARD_EFFECTIVENESS = {
25
+ 'sanitizer-numeric': {
26
+ sql_injection: true, // numbers can't carry SQL syntax
27
+ nosql_injection: true, // numbers can't carry NoSQL operators
28
+ command_injection: true, // numbers can't carry shell metachars
29
+ xss: true, // numbers can't carry script tags
30
+ open_redirect: true, // numbers can't be URLs
31
+ path_traversal: true, // numbers can't carry ../
32
+ ssrf: true, // numbers can't be URLs
33
+ prototype_pollution: true, // numbers can't carry __proto__
34
+ },
35
+ 'sanitizer-html': {
36
+ xss: true, // HTML escaping stops XSS
37
+ sql_injection: false, // HTML escaping does NOT stop SQLi
38
+ command_injection: false,
39
+ open_redirect: false,
40
+ path_traversal: false,
41
+ ssrf: false,
42
+ prototype_pollution: false,
43
+ },
44
+ 'sanitizer-url': {
45
+ open_redirect: true, // URL encoding stops redirect injection
46
+ xss: false, // URL encoding does NOT stop XSS
47
+ sql_injection: false,
48
+ command_injection: false,
49
+ ssrf: true, // URL encoding limits SSRF target manipulation
50
+ path_traversal: false,
51
+ },
52
+ 'parameterized-query': {
53
+ sql_injection: true, // parameterized queries stop SQLi
54
+ nosql_injection: false,
55
+ command_injection: false,
56
+ xss: false,
57
+ },
58
+ 'allowlist-literal': {
59
+ sql_injection: true,
60
+ nosql_injection: true,
61
+ command_injection: true,
62
+ xss: true,
63
+ open_redirect: true,
64
+ path_traversal: true,
65
+ ssrf: true,
66
+ prototype_pollution: true,
67
+ },
68
+ 'allowlist-dynamic': {
69
+ // An allowlist with a user-controlled key is NOT effective against anything
70
+ sql_injection: false,
71
+ nosql_injection: false,
72
+ command_injection: false,
73
+ xss: false,
74
+ open_redirect: false,
75
+ path_traversal: false,
76
+ ssrf: false,
77
+ },
78
+ 'auth-jwt-verify': {
79
+ broken_access_control: true, // verified JWT = authenticated
80
+ },
81
+ 'auth-jwt-verify-noalg': {
82
+ broken_access_control: false, // algorithm confusion bypass
83
+ },
84
+ 'auth-session': {
85
+ broken_access_control: true,
86
+ },
87
+ 'auth-api-key': {
88
+ broken_access_control: true,
89
+ },
90
+ 'auth-none': {
91
+ broken_access_control: false,
92
+ },
93
+ 'rate-limit': {
94
+ // Rate limiting stops brute force but not the vuln types in our taxonomy
95
+ broken_access_control: false,
96
+ },
97
+ 'helmet': {
98
+ xss: false, // helmet sets headers, doesn't sanitize output
99
+ ssrf: false,
100
+ },
101
+ 'cors-strict': {
102
+ // CORS strict doesn't stop any server-side vuln
103
+ },
104
+ 'cors-permissive': {
105
+ broken_access_control: false,
106
+ },
107
+ 'validator': {
108
+ // Schema validation (zod/joi/pydantic) is effective when the schema
109
+ // constrains the type (e.g. z.number() stops SQLi). Without seeing
110
+ // the schema, we can't say — return unknown (false + reason).
111
+ sql_injection: false,
112
+ xss: false,
113
+ },
114
+ 'unknown': {},
115
+ };
116
+ /** Bypass examples for known ineffective guard×attack pairs. */
117
+ exports.GUARD_BYPASS_EXAMPLES = {
118
+ 'sanitizer-html': {
119
+ sql_injection: "escapeHtml doesn't stop SQLi: q' OR 1=1-- is valid HTML",
120
+ command_injection: "escapeHtml doesn't stop cmd injection: ; cat /etc/passwd",
121
+ },
122
+ 'sanitizer-url': {
123
+ xss: "encodeURIComponent doesn't stop XSS: <script> stays as %3Cscript%3E (decodes in HTML)",
124
+ },
125
+ 'sanitizer-numeric': {
126
+ insecure_deserialization: "parseInt doesn't validate serialized objects",
127
+ },
128
+ 'auth-jwt-verify-noalg': {
129
+ broken_access_control: "Algorithm confusion: sign with HS256 using the public RSA key as the secret",
130
+ },
131
+ 'allowlist-dynamic': {
132
+ sql_injection: "User-controlled allowlist key: attacker sets key to their payload",
133
+ xss: "User-controlled allowlist key: attacker sets key to <script>",
134
+ },
135
+ 'rate-limit': {
136
+ broken_access_control: "Rate limiting slows brute force but doesn't stop auth bypass",
137
+ },
138
+ 'helmet': {
139
+ xss: "helmet sets CSP/X-Frame-Options but doesn't sanitize response body content",
140
+ },
141
+ 'cors-permissive': {
142
+ broken_access_control: "CORS origin:'*' allows any origin to read responses",
143
+ },
144
+ 'validator': {
145
+ sql_injection: "Schema validation only stops SQLi if the schema enforces numeric/enum type",
146
+ xss: "Schema validation only stops XSS if the schema enforces no HTML or sanitizes",
147
+ },
148
+ };
149
+ /** Reasons explaining why a guard is effective. */
150
+ exports.GUARD_EFFECTIVE_REASONS = {
151
+ 'sanitizer-numeric': {
152
+ sql_injection: 'parseInt/Number produces a numeric value — no SQL syntax can survive',
153
+ xss: 'parseInt/Number produces a numeric value — no script tags can survive',
154
+ command_injection: 'parseInt/Number produces a numeric value — no shell metacharacters',
155
+ },
156
+ 'sanitizer-html': {
157
+ xss: 'HTML escaping escapes <, >, ", \', & — prevents script injection',
158
+ },
159
+ 'parameterized-query': {
160
+ sql_injection: 'Parameterized queries separate code from data — injection impossible',
161
+ },
162
+ 'allowlist-literal': {
163
+ sql_injection: 'Literal allowlist rejects any value not in the set',
164
+ xss: 'Literal allowlist rejects any value not in the set',
165
+ },
166
+ 'auth-jwt-verify': {
167
+ broken_access_control: 'jwt.verify with algorithm pinning rejects forged tokens',
168
+ },
169
+ 'auth-session': {
170
+ broken_access_control: 'Session check rejects unauthenticated requests',
171
+ },
172
+ };
173
+ //# sourceMappingURL=guardPatterns.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guardPatterns.js","sourceRoot":"","sources":["../../src/project-map/guardPatterns.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Phase C — sanitizer registry.
3
+ *
4
+ * Functions that remove taint from data. When the taint tracker encounters
5
+ * a call to a sanitizer, the result is NOT tainted (the sanitizer removes
6
+ * the taint). Note: `String()` alone does NOT remove taint — it's a type
7
+ * coercion, not a sanitizer.
8
+ */
9
+ import type { SinkLanguage } from './sinkRegistry';
10
+ export interface SanitizerDef {
11
+ /** Method name: 'parseInt', 'escape', 'sanitize', etc. */
12
+ method: string;
13
+ /** Optional receiver: 'DOMPurify' for DOMPurify.sanitize. */
14
+ receiver?: string;
15
+ languages: SinkLanguage[];
16
+ }
17
+ /**
18
+ * Known sanitizers. A call to any of these with a tainted argument produces
19
+ * a non-tainted result.
20
+ *
21
+ * Type coercions that reject non-numeric input (parseInt, parseFloat, Number)
22
+ * ARE sanitizers for SQL injection — the result is always a number.
23
+ * `String()` is NOT a sanitizer — it accepts anything.
24
+ */
25
+ export declare const SANITIZERS: SanitizerDef[];
26
+ /**
27
+ * Check if a call expression is a sanitizer call.
28
+ * Returns the sanitizer name, or null if not a sanitizer.
29
+ *
30
+ * @param method the method name from callParts
31
+ * @param receiver the base identifier from callParts (or null for bare calls)
32
+ * @param language the source language
33
+ */
34
+ export declare function matchSanitizer(method: string, receiver: string | null, language: SinkLanguage): string | null;
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ /**
3
+ * Phase C — sanitizer registry.
4
+ *
5
+ * Functions that remove taint from data. When the taint tracker encounters
6
+ * a call to a sanitizer, the result is NOT tainted (the sanitizer removes
7
+ * the taint). Note: `String()` alone does NOT remove taint — it's a type
8
+ * coercion, not a sanitizer.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.SANITIZERS = void 0;
12
+ exports.matchSanitizer = matchSanitizer;
13
+ /**
14
+ * Known sanitizers. A call to any of these with a tainted argument produces
15
+ * a non-tainted result.
16
+ *
17
+ * Type coercions that reject non-numeric input (parseInt, parseFloat, Number)
18
+ * ARE sanitizers for SQL injection — the result is always a number.
19
+ * `String()` is NOT a sanitizer — it accepts anything.
20
+ */
21
+ exports.SANITIZERS = [
22
+ // ── JS/TS — type coercions that reject invalid input ─────────────────
23
+ { method: 'parseInt', languages: ['javascript', 'typescript', 'tsx'] },
24
+ { method: 'parseFloat', languages: ['javascript', 'typescript', 'tsx'] },
25
+ { method: 'Number', languages: ['javascript', 'typescript', 'tsx'] },
26
+ { method: 'Boolean', languages: ['javascript', 'typescript', 'tsx'] },
27
+ // ── JS/TS — encoding functions ───────────────────────────────────────
28
+ { method: 'encodeURIComponent', languages: ['javascript', 'typescript', 'tsx'] },
29
+ { method: 'encodeURI', languages: ['javascript', 'typescript', 'tsx'] },
30
+ // ── JS/TS — HTML/XSS sanitizers ──────────────────────────────────────
31
+ { method: 'escape', languages: ['javascript', 'typescript', 'tsx'] },
32
+ { method: 'escapeHtml', languages: ['javascript', 'typescript', 'tsx'] },
33
+ { method: 'sanitize', languages: ['javascript', 'typescript', 'tsx'] },
34
+ { method: 'sanitizeHtml', languages: ['javascript', 'typescript', 'tsx'] },
35
+ { method: 'sanitize', receiver: 'DOMPurify', languages: ['javascript', 'typescript', 'tsx'] },
36
+ { method: 'xss', languages: ['javascript', 'typescript', 'tsx'] },
37
+ { method: 'clean', receiver: 'xss', languages: ['javascript', 'typescript', 'tsx'] },
38
+ // ── JS/TS — validator library ────────────────────────────────────────
39
+ // validator.isInt(x) etc. are validators, not sanitizers — they return
40
+ // boolean, not cleaned data. The sanitizer is validator.toString(x, true)
41
+ // etc. But `escape` from validator IS a sanitizer.
42
+ { method: 'escape', receiver: 'validator', languages: ['javascript', 'typescript', 'tsx'] },
43
+ { method: 'ltrim', receiver: 'validator', languages: ['javascript', 'typescript', 'tsx'] },
44
+ { method: 'rtrim', receiver: 'validator', languages: ['javascript', 'typescript', 'tsx'] },
45
+ { method: 'trim', receiver: 'validator', languages: ['javascript', 'typescript', 'tsx'] },
46
+ // ── Python — type coercions ──────────────────────────────────────────
47
+ { method: 'int', languages: ['python'] },
48
+ { method: 'float', languages: ['python'] },
49
+ { method: 'bool', languages: ['python'] },
50
+ // ── Python — HTML/XSS sanitizers ─────────────────────────────────────
51
+ { method: 'escape', languages: ['python'] },
52
+ { method: 'escape', receiver: 'markupsafe', languages: ['python'] },
53
+ { method: 'clean', receiver: 'bleach', languages: ['python'] },
54
+ { method: 'clean', receiver: 'nh3', languages: ['python'] },
55
+ ];
56
+ /**
57
+ * Check if a call expression is a sanitizer call.
58
+ * Returns the sanitizer name, or null if not a sanitizer.
59
+ *
60
+ * @param method the method name from callParts
61
+ * @param receiver the base identifier from callParts (or null for bare calls)
62
+ * @param language the source language
63
+ */
64
+ function matchSanitizer(method, receiver, language) {
65
+ for (const san of exports.SANITIZERS) {
66
+ if (!san.languages.includes(language))
67
+ continue;
68
+ if (san.method !== method)
69
+ continue;
70
+ if (san.receiver && receiver !== san.receiver)
71
+ continue;
72
+ return san.receiver ? `${san.receiver}.${san.method}` : san.method;
73
+ }
74
+ return null;
75
+ }
76
+ //# sourceMappingURL=sanitizers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sanitizers.js","sourceRoot":"","sources":["../../src/project-map/sanitizers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Phase B — AST-based sink finder.
3
+ *
4
+ * Walks a parsed file once and matches every call/assignment/jsx-attribute
5
+ * against the sink registry. Returns findings with argument shapes and
6
+ * enclosing-function context so the Taint Tracker (Phase C) and the Juror
7
+ * can reason about exploitability without re-parsing.
8
+ *
9
+ * Replaces the regex `sinkFloorService` with zero false positives on
10
+ * variable names that happen to match sink names (`const exec = ...`),
11
+ * sinks inside comments (AST skips them), and sinks inside string literals.
12
+ */
13
+ import { SinkLanguage } from './sinkRegistry';
14
+ export interface ArgInfo {
15
+ kind: 'literal' | 'template' | 'identifier' | 'binary' | 'call' | 'other';
16
+ /** For literal: the string value. For identifier: the variable name. For call: the call name. */
17
+ value?: string;
18
+ /** For template: whether the template has interpolation. */
19
+ interpolated?: boolean;
20
+ }
21
+ export interface SinkFinding {
22
+ /** 1-indexed start line. */
23
+ line: number;
24
+ /** 1-indexed end line (inclusive). */
25
+ endLine: number;
26
+ /** Sink id from the registry: 'exec', 'eval', 'innerHTML'. */
27
+ sink: string;
28
+ /** Canonical vulnerability type (matches API taxonomy). */
29
+ canonicalType: string;
30
+ severity: 'Critical' | 'High' | 'Medium';
31
+ /** The full call/assignment expression text (for display). */
32
+ callExpression: string;
33
+ /** Each argument's shape — empty for member-assignment / jsx-attribute. */
34
+ arguments: ArgInfo[];
35
+ /** Name of the enclosing function, or null at module level. */
36
+ enclosingFunction: string | null;
37
+ /** Whether the sink is inside a try/catch block. */
38
+ isInsideTryCatch: boolean;
39
+ }
40
+ /**
41
+ * Find all security sinks in source code via AST analysis.
42
+ *
43
+ * @param source the file's source text
44
+ * @param language the grammar to parse with
45
+ * @returns sink findings, ordered by line. Empty when the grammar is missing
46
+ * or the file fails to parse (best-effort: never throws).
47
+ */
48
+ export declare function findSinks(source: string, language: SinkLanguage): Promise<SinkFinding[]>;