@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.
- package/README.md +5 -3
- package/dist/api/client.d.ts +4 -0
- package/dist/api/client.js +49 -0
- package/dist/api/client.js.map +1 -1
- package/dist/api/types.d.ts +40 -0
- package/dist/index.js +64 -7
- package/dist/index.js.map +1 -1
- package/dist/poc/httpPocExecutor.d.ts +20 -0
- package/dist/poc/httpPocExecutor.js +247 -0
- package/dist/poc/httpPocExecutor.js.map +1 -0
- package/dist/poc/lightpandaExecutor.d.ts +41 -0
- package/dist/poc/lightpandaExecutor.js +263 -0
- package/dist/poc/lightpandaExecutor.js.map +1 -0
- package/dist/poc/pocExecutor.d.ts +46 -0
- package/dist/poc/pocExecutor.js +74 -0
- package/dist/poc/pocExecutor.js.map +1 -0
- package/dist/poc/pocRouter.d.ts +20 -0
- package/dist/poc/pocRouter.js +40 -0
- package/dist/poc/pocRouter.js.map +1 -0
- package/dist/poc/pocTypes.d.ts +54 -0
- package/dist/poc/pocTypes.js +16 -0
- package/dist/poc/pocTypes.js.map +1 -0
- package/dist/project-map/fixTester.d.ts +55 -0
- package/dist/project-map/fixTester.js +338 -0
- package/dist/project-map/fixTester.js.map +1 -0
- package/dist/project-map/guardEvaluator.d.ts +40 -0
- package/dist/project-map/guardEvaluator.js +216 -0
- package/dist/project-map/guardEvaluator.js.map +1 -0
- package/dist/project-map/guardPatterns.d.ts +43 -0
- package/dist/project-map/guardPatterns.js +173 -0
- package/dist/project-map/guardPatterns.js.map +1 -0
- package/dist/project-map/sanitizers.d.ts +34 -0
- package/dist/project-map/sanitizers.js +76 -0
- package/dist/project-map/sanitizers.js.map +1 -0
- package/dist/project-map/sinkFinder.d.ts +48 -0
- package/dist/project-map/sinkFinder.js +340 -0
- package/dist/project-map/sinkFinder.js.map +1 -0
- package/dist/project-map/sinkRegistry.d.ts +60 -0
- package/dist/project-map/sinkRegistry.js +246 -0
- package/dist/project-map/sinkRegistry.js.map +1 -0
- package/dist/project-map/taintSources.d.ts +30 -0
- package/dist/project-map/taintSources.js +77 -0
- package/dist/project-map/taintSources.js.map +1 -0
- package/dist/project-map/taintTracker.d.ts +42 -0
- package/dist/project-map/taintTracker.js +571 -0
- package/dist/project-map/taintTracker.js.map +1 -0
- package/dist/tools/scan.js +44 -0
- package/dist/tools/scan.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,571 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Phase C — taint propagation tracker.
|
|
4
|
+
*
|
|
5
|
+
* Walks a parsed file forward, maintaining a per-scope set of tainted
|
|
6
|
+
* variables. When a source access is found (req.body, request.GET, etc.),
|
|
7
|
+
* the variable is marked tainted. Taint propagates through assignments,
|
|
8
|
+
* concatenations, and template interpolations. Sanitizer calls strip
|
|
9
|
+
* taint. When a sink (from the sink registry) is encountered, the
|
|
10
|
+
* arguments are checked for taint — if tainted, a TaintResult is recorded
|
|
11
|
+
* with the full propagation path from source to sink.
|
|
12
|
+
*
|
|
13
|
+
* Intra-function: source and sink in the same function (the common case).
|
|
14
|
+
* Inter-function: a simple first pass identifies functions that return
|
|
15
|
+
* tainted data; calls to those functions propagate taint to the result.
|
|
16
|
+
*/
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.trackTaint = trackTaint;
|
|
19
|
+
const parserLoader_1 = require("./parserLoader");
|
|
20
|
+
const astHelpers_1 = require("./astHelpers");
|
|
21
|
+
const sinkRegistry_1 = require("./sinkRegistry");
|
|
22
|
+
const taintSources_1 = require("./taintSources");
|
|
23
|
+
const sanitizers_1 = require("./sanitizers");
|
|
24
|
+
function scopeGet(scope, name) {
|
|
25
|
+
let s = scope;
|
|
26
|
+
while (s) {
|
|
27
|
+
if (s.tainted.has(name))
|
|
28
|
+
return s.tainted.get(name);
|
|
29
|
+
s = s.parent;
|
|
30
|
+
}
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
// ── Node type sets ──────────────────────────────────────────────────────────
|
|
34
|
+
const FUNCTION_NODE_TYPES = new Set([
|
|
35
|
+
'function_declaration', 'function_definition', 'method_definition',
|
|
36
|
+
'async_function_declaration', 'async_function_definition',
|
|
37
|
+
'arrow_function', 'function_expression',
|
|
38
|
+
'generator_function_declaration', 'generator_declaration',
|
|
39
|
+
]);
|
|
40
|
+
const CALL_NODE_TYPES = new Set(['call_expression', 'call', 'new_expression']);
|
|
41
|
+
const STATEMENT_TYPES = new Set([
|
|
42
|
+
'expression_statement', 'lexical_declaration', 'variable_declaration',
|
|
43
|
+
'if_statement', 'for_statement', 'for_in_statement', 'for_each_statement',
|
|
44
|
+
'while_statement', 'do_statement', 'try_statement', 'try',
|
|
45
|
+
'return_statement', 'return',
|
|
46
|
+
'function_declaration', 'function_definition', 'method_definition',
|
|
47
|
+
'block', 'statement_block',
|
|
48
|
+
'export_statement', 'throw_statement', 'raise_statement',
|
|
49
|
+
'with_statement', 'augmented_assignment', 'assignment',
|
|
50
|
+
'decorated_definition',
|
|
51
|
+
]);
|
|
52
|
+
// ── Source detection ────────────────────────────────────────────────────────
|
|
53
|
+
/**
|
|
54
|
+
* Check if an expression node is a source access. Returns the source text
|
|
55
|
+
* if it is, null otherwise. Checks the text of the node against source
|
|
56
|
+
* patterns (req.body, request.GET, etc.).
|
|
57
|
+
*/
|
|
58
|
+
function detectSource(node, sourceText, language) {
|
|
59
|
+
const text = sourceText.slice(node.startIndex, node.endIndex);
|
|
60
|
+
const match = (0, taintSources_1.matchTaintSource)(text, language);
|
|
61
|
+
return match ? text : null;
|
|
62
|
+
}
|
|
63
|
+
// ── Expression taint checking ───────────────────────────────────────────────
|
|
64
|
+
/**
|
|
65
|
+
* Recursively check if an expression is tainted. Returns TaintInfo if
|
|
66
|
+
* tainted, null otherwise.
|
|
67
|
+
*/
|
|
68
|
+
function checkExpressionTaint(node, scope, sourceText, language, taintReturningFns) {
|
|
69
|
+
// 1. Check if the node text is a source
|
|
70
|
+
const srcText = detectSource(node, sourceText, language);
|
|
71
|
+
if (srcText) {
|
|
72
|
+
return {
|
|
73
|
+
source: srcText,
|
|
74
|
+
sourceLine: node.startPosition.row + 1,
|
|
75
|
+
path: [{
|
|
76
|
+
line: node.startPosition.row + 1,
|
|
77
|
+
variable: srcText,
|
|
78
|
+
operation: 'source',
|
|
79
|
+
description: `Source: ${srcText}`,
|
|
80
|
+
}],
|
|
81
|
+
sanitizersApplied: [],
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
// 2. Identifier — check if it's in the tainted set
|
|
85
|
+
if ((0, astHelpers_1.isIdentifier)(node) || node.type === 'identifier') {
|
|
86
|
+
const name = sourceText.slice(node.startIndex, node.endIndex);
|
|
87
|
+
return scopeGet(scope, name) ?? null;
|
|
88
|
+
}
|
|
89
|
+
// 3. Call expression — check sanitizer, source method, taint-returning
|
|
90
|
+
if (CALL_NODE_TYPES.has(node.type)) {
|
|
91
|
+
const p = (0, astHelpers_1.callParts)(node, sourceText);
|
|
92
|
+
if (p) {
|
|
93
|
+
// Sanitizer → taint stripped
|
|
94
|
+
const sanitizer = (0, sanitizers_1.matchSanitizer)(p.method, p.receiver, language);
|
|
95
|
+
if (sanitizer)
|
|
96
|
+
return null;
|
|
97
|
+
// Function text starts with a source (e.g. req.body.get('q'))
|
|
98
|
+
const funcText = p.receiverText
|
|
99
|
+
? `${p.receiverText}.${p.method}`
|
|
100
|
+
: p.method;
|
|
101
|
+
const srcMatch = (0, taintSources_1.matchTaintSource)(funcText, language);
|
|
102
|
+
if (srcMatch) {
|
|
103
|
+
return {
|
|
104
|
+
source: funcText,
|
|
105
|
+
sourceLine: node.startPosition.row + 1,
|
|
106
|
+
path: [{
|
|
107
|
+
line: node.startPosition.row + 1,
|
|
108
|
+
variable: funcText,
|
|
109
|
+
operation: 'source',
|
|
110
|
+
description: `Source: ${funcText}`,
|
|
111
|
+
}],
|
|
112
|
+
sanitizersApplied: [],
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
// Taint-returning function
|
|
116
|
+
const fnName = p.receiver ?? p.method;
|
|
117
|
+
if (taintReturningFns.has(fnName)) {
|
|
118
|
+
// Find the tainted argument to carry the source info
|
|
119
|
+
for (const arg of p.args) {
|
|
120
|
+
const argTaint = checkExpressionTaint(arg, scope, sourceText, language, taintReturningFns);
|
|
121
|
+
if (argTaint) {
|
|
122
|
+
return {
|
|
123
|
+
...argTaint,
|
|
124
|
+
path: [...argTaint.path, {
|
|
125
|
+
line: node.startPosition.row + 1,
|
|
126
|
+
variable: fnName,
|
|
127
|
+
operation: 'call-pass',
|
|
128
|
+
description: `${fnName}() returns tainted data`,
|
|
129
|
+
}],
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// Function is taint-returning but we can't trace the source
|
|
134
|
+
return {
|
|
135
|
+
source: `<${fnName}>`,
|
|
136
|
+
sourceLine: node.startPosition.row + 1,
|
|
137
|
+
path: [{
|
|
138
|
+
line: node.startPosition.row + 1,
|
|
139
|
+
variable: fnName,
|
|
140
|
+
operation: 'call-pass',
|
|
141
|
+
description: `${fnName}() returns tainted data`,
|
|
142
|
+
}],
|
|
143
|
+
sanitizersApplied: [],
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// Also check if the receiver of a method call is tainted
|
|
148
|
+
// e.g. const x = req.body; x.toString() — x is tainted, so x.toString() is tainted
|
|
149
|
+
if (node.type === 'call_expression' || node.type === 'call') {
|
|
150
|
+
const func = node.child(0);
|
|
151
|
+
if (func && (func.type === 'member_expression' || func.type === 'attribute')) {
|
|
152
|
+
const obj = func.child(0);
|
|
153
|
+
if (obj) {
|
|
154
|
+
const objTaint = checkExpressionTaint(obj, scope, sourceText, language, taintReturningFns);
|
|
155
|
+
if (objTaint) {
|
|
156
|
+
return {
|
|
157
|
+
...objTaint,
|
|
158
|
+
path: [...objTaint.path, {
|
|
159
|
+
line: node.startPosition.row + 1,
|
|
160
|
+
variable: sourceText.slice(func.startIndex, func.endIndex),
|
|
161
|
+
operation: 'call-pass',
|
|
162
|
+
description: `Method call on tainted receiver`,
|
|
163
|
+
}],
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
// 4. Binary expression (concatenation) — check both operands
|
|
172
|
+
if (node.type === 'binary_expression' || node.type === 'binary_operator_expression') {
|
|
173
|
+
const left = node.child(0);
|
|
174
|
+
const right = node.child(node.childCount - 1);
|
|
175
|
+
const leftTaint = left ? checkExpressionTaint(left, scope, sourceText, language, taintReturningFns) : null;
|
|
176
|
+
if (leftTaint) {
|
|
177
|
+
return {
|
|
178
|
+
...leftTaint,
|
|
179
|
+
path: [...leftTaint.path, {
|
|
180
|
+
line: node.startPosition.row + 1,
|
|
181
|
+
variable: sourceText.slice(node.startIndex, node.endIndex),
|
|
182
|
+
operation: 'concat',
|
|
183
|
+
description: `Concatenation with tainted data`,
|
|
184
|
+
}],
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
const rightTaint = right ? checkExpressionTaint(right, scope, sourceText, language, taintReturningFns) : null;
|
|
188
|
+
if (rightTaint) {
|
|
189
|
+
return {
|
|
190
|
+
...rightTaint,
|
|
191
|
+
path: [...rightTaint.path, {
|
|
192
|
+
line: node.startPosition.row + 1,
|
|
193
|
+
variable: sourceText.slice(node.startIndex, node.endIndex),
|
|
194
|
+
operation: 'concat',
|
|
195
|
+
description: `Concatenation with tainted data`,
|
|
196
|
+
}],
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
// 5. Template literal — check interpolations
|
|
202
|
+
if (node.type === 'template_literal' || node.type === 'template_string') {
|
|
203
|
+
for (const child of node.namedChildren) {
|
|
204
|
+
if (child.type === 'template_substitution' || child.type === 'template_expr') {
|
|
205
|
+
const expr = child.namedChildren[0];
|
|
206
|
+
if (expr) {
|
|
207
|
+
const taint = checkExpressionTaint(expr, scope, sourceText, language, taintReturningFns);
|
|
208
|
+
if (taint) {
|
|
209
|
+
return {
|
|
210
|
+
...taint,
|
|
211
|
+
path: [...taint.path, {
|
|
212
|
+
line: node.startPosition.row + 1,
|
|
213
|
+
variable: sourceText.slice(node.startIndex, node.endIndex),
|
|
214
|
+
operation: 'template',
|
|
215
|
+
description: `Template interpolation with tainted data`,
|
|
216
|
+
}],
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
// 6. Member expression — check if the object is tainted
|
|
225
|
+
if (node.type === 'member_expression' || node.type === 'attribute') {
|
|
226
|
+
const obj = node.child(0);
|
|
227
|
+
if (obj) {
|
|
228
|
+
return checkExpressionTaint(obj, scope, sourceText, language, taintReturningFns);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
// 7. Subscript expression — check if the object is tainted (req.body['q'])
|
|
232
|
+
if (node.type === 'subscript_expression' || node.type === 'subscript') {
|
|
233
|
+
const obj = node.child(0);
|
|
234
|
+
if (obj) {
|
|
235
|
+
return checkExpressionTaint(obj, scope, sourceText, language, taintReturningFns);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
// 8. Await / parenthesized / as — unwrap
|
|
239
|
+
if (node.type === 'await_expression' || node.type === 'await'
|
|
240
|
+
|| node.type === 'parenthesized_expression' || node.type === 'non_null_expression'
|
|
241
|
+
|| node.type === 'as_expression') {
|
|
242
|
+
const inner = node.namedChildren[0];
|
|
243
|
+
if (inner) {
|
|
244
|
+
return checkExpressionTaint(inner, scope, sourceText, language, taintReturningFns);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
// 9. Python augmented assignment (x += tainted)
|
|
248
|
+
if (node.type === 'augmented_assignment') {
|
|
249
|
+
const right = node.child(node.childCount - 1);
|
|
250
|
+
if (right) {
|
|
251
|
+
return checkExpressionTaint(right, scope, sourceText, language, taintReturningFns);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
// ── Sink matching ──────────────────────────────────────────────────────────
|
|
257
|
+
/** Match a call's (receiver, method) against a single `call` matcher. */
|
|
258
|
+
function matchCallMatcher(matcher, receiver, method) {
|
|
259
|
+
if (method !== matcher.method)
|
|
260
|
+
return false;
|
|
261
|
+
if (matcher.receiver === undefined)
|
|
262
|
+
return receiver === null;
|
|
263
|
+
if (matcher.receiver === '*')
|
|
264
|
+
return true;
|
|
265
|
+
return receiver === matcher.receiver;
|
|
266
|
+
}
|
|
267
|
+
/** Check if a call node matches any sink definition. Returns the def + args. */
|
|
268
|
+
function matchSink(node, sourceText, language) {
|
|
269
|
+
if (!CALL_NODE_TYPES.has(node.type))
|
|
270
|
+
return null;
|
|
271
|
+
const p = (0, astHelpers_1.callParts)(node, sourceText);
|
|
272
|
+
if (!p)
|
|
273
|
+
return null;
|
|
274
|
+
// Handle tagged template literals (queryRaw`...${x}...`)
|
|
275
|
+
let args = p.args;
|
|
276
|
+
const lastChild = node.child(node.childCount - 1);
|
|
277
|
+
if (lastChild && (lastChild.type === 'template_literal' || lastChild.type === 'template_string')) {
|
|
278
|
+
args = [lastChild];
|
|
279
|
+
}
|
|
280
|
+
for (const def of sinkRegistry_1.SINK_REGISTRY) {
|
|
281
|
+
if (!def.languages.includes(language))
|
|
282
|
+
continue;
|
|
283
|
+
for (const matcher of def.matchers) {
|
|
284
|
+
if (matcher.kind !== 'call')
|
|
285
|
+
continue;
|
|
286
|
+
if (matchCallMatcher(matcher, p.receiver, p.method)) {
|
|
287
|
+
return { def, args, line: p.line };
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
return null;
|
|
292
|
+
}
|
|
293
|
+
// ── Statement processing ───────────────────────────────────────────────────
|
|
294
|
+
/** Extract variable names from a destructuring pattern (object/array). */
|
|
295
|
+
function patternNames(pattern, sourceText) {
|
|
296
|
+
const names = [];
|
|
297
|
+
for (const n of (0, astHelpers_1.walk)(pattern)) {
|
|
298
|
+
if (n.type === 'shorthand_property_identifier_pattern'
|
|
299
|
+
|| n.type === 'shorthand_property_identifier') {
|
|
300
|
+
names.push(sourceText.slice(n.startIndex, n.endIndex));
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
if (n.type === 'pair_pattern' || n.type === 'pair') {
|
|
304
|
+
const value = n.namedChildren[n.namedChildren.length - 1];
|
|
305
|
+
if (value && (0, astHelpers_1.isIdentifier)(value)) {
|
|
306
|
+
names.push(sourceText.slice(value.startIndex, value.endIndex));
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return names;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Process a single variable declarator: `const x = expr` or `const { a, b } = expr`.
|
|
314
|
+
* If the RHS is tainted, the LHS variable(s) are marked tainted in the scope.
|
|
315
|
+
*/
|
|
316
|
+
function processDeclarator(decl, scope, sourceText, language, taintReturningFns) {
|
|
317
|
+
const lhs = decl.child(0);
|
|
318
|
+
const rhs = decl.child(decl.childCount - 1);
|
|
319
|
+
if (!lhs || !rhs || lhs === rhs)
|
|
320
|
+
return;
|
|
321
|
+
const taint = checkExpressionTaint(rhs, scope, sourceText, language, taintReturningFns);
|
|
322
|
+
if (!taint)
|
|
323
|
+
return;
|
|
324
|
+
if ((0, astHelpers_1.isIdentifier)(lhs) || lhs.type === 'identifier') {
|
|
325
|
+
const name = sourceText.slice(lhs.startIndex, lhs.endIndex);
|
|
326
|
+
scope.tainted.set(name, {
|
|
327
|
+
...taint,
|
|
328
|
+
path: [...taint.path, {
|
|
329
|
+
line: decl.startPosition.row + 1,
|
|
330
|
+
variable: name,
|
|
331
|
+
operation: 'assign',
|
|
332
|
+
description: `${name} = ${sourceText.slice(rhs.startIndex, rhs.endIndex)}`,
|
|
333
|
+
}],
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
else if (lhs.type === 'object_pattern' || lhs.type === 'array_pattern'
|
|
337
|
+
|| lhs.type === 'object' || lhs.type === 'list_pattern') {
|
|
338
|
+
for (const name of patternNames(lhs, sourceText)) {
|
|
339
|
+
scope.tainted.set(name, {
|
|
340
|
+
...taint,
|
|
341
|
+
path: [...taint.path, {
|
|
342
|
+
line: decl.startPosition.row + 1,
|
|
343
|
+
variable: name,
|
|
344
|
+
operation: 'assign',
|
|
345
|
+
description: `const { ${name} } = ${sourceText.slice(rhs.startIndex, rhs.endIndex)}`,
|
|
346
|
+
}],
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Process an expression statement. Handles:
|
|
353
|
+
* - Assignments: `x = tainted` → update scope
|
|
354
|
+
* - Sink calls: `exec(tainted)` → record result
|
|
355
|
+
*/
|
|
356
|
+
function processExpression(node, scope, sourceText, language, taintReturningFns, onSink) {
|
|
357
|
+
// Assignment: x = expr or x += expr
|
|
358
|
+
if (node.type === 'assignment_expression' || node.type === 'assignment'
|
|
359
|
+
|| node.type === 'augmented_assignment') {
|
|
360
|
+
const lhs = node.child(0);
|
|
361
|
+
const rhs = node.child(node.childCount - 1);
|
|
362
|
+
if (!lhs || !rhs || lhs === rhs)
|
|
363
|
+
return;
|
|
364
|
+
const taint = checkExpressionTaint(rhs, scope, sourceText, language, taintReturningFns);
|
|
365
|
+
if (taint && (0, astHelpers_1.isIdentifier)(lhs)) {
|
|
366
|
+
const name = sourceText.slice(lhs.startIndex, lhs.endIndex);
|
|
367
|
+
scope.tainted.set(name, {
|
|
368
|
+
...taint,
|
|
369
|
+
path: [...taint.path, {
|
|
370
|
+
line: node.startPosition.row + 1,
|
|
371
|
+
variable: name,
|
|
372
|
+
operation: 'assign',
|
|
373
|
+
description: `${name} = ${sourceText.slice(rhs.startIndex, rhs.endIndex)}`,
|
|
374
|
+
}],
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
// Sink call
|
|
380
|
+
const sinkMatch = matchSink(node, sourceText, language);
|
|
381
|
+
if (sinkMatch) {
|
|
382
|
+
for (const arg of sinkMatch.args) {
|
|
383
|
+
const taint = checkExpressionTaint(arg, scope, sourceText, language, taintReturningFns);
|
|
384
|
+
if (taint) {
|
|
385
|
+
onSink({
|
|
386
|
+
source: taint.source,
|
|
387
|
+
sourceLine: taint.sourceLine,
|
|
388
|
+
sink: sinkMatch.def.id,
|
|
389
|
+
sinkLine: sinkMatch.line + 1,
|
|
390
|
+
canonicalType: sinkMatch.def.canonicalType,
|
|
391
|
+
propagationPath: [...taint.path, {
|
|
392
|
+
line: sinkMatch.line + 1,
|
|
393
|
+
variable: sourceText.slice(arg.startIndex, arg.endIndex),
|
|
394
|
+
operation: 'sink-arg',
|
|
395
|
+
description: `${sinkMatch.def.id}(${sourceText.slice(arg.startIndex, arg.endIndex)})`,
|
|
396
|
+
}],
|
|
397
|
+
isTainted: true,
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
/** Find the body node of a function. Returns null for expression-body arrows. */
|
|
404
|
+
function functionBody(fn) {
|
|
405
|
+
for (const c of fn.namedChildren) {
|
|
406
|
+
if (c.type === 'statement_block' || c.type === 'block')
|
|
407
|
+
return c;
|
|
408
|
+
}
|
|
409
|
+
return null;
|
|
410
|
+
}
|
|
411
|
+
/** Get the name of a function node. */
|
|
412
|
+
function functionName(fn, sourceText) {
|
|
413
|
+
const id = fn.namedChildren.find(c => (0, astHelpers_1.isIdentifier)(c));
|
|
414
|
+
if (id)
|
|
415
|
+
return sourceText.slice(id.startIndex, id.endIndex);
|
|
416
|
+
const parent = fn.parent;
|
|
417
|
+
if (parent && (parent.type === 'lexical_declaration' || parent.type === 'variable_declaration' || parent.type === 'assignment')) {
|
|
418
|
+
const name = parent.child(0);
|
|
419
|
+
if (name && (0, astHelpers_1.isIdentifier)(name))
|
|
420
|
+
return sourceText.slice(name.startIndex, name.endIndex);
|
|
421
|
+
}
|
|
422
|
+
return null;
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* Process a scope (function body or module level). Walks named children in
|
|
426
|
+
* order, tracking taint and calling onSink when a tainted sink is found.
|
|
427
|
+
*/
|
|
428
|
+
function processScope(bodyNode, scope, sourceText, language, taintReturningFns, onSink, onReturn) {
|
|
429
|
+
for (const stmt of bodyNode.namedChildren) {
|
|
430
|
+
// Variable declaration
|
|
431
|
+
if (stmt.type === 'lexical_declaration' || stmt.type === 'variable_declaration') {
|
|
432
|
+
for (const decl of stmt.namedChildren) {
|
|
433
|
+
if (decl.type === 'variable_declarator') {
|
|
434
|
+
// Check if the RHS is an arrow/function — recurse into it
|
|
435
|
+
const rhs = decl.child(decl.childCount - 1);
|
|
436
|
+
if (rhs && FUNCTION_NODE_TYPES.has(rhs.type)) {
|
|
437
|
+
const fnName = sourceText.slice((decl.child(0) ?? decl).startIndex, (decl.child(0) ?? decl).endIndex);
|
|
438
|
+
const body = functionBody(rhs);
|
|
439
|
+
if (body) {
|
|
440
|
+
const childScope = { tainted: new Map(), parent: scope };
|
|
441
|
+
processScope(body, childScope, sourceText, language, taintReturningFns, onSink, onReturn);
|
|
442
|
+
}
|
|
443
|
+
continue;
|
|
444
|
+
}
|
|
445
|
+
processDeclarator(decl, scope, sourceText, language, taintReturningFns);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
continue;
|
|
449
|
+
}
|
|
450
|
+
// Expression statement
|
|
451
|
+
if (stmt.type === 'expression_statement') {
|
|
452
|
+
const expr = stmt.namedChildren[0];
|
|
453
|
+
if (expr)
|
|
454
|
+
processExpression(expr, scope, sourceText, language, taintReturningFns, onSink);
|
|
455
|
+
continue;
|
|
456
|
+
}
|
|
457
|
+
// Python assignment (not inside expression_statement)
|
|
458
|
+
if (stmt.type === 'assignment' || stmt.type === 'augmented_assignment') {
|
|
459
|
+
processExpression(stmt, scope, sourceText, language, taintReturningFns, onSink);
|
|
460
|
+
continue;
|
|
461
|
+
}
|
|
462
|
+
// Return statement
|
|
463
|
+
if (stmt.type === 'return_statement' || stmt.type === 'return') {
|
|
464
|
+
const expr = stmt.namedChildren[0];
|
|
465
|
+
if (expr) {
|
|
466
|
+
const taint = checkExpressionTaint(expr, scope, sourceText, language, taintReturningFns);
|
|
467
|
+
onReturn(taint);
|
|
468
|
+
}
|
|
469
|
+
else {
|
|
470
|
+
onReturn(null);
|
|
471
|
+
}
|
|
472
|
+
continue;
|
|
473
|
+
}
|
|
474
|
+
// Function declaration — recurse with new scope
|
|
475
|
+
if (FUNCTION_NODE_TYPES.has(stmt.type)) {
|
|
476
|
+
const body = functionBody(stmt);
|
|
477
|
+
if (body) {
|
|
478
|
+
const childScope = { tainted: new Map(), parent: scope };
|
|
479
|
+
processScope(body, childScope, sourceText, language, taintReturningFns, onSink, onReturn);
|
|
480
|
+
}
|
|
481
|
+
continue;
|
|
482
|
+
}
|
|
483
|
+
// Export statement — recurse into the declaration
|
|
484
|
+
if (stmt.type === 'export_statement') {
|
|
485
|
+
for (const child of stmt.namedChildren) {
|
|
486
|
+
if (STATEMENT_TYPES.has(child.type)) {
|
|
487
|
+
// Recursively process the exported declaration
|
|
488
|
+
processScope({ namedChildren: [child] }, scope, sourceText, language, taintReturningFns, onSink, onReturn);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
continue;
|
|
492
|
+
}
|
|
493
|
+
// Control flow — recurse into body
|
|
494
|
+
if (stmt.type === 'if_statement' || stmt.type === 'for_statement'
|
|
495
|
+
|| stmt.type === 'for_in_statement' || stmt.type === 'for_each_statement'
|
|
496
|
+
|| stmt.type === 'while_statement' || stmt.type === 'do_statement'
|
|
497
|
+
|| stmt.type === 'try_statement' || stmt.type === 'try'
|
|
498
|
+
|| stmt.type === 'with_statement' || stmt.type === 'block'
|
|
499
|
+
|| stmt.type === 'statement_block'
|
|
500
|
+
|| stmt.type === 'decorated_definition') {
|
|
501
|
+
for (const child of stmt.namedChildren) {
|
|
502
|
+
if (child.type === 'statement_block' || child.type === 'block'
|
|
503
|
+
|| STATEMENT_TYPES.has(child.type)) {
|
|
504
|
+
processScope(child.type === 'statement_block' || child.type === 'block' ? child : { namedChildren: [child] }, scope, sourceText, language, taintReturningFns, onSink, onReturn);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
continue;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
// ── First pass: identify taint-returning functions ─────────────────────────
|
|
512
|
+
/**
|
|
513
|
+
* Walk the AST and identify functions that return tainted data. A function
|
|
514
|
+
* is taint-returning if any return statement in its body returns a source
|
|
515
|
+
* access or a tainted variable.
|
|
516
|
+
*/
|
|
517
|
+
function findTaintReturningFunctions(root, sourceText, language) {
|
|
518
|
+
const result = new Set();
|
|
519
|
+
for (const node of (0, astHelpers_1.walk)(root)) {
|
|
520
|
+
if (!FUNCTION_NODE_TYPES.has(node.type))
|
|
521
|
+
continue;
|
|
522
|
+
const name = functionName(node, sourceText);
|
|
523
|
+
if (!name)
|
|
524
|
+
continue;
|
|
525
|
+
const body = functionBody(node);
|
|
526
|
+
if (!body)
|
|
527
|
+
continue;
|
|
528
|
+
const scope = { tainted: new Map(), parent: null };
|
|
529
|
+
let returnsTainted = false;
|
|
530
|
+
processScope(body, scope, sourceText, language, new Set(), () => { }, (taint) => {
|
|
531
|
+
if (taint)
|
|
532
|
+
returnsTainted = true;
|
|
533
|
+
});
|
|
534
|
+
if (returnsTainted)
|
|
535
|
+
result.add(name);
|
|
536
|
+
}
|
|
537
|
+
return result;
|
|
538
|
+
}
|
|
539
|
+
// ── Main entry point ───────────────────────────────────────────────────────
|
|
540
|
+
/**
|
|
541
|
+
* Track taint propagation through source code. Returns a TaintResult for
|
|
542
|
+
* every sink where tainted data reaches an argument.
|
|
543
|
+
*
|
|
544
|
+
* @param source the file's source text
|
|
545
|
+
* @param language the grammar to parse with
|
|
546
|
+
* @returns taint results, one per tainted sink argument. Empty when the
|
|
547
|
+
* grammar is missing, the file fails to parse, or no tainted data
|
|
548
|
+
* reaches any sink (best-effort: never throws).
|
|
549
|
+
*/
|
|
550
|
+
async function trackTaint(source, language) {
|
|
551
|
+
const parsed = await (0, parserLoader_1.parseSource)(source, language);
|
|
552
|
+
if (!parsed)
|
|
553
|
+
return [];
|
|
554
|
+
const { root } = parsed;
|
|
555
|
+
// First pass: identify taint-returning functions
|
|
556
|
+
const taintReturningFns = findTaintReturningFunctions(root, source, language);
|
|
557
|
+
// Second pass: track taint and record results at sinks
|
|
558
|
+
const results = [];
|
|
559
|
+
const onSink = (result) => {
|
|
560
|
+
// Dedup by (source, sink, sinkLine)
|
|
561
|
+
const key = `${result.source}:${result.sink}:${result.sinkLine}`;
|
|
562
|
+
if (!results.some(r => `${r.source}:${r.sink}:${r.sinkLine}` === key)) {
|
|
563
|
+
results.push(result);
|
|
564
|
+
}
|
|
565
|
+
};
|
|
566
|
+
// Process module level
|
|
567
|
+
const moduleScope = { tainted: new Map(), parent: null };
|
|
568
|
+
processScope(root, moduleScope, source, language, taintReturningFns, onSink, () => { });
|
|
569
|
+
return results;
|
|
570
|
+
}
|
|
571
|
+
//# sourceMappingURL=taintTracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"taintTracker.js","sourceRoot":"","sources":["../../src/project-map/taintTracker.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/scan.js
CHANGED
|
@@ -3,6 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.toolScan = toolScan;
|
|
4
4
|
const client_1 = require("../api/client");
|
|
5
5
|
const files_1 = require("../utils/files");
|
|
6
|
+
const sinkFinder_1 = require("../project-map/sinkFinder");
|
|
7
|
+
const taintTracker_1 = require("../project-map/taintTracker");
|
|
8
|
+
const guardEvaluator_1 = require("../project-map/guardEvaluator");
|
|
9
|
+
const parserLoader_1 = require("../project-map/parserLoader");
|
|
6
10
|
async function toolScan(ctx, args) {
|
|
7
11
|
const client = new client_1.ApiClient({ baseUrl: ctx.apiUrl, token: ctx.apiToken });
|
|
8
12
|
let code = args.code;
|
|
@@ -19,11 +23,51 @@ async function toolScan(ctx, args) {
|
|
|
19
23
|
if (!language) {
|
|
20
24
|
throw Object.assign(new Error('Provide language or filePath with a known extension.'), { code: -32602 });
|
|
21
25
|
}
|
|
26
|
+
// Phase B/C/E: AST-based sink finder + taint tracker + guard evaluator.
|
|
27
|
+
// Runs locally via tree-sitter and attaches deterministic facts to the
|
|
28
|
+
// scan request. The MCP has no related-files infrastructure, so the
|
|
29
|
+
// guard evaluator only evaluates guards found in the scanned file itself.
|
|
30
|
+
let deterministicFacts;
|
|
31
|
+
if (filePath) {
|
|
32
|
+
const grammar = (0, parserLoader_1.grammarForFile)(filePath);
|
|
33
|
+
if (grammar !== 'unknown') {
|
|
34
|
+
try {
|
|
35
|
+
const [sinks, taint] = await Promise.all([
|
|
36
|
+
(0, sinkFinder_1.findSinks)(code, grammar),
|
|
37
|
+
(0, taintTracker_1.trackTaint)(code, grammar),
|
|
38
|
+
]);
|
|
39
|
+
// Phase E: evaluate guards from the scanned file itself against
|
|
40
|
+
// the attack types found by the sink finder + taint tracker.
|
|
41
|
+
let guards;
|
|
42
|
+
const attackTypes = new Set();
|
|
43
|
+
for (const s of sinks)
|
|
44
|
+
attackTypes.add(s.canonicalType);
|
|
45
|
+
for (const t of taint)
|
|
46
|
+
attackTypes.add(t.canonicalType);
|
|
47
|
+
if (attackTypes.size > 0) {
|
|
48
|
+
guards = await (0, guardEvaluator_1.evaluateGuards)([{ source: code, name: filePath }], [...attackTypes], grammar);
|
|
49
|
+
if (guards.length === 0)
|
|
50
|
+
guards = undefined;
|
|
51
|
+
}
|
|
52
|
+
if (sinks.length > 0 || taint.length > 0 || (guards && guards.length > 0)) {
|
|
53
|
+
deterministicFacts = {
|
|
54
|
+
...(sinks.length > 0 && { sinks }),
|
|
55
|
+
...(taint.length > 0 && { taint }),
|
|
56
|
+
...(guards && { guards }),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// Best-effort: tree-sitter may be unavailable.
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
22
65
|
const data = await client.postJson('/scan', {
|
|
23
66
|
code,
|
|
24
67
|
language,
|
|
25
68
|
...(filePath ? { filePath } : {}),
|
|
26
69
|
scanDepth: 'auto',
|
|
70
|
+
...(deterministicFacts && { deterministicFacts }),
|
|
27
71
|
});
|
|
28
72
|
const findings = data.scanType === 'advanced' && data.finalFindings
|
|
29
73
|
? data.finalFindings
|