@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,340 @@
1
+ "use strict";
2
+ /**
3
+ * Phase B — AST-based sink finder.
4
+ *
5
+ * Walks a parsed file once and matches every call/assignment/jsx-attribute
6
+ * against the sink registry. Returns findings with argument shapes and
7
+ * enclosing-function context so the Taint Tracker (Phase C) and the Juror
8
+ * can reason about exploitability without re-parsing.
9
+ *
10
+ * Replaces the regex `sinkFloorService` with zero false positives on
11
+ * variable names that happen to match sink names (`const exec = ...`),
12
+ * sinks inside comments (AST skips them), and sinks inside string literals.
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.findSinks = findSinks;
16
+ const parserLoader_1 = require("./parserLoader");
17
+ const astHelpers_1 = require("./astHelpers");
18
+ const sinkRegistry_1 = require("./sinkRegistry");
19
+ // ── Argument shape classification ──────────────────────────────────────────
20
+ function classifyArg(node, source) {
21
+ // JS/TS string literal
22
+ if ((0, astHelpers_1.isStringLiteral)(node)) {
23
+ return { kind: 'literal', value: source.slice(node.startIndex, node.endIndex) };
24
+ }
25
+ // Python string node is also 'string'
26
+ if (node.type === 'string') {
27
+ return { kind: 'literal', value: source.slice(node.startIndex, node.endIndex) };
28
+ }
29
+ // Numeric, boolean, regex, null, undefined → literal
30
+ if (['number', 'true', 'false', 'null', 'undefined', 'none', 'float', 'integer', 'boolean'].includes(node.type)) {
31
+ return { kind: 'literal', value: source.slice(node.startIndex, node.endIndex) };
32
+ }
33
+ // Function/arrow expressions are code, not user input — treat as literal
34
+ // for requireNonLiteralArg purposes (taint tracker handles closure taint).
35
+ if (['arrow_function', 'function_expression', 'function'].includes(node.type)) {
36
+ return { kind: 'literal', value: '<function>' };
37
+ }
38
+ // Template literal / template string
39
+ if (node.type === 'template_string' || node.type === 'template_literal') {
40
+ const interpolated = node.namedChildren.some(c => c.type === 'template_substitution' || c.type === 'template_expr');
41
+ return { kind: 'template', interpolated };
42
+ }
43
+ // Identifier — a variable reference
44
+ if ((0, astHelpers_1.isIdentifier)(node)) {
45
+ return { kind: 'identifier', value: source.slice(node.startIndex, node.endIndex) };
46
+ }
47
+ // Python identifier is 'identifier'
48
+ if (node.type === 'identifier') {
49
+ return { kind: 'identifier', value: source.slice(node.startIndex, node.endIndex) };
50
+ }
51
+ // Binary expression (concatenation, arithmetic)
52
+ if (node.type === 'binary_expression' || node.type === 'binary_operator_expression') {
53
+ return { kind: 'binary' };
54
+ }
55
+ // Python f-string / formatted string
56
+ if (node.type === 'concatenated_string' || node.type === 'string_interpolation') {
57
+ return { kind: 'template', interpolated: true };
58
+ }
59
+ // Call expression
60
+ if (node.type === 'call_expression' || node.type === 'call') {
61
+ const p = (0, astHelpers_1.callParts)(node, source);
62
+ return { kind: 'call', value: p ? (p.receiver ? `${p.receiver}.${p.method}` : p.method) : undefined };
63
+ }
64
+ // Member expression (e.g. req.body.q) — treat as identifier-like
65
+ if (node.type === 'member_expression' || node.type === 'attribute') {
66
+ return { kind: 'identifier', value: source.slice(node.startIndex, node.endIndex) };
67
+ }
68
+ return { kind: 'other' };
69
+ }
70
+ /** True if an argument is non-literal (potentially attacker-controlled). */
71
+ function isNonLiteral(arg) {
72
+ if (arg.kind === 'literal')
73
+ return false;
74
+ if (arg.kind === 'template' && !arg.interpolated)
75
+ return false;
76
+ return true;
77
+ }
78
+ // ── Enclosing function + try/catch ──────────────────────────────────────────
79
+ const FUNCTION_NODE_TYPES = new Set([
80
+ 'function_declaration', 'function_definition', 'method_definition',
81
+ 'async_function_declaration', 'async_function_definition',
82
+ 'arrow_function', 'function_expression',
83
+ 'generator_function_declaration', 'generator_declaration',
84
+ ]);
85
+ const TRY_TYPES = new Set(['try_statement', 'try']);
86
+ function enclosingFunctionName(node, source) {
87
+ const fn = (0, astHelpers_1.firstAncestor)(node, n => FUNCTION_NODE_TYPES.has(n.type));
88
+ if (!fn)
89
+ return null;
90
+ // Named function: function foo() {} — the name is the first identifier child
91
+ const id = fn.namedChildren.find(c => (0, astHelpers_1.isIdentifier)(c));
92
+ if (id)
93
+ return source.slice(id.startIndex, id.endIndex);
94
+ // const foo = () => {} — the name is on the declarator's parent
95
+ const parent = fn.parent;
96
+ if (parent) {
97
+ if (parent.type === 'lexical_declaration' || parent.type === 'variable_declaration') {
98
+ for (const decl of parent.namedChildren) {
99
+ if (decl.type !== 'variable_declarator')
100
+ continue;
101
+ const name = decl.child(0);
102
+ if (name && (0, astHelpers_1.isIdentifier)(name)) {
103
+ return source.slice(name.startIndex, name.endIndex);
104
+ }
105
+ }
106
+ }
107
+ // Python: `name = def x():` → assignment
108
+ if (parent.type === 'assignment') {
109
+ const target = parent.child(0);
110
+ if (target && (0, astHelpers_1.isIdentifier)(target)) {
111
+ return source.slice(target.startIndex, target.endIndex);
112
+ }
113
+ }
114
+ }
115
+ return '<anonymous>';
116
+ }
117
+ function isInsideTryCatch(node) {
118
+ return (0, astHelpers_1.firstAncestor)(node, n => TRY_TYPES.has(n.type)) !== null;
119
+ }
120
+ function extractCallInfo(node, source) {
121
+ if (node.type === 'call_expression' || node.type === 'call') {
122
+ const p = (0, astHelpers_1.callParts)(node, source);
123
+ if (!p)
124
+ return null;
125
+ let args = p.args;
126
+ // Tagged template literal: `tag\`...\`` — tree-sitter parses the
127
+ // template_literal as the last child directly (not inside an
128
+ // `arguments` node). callParts then extracts the template's named
129
+ // children (substitutions) instead of the template itself. Detect
130
+ // this and use the template node as the sole argument.
131
+ const lastChild = node.child(node.childCount - 1);
132
+ if (lastChild
133
+ && (lastChild.type === 'template_literal' || lastChild.type === 'template_string')) {
134
+ args = [lastChild];
135
+ }
136
+ return { receiver: p.receiver, method: p.method, args, line: p.line };
137
+ }
138
+ if (node.type === 'new_expression') {
139
+ // new_expression: `new Constructor(args)` — constructor is the first named child.
140
+ const constructor = node.namedChildren.find(c => c.type === 'identifier' || c.type === 'member_expression');
141
+ if (!constructor)
142
+ return null;
143
+ let receiver = null;
144
+ let method = '';
145
+ if (constructor.type === 'member_expression') {
146
+ const obj = constructor.child(0);
147
+ const prop = constructor.child(constructor.childCount - 1);
148
+ if (obj && prop) {
149
+ receiver = (0, astHelpers_1.baseIdentifier)(obj, source) ?? (0, parserLoader_1.nodeText)(obj, source);
150
+ method = source.slice(prop.startIndex, prop.endIndex);
151
+ }
152
+ }
153
+ else {
154
+ method = source.slice(constructor.startIndex, constructor.endIndex);
155
+ }
156
+ // Args: last named child that's an arguments/argument_list node.
157
+ const argsNode = node.namedChildren.find(c => c.type === 'arguments' || c.type === 'argument_list');
158
+ const args = [];
159
+ if (argsNode) {
160
+ for (const c of argsNode.namedChildren)
161
+ args.push(c);
162
+ }
163
+ return { receiver, method, args, line: node.startPosition.row };
164
+ }
165
+ return null;
166
+ }
167
+ /** Match a call's (receiver, method) against a single `call` matcher. */
168
+ function matchCall(matcher, receiver, method) {
169
+ if (method !== matcher.method)
170
+ return false;
171
+ if (matcher.receiver === undefined)
172
+ return receiver === null;
173
+ if (matcher.receiver === '*')
174
+ return true;
175
+ return receiver === matcher.receiver;
176
+ }
177
+ /** Check if a definition applies to the given language. */
178
+ function defForLanguage(def, lang) {
179
+ return def.languages.includes(lang);
180
+ }
181
+ // ── Finder ──────────────────────────────────────────────────────────────────
182
+ /**
183
+ * Find all security sinks in source code via AST analysis.
184
+ *
185
+ * @param source the file's source text
186
+ * @param language the grammar to parse with
187
+ * @returns sink findings, ordered by line. Empty when the grammar is missing
188
+ * or the file fails to parse (best-effort: never throws).
189
+ */
190
+ async function findSinks(source, language) {
191
+ const parsed = await (0, parserLoader_1.parseSource)(source, language);
192
+ if (!parsed)
193
+ return [];
194
+ const { root } = parsed;
195
+ const findings = [];
196
+ // Dedup key: `${line}:${canonicalType}` — same as the regex sink floor.
197
+ const seen = new Set();
198
+ for (const node of (0, astHelpers_1.walk)(root)) {
199
+ // ── 1. Call sinks (call_expression / call / new_expression) ──────
200
+ if (node.type === 'call_expression' || node.type === 'call' || node.type === 'new_expression') {
201
+ const info = extractCallInfo(node, source);
202
+ if (!info)
203
+ continue;
204
+ for (const def of sinkRegistry_1.SINK_REGISTRY) {
205
+ if (!defForLanguage(def, language))
206
+ continue;
207
+ let matched = false;
208
+ for (const matcher of def.matchers) {
209
+ if (matcher.kind !== 'call')
210
+ continue;
211
+ if (matchCall(matcher, info.receiver, info.method)) {
212
+ matched = true;
213
+ break;
214
+ }
215
+ }
216
+ if (!matched)
217
+ continue;
218
+ const args = info.args.map(a => classifyArg(a, source));
219
+ // For call sinks, only the FIRST argument is the injection
220
+ // vector (the query string, the path, the redirect URL).
221
+ // Subsequent arguments are parameters/options (e.g.
222
+ // db.query("SELECT...?", [params]) — the array is NOT an
223
+ // injection vector). Checking all args would false-positive
224
+ // on parameterized queries.
225
+ if (def.requireNonLiteralArg && !(args.length > 0 && isNonLiteral(args[0])))
226
+ continue;
227
+ const key = `${info.line + 1}:${def.canonicalType}`;
228
+ if (seen.has(key))
229
+ continue;
230
+ seen.add(key);
231
+ findings.push({
232
+ line: info.line + 1,
233
+ endLine: (node.endPosition?.row ?? info.line) + 1,
234
+ sink: def.id,
235
+ canonicalType: def.canonicalType,
236
+ severity: def.severity,
237
+ callExpression: source.slice(node.startIndex, node.endIndex),
238
+ arguments: args,
239
+ enclosingFunction: enclosingFunctionName(node, source),
240
+ isInsideTryCatch: isInsideTryCatch(node),
241
+ });
242
+ break; // first matching definition wins (registry is severity-ordered)
243
+ }
244
+ continue;
245
+ }
246
+ // ── 2. Member-assignment sinks (.innerHTML = ...) ────────────────
247
+ if (node.type === 'assignment_expression' || node.type === 'assignment') {
248
+ const lhs = node.child(0);
249
+ if (!lhs)
250
+ continue;
251
+ // LHS must be a member_expression / attribute
252
+ if (lhs.type !== 'member_expression' && lhs.type !== 'attribute')
253
+ continue;
254
+ const propNode = lhs.child(lhs.childCount - 1);
255
+ if (!propNode)
256
+ continue;
257
+ const propName = source.slice(propNode.startIndex, propNode.endIndex);
258
+ for (const def of sinkRegistry_1.SINK_REGISTRY) {
259
+ if (!defForLanguage(def, language))
260
+ continue;
261
+ let matched = false;
262
+ for (const matcher of def.matchers) {
263
+ if (matcher.kind !== 'member-assignment')
264
+ continue;
265
+ if (matcher.property === propName) {
266
+ matched = true;
267
+ break;
268
+ }
269
+ }
270
+ if (!matched)
271
+ continue;
272
+ const rhs = node.child(node.childCount - 1);
273
+ const args = rhs ? [classifyArg(rhs, source)] : [];
274
+ if (def.requireNonLiteralArg && !args.some(isNonLiteral))
275
+ continue;
276
+ const key = `${node.startPosition.row + 1}:${def.canonicalType}`;
277
+ if (seen.has(key))
278
+ continue;
279
+ seen.add(key);
280
+ findings.push({
281
+ line: node.startPosition.row + 1,
282
+ endLine: (node.endPosition?.row ?? node.startPosition.row) + 1,
283
+ sink: def.id,
284
+ canonicalType: def.canonicalType,
285
+ severity: def.severity,
286
+ callExpression: source.slice(node.startIndex, node.endIndex),
287
+ arguments: args,
288
+ enclosingFunction: enclosingFunctionName(node, source),
289
+ isInsideTryCatch: isInsideTryCatch(node),
290
+ });
291
+ break;
292
+ }
293
+ continue;
294
+ }
295
+ // ── 3. JSX attribute sinks (dangerouslySetInnerHTML) ─────────────
296
+ if (node.type === 'jsx_attribute') {
297
+ const nameNode = node.child(0);
298
+ if (!nameNode)
299
+ continue;
300
+ const attrName = source.slice(nameNode.startIndex, nameNode.endIndex);
301
+ for (const def of sinkRegistry_1.SINK_REGISTRY) {
302
+ if (!defForLanguage(def, language))
303
+ continue;
304
+ let matched = false;
305
+ for (const matcher of def.matchers) {
306
+ if (matcher.kind !== 'jsx-attribute')
307
+ continue;
308
+ if (matcher.name === attrName) {
309
+ matched = true;
310
+ break;
311
+ }
312
+ }
313
+ if (!matched)
314
+ continue;
315
+ const key = `${node.startPosition.row + 1}:${def.canonicalType}`;
316
+ if (seen.has(key))
317
+ continue;
318
+ seen.add(key);
319
+ // The value is child(1) or namedChildren[1]
320
+ const valueNode = node.namedChildren.length > 1 ? node.namedChildren[1] : null;
321
+ const args = valueNode ? [classifyArg(valueNode, source)] : [];
322
+ findings.push({
323
+ line: node.startPosition.row + 1,
324
+ endLine: (node.endPosition?.row ?? node.startPosition.row) + 1,
325
+ sink: def.id,
326
+ canonicalType: def.canonicalType,
327
+ severity: def.severity,
328
+ callExpression: source.slice(node.startIndex, node.endIndex),
329
+ arguments: args,
330
+ enclosingFunction: enclosingFunctionName(node, source),
331
+ isInsideTryCatch: isInsideTryCatch(node),
332
+ });
333
+ break;
334
+ }
335
+ }
336
+ }
337
+ findings.sort((a, b) => a.line - b.line);
338
+ return findings;
339
+ }
340
+ //# sourceMappingURL=sinkFinder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sinkFinder.js","sourceRoot":"","sources":["../../src/project-map/sinkFinder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Phase B — declarative sink registry for the AST sink finder.
3
+ *
4
+ * Each entry describes a dangerous operation (a "sink") that the finder
5
+ * matches against the parsed AST. The registry is deliberately conservative
6
+ * on false negatives (high recall): a missed sink is a missed vulnerability,
7
+ * while a false sink is dismissed by the Juror at no structural cost.
8
+ *
9
+ * The canonical types mirror `api/src/services/taxonomy.ts` CANONICAL_TYPES
10
+ * so the API can consume findings without translation.
11
+ */
12
+ /** Languages supported by the tree-sitter grammars we ship. */
13
+ export type SinkLanguage = 'javascript' | 'typescript' | 'tsx' | 'python';
14
+ /** How a sink is matched in the AST. */
15
+ export type SinkMatcher = {
16
+ kind: 'call';
17
+ /** The method name being called: `exec`, `eval`, `query`, `system`. */
18
+ method: string;
19
+ /**
20
+ * The base identifier the call is rooted at, or:
21
+ * - `undefined` → match only bare calls (no receiver): `eval(...)`
22
+ * - `'*'` → match any receiver: `x.query(...)`, `query(...)`
23
+ * - a string → match that exact receiver: `child_process.exec(...)`
24
+ */
25
+ receiver?: string | '*';
26
+ } | {
27
+ kind: 'member-assignment';
28
+ /** The property being assigned: `innerHTML`, `outerHTML`, `href`. */
29
+ property: string;
30
+ } | {
31
+ kind: 'jsx-attribute';
32
+ /** The JSX attribute name: `dangerouslySetInnerHTML`. */
33
+ name: string;
34
+ };
35
+ export interface SinkDefinition {
36
+ /** Stable id for dedup/logging: 'exec', 'eval', 'inner-html'. */
37
+ id: string;
38
+ /** Canonical vulnerability type (matches API taxonomy). */
39
+ canonicalType: string;
40
+ severity: 'Critical' | 'High' | 'Medium';
41
+ languages: SinkLanguage[];
42
+ matchers: SinkMatcher[];
43
+ /**
44
+ * Only report when at least one argument is non-literal (identifier,
45
+ * template with interpolation, binary expression, or call expression).
46
+ * Use for sinks where a literal argument is definitively safe:
47
+ * `res.redirect("/home")`, `fs.readFile("config.json")`,
48
+ * `db.query("SELECT * FROM users")`.
49
+ */
50
+ requireNonLiteralArg?: boolean;
51
+ description: string;
52
+ }
53
+ /**
54
+ * The sink registry. Superset of the 11 regex rules in
55
+ * `api/src/services/sinkFloorService.ts` plus Python sinks.
56
+ *
57
+ * Ordering is by severity (Critical first) so the finder, which stops at the
58
+ * first match per call site, prefers the most severe reading.
59
+ */
60
+ export declare const SINK_REGISTRY: SinkDefinition[];