@securecode-ai/mcp 0.1.0 → 0.2.1
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/mcp/server.js +16 -1
- package/dist/mcp/server.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/mapBuilder.js +44 -5
- package/dist/project-map/mapBuilder.js.map +1 -1
- 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/map.js +13 -1
- package/dist/tools/map.js.map +1 -1
- package/dist/tools/scan.js +44 -0
- package/dist/tools/scan.js.map +1 -1
- 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[];
|