@trust-assurance-protocol/owaspscan 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analysis/ast-analyzer.d.ts +13 -0
- package/dist/analysis/ast-analyzer.d.ts.map +1 -0
- package/dist/analysis/ast-analyzer.js +58 -0
- package/dist/analysis/ast-analyzer.js.map +1 -0
- package/dist/analysis/llm-verifier.d.ts +17 -0
- package/dist/analysis/llm-verifier.d.ts.map +1 -0
- package/dist/analysis/llm-verifier.js +152 -0
- package/dist/analysis/llm-verifier.js.map +1 -0
- package/dist/analysis/result-cache.d.ts +20 -0
- package/dist/analysis/result-cache.d.ts.map +1 -0
- package/dist/analysis/result-cache.js +70 -0
- package/dist/analysis/result-cache.js.map +1 -0
- package/dist/analysis/sinks.d.ts +12 -0
- package/dist/analysis/sinks.d.ts.map +1 -0
- package/dist/analysis/sinks.js +142 -0
- package/dist/analysis/sinks.js.map +1 -0
- package/dist/analysis/sources.d.ts +8 -0
- package/dist/analysis/sources.d.ts.map +1 -0
- package/dist/analysis/sources.js +114 -0
- package/dist/analysis/sources.js.map +1 -0
- package/dist/analysis/taint-engine.d.ts +5 -0
- package/dist/analysis/taint-engine.d.ts.map +1 -0
- package/dist/analysis/taint-engine.js +187 -0
- package/dist/analysis/taint-engine.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +227 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/config/loader.d.ts +10 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +81 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +23 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +17 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/mcp/server.d.ts +2 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +250 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/parsers/ast-parser.d.ts +38 -0
- package/dist/parsers/ast-parser.d.ts.map +1 -0
- package/dist/parsers/ast-parser.js +88 -0
- package/dist/parsers/ast-parser.js.map +1 -0
- package/dist/parsers/ast-queries.d.ts +63 -0
- package/dist/parsers/ast-queries.d.ts.map +1 -0
- package/dist/parsers/ast-queries.js +580 -0
- package/dist/parsers/ast-queries.js.map +1 -0
- package/dist/reporter/console.d.ts +8 -0
- package/dist/reporter/console.d.ts.map +1 -0
- package/dist/reporter/console.js +143 -0
- package/dist/reporter/console.js.map +1 -0
- package/dist/reporter/json.d.ts +3 -0
- package/dist/reporter/json.d.ts.map +1 -0
- package/dist/reporter/json.js +7 -0
- package/dist/reporter/json.js.map +1 -0
- package/dist/reporter/llm.d.ts +3 -0
- package/dist/reporter/llm.d.ts.map +1 -0
- package/dist/reporter/llm.js +66 -0
- package/dist/reporter/llm.js.map +1 -0
- package/dist/reporter/sarif.d.ts +3 -0
- package/dist/reporter/sarif.d.ts.map +1 -0
- package/dist/reporter/sarif.js +110 -0
- package/dist/reporter/sarif.js.map +1 -0
- package/dist/rules/owasp-a01/idor.d.ts +3 -0
- package/dist/rules/owasp-a01/idor.d.ts.map +1 -0
- package/dist/rules/owasp-a01/idor.js +48 -0
- package/dist/rules/owasp-a01/idor.js.map +1 -0
- package/dist/rules/owasp-a01/missing-auth-middleware.d.ts +3 -0
- package/dist/rules/owasp-a01/missing-auth-middleware.d.ts.map +1 -0
- package/dist/rules/owasp-a01/missing-auth-middleware.js +41 -0
- package/dist/rules/owasp-a01/missing-auth-middleware.js.map +1 -0
- package/dist/rules/owasp-a01/path-traversal.d.ts +3 -0
- package/dist/rules/owasp-a01/path-traversal.d.ts.map +1 -0
- package/dist/rules/owasp-a01/path-traversal.js +73 -0
- package/dist/rules/owasp-a01/path-traversal.js.map +1 -0
- package/dist/rules/owasp-a02/hardcoded-secrets.d.ts +3 -0
- package/dist/rules/owasp-a02/hardcoded-secrets.d.ts.map +1 -0
- package/dist/rules/owasp-a02/hardcoded-secrets.js +97 -0
- package/dist/rules/owasp-a02/hardcoded-secrets.js.map +1 -0
- package/dist/rules/owasp-a02/insecure-tls.d.ts +3 -0
- package/dist/rules/owasp-a02/insecure-tls.d.ts.map +1 -0
- package/dist/rules/owasp-a02/insecure-tls.js +75 -0
- package/dist/rules/owasp-a02/insecure-tls.js.map +1 -0
- package/dist/rules/owasp-a02/weak-hash.d.ts +3 -0
- package/dist/rules/owasp-a02/weak-hash.d.ts.map +1 -0
- package/dist/rules/owasp-a02/weak-hash.js +73 -0
- package/dist/rules/owasp-a02/weak-hash.js.map +1 -0
- package/dist/rules/owasp-a02/weak-random.d.ts +3 -0
- package/dist/rules/owasp-a02/weak-random.d.ts.map +1 -0
- package/dist/rules/owasp-a02/weak-random.js +70 -0
- package/dist/rules/owasp-a02/weak-random.js.map +1 -0
- package/dist/rules/owasp-a03/command-injection.d.ts +3 -0
- package/dist/rules/owasp-a03/command-injection.d.ts.map +1 -0
- package/dist/rules/owasp-a03/command-injection.js +79 -0
- package/dist/rules/owasp-a03/command-injection.js.map +1 -0
- package/dist/rules/owasp-a03/ldap-injection.d.ts +3 -0
- package/dist/rules/owasp-a03/ldap-injection.d.ts.map +1 -0
- package/dist/rules/owasp-a03/ldap-injection.js +56 -0
- package/dist/rules/owasp-a03/ldap-injection.js.map +1 -0
- package/dist/rules/owasp-a03/nosql-injection.d.ts +3 -0
- package/dist/rules/owasp-a03/nosql-injection.d.ts.map +1 -0
- package/dist/rules/owasp-a03/nosql-injection.js +61 -0
- package/dist/rules/owasp-a03/nosql-injection.js.map +1 -0
- package/dist/rules/owasp-a03/sql-injection.d.ts +3 -0
- package/dist/rules/owasp-a03/sql-injection.d.ts.map +1 -0
- package/dist/rules/owasp-a03/sql-injection.js +88 -0
- package/dist/rules/owasp-a03/sql-injection.js.map +1 -0
- package/dist/rules/owasp-a03/template-injection.d.ts +3 -0
- package/dist/rules/owasp-a03/template-injection.d.ts.map +1 -0
- package/dist/rules/owasp-a03/template-injection.js +64 -0
- package/dist/rules/owasp-a03/template-injection.js.map +1 -0
- package/dist/rules/owasp-a03/xss.d.ts +3 -0
- package/dist/rules/owasp-a03/xss.d.ts.map +1 -0
- package/dist/rules/owasp-a03/xss.js +74 -0
- package/dist/rules/owasp-a03/xss.js.map +1 -0
- package/dist/rules/owasp-a04/mass-assignment.d.ts +3 -0
- package/dist/rules/owasp-a04/mass-assignment.d.ts.map +1 -0
- package/dist/rules/owasp-a04/mass-assignment.js +63 -0
- package/dist/rules/owasp-a04/mass-assignment.js.map +1 -0
- package/dist/rules/owasp-a04/missing-rate-limit.d.ts +3 -0
- package/dist/rules/owasp-a04/missing-rate-limit.d.ts.map +1 -0
- package/dist/rules/owasp-a04/missing-rate-limit.js +48 -0
- package/dist/rules/owasp-a04/missing-rate-limit.js.map +1 -0
- package/dist/rules/owasp-a05/cors-wildcard.d.ts +3 -0
- package/dist/rules/owasp-a05/cors-wildcard.d.ts.map +1 -0
- package/dist/rules/owasp-a05/cors-wildcard.js +79 -0
- package/dist/rules/owasp-a05/cors-wildcard.js.map +1 -0
- package/dist/rules/owasp-a05/debug-mode.d.ts +3 -0
- package/dist/rules/owasp-a05/debug-mode.d.ts.map +1 -0
- package/dist/rules/owasp-a05/debug-mode.js +73 -0
- package/dist/rules/owasp-a05/debug-mode.js.map +1 -0
- package/dist/rules/owasp-a05/default-credentials.d.ts +3 -0
- package/dist/rules/owasp-a05/default-credentials.d.ts.map +1 -0
- package/dist/rules/owasp-a05/default-credentials.js +52 -0
- package/dist/rules/owasp-a05/default-credentials.js.map +1 -0
- package/dist/rules/owasp-a05/error-disclosure.d.ts +3 -0
- package/dist/rules/owasp-a05/error-disclosure.d.ts.map +1 -0
- package/dist/rules/owasp-a05/error-disclosure.js +70 -0
- package/dist/rules/owasp-a05/error-disclosure.js.map +1 -0
- package/dist/rules/owasp-a06/outdated-packages.d.ts +3 -0
- package/dist/rules/owasp-a06/outdated-packages.d.ts.map +1 -0
- package/dist/rules/owasp-a06/outdated-packages.js +75 -0
- package/dist/rules/owasp-a06/outdated-packages.js.map +1 -0
- package/dist/rules/owasp-a07/insecure-cookies.d.ts +3 -0
- package/dist/rules/owasp-a07/insecure-cookies.d.ts.map +1 -0
- package/dist/rules/owasp-a07/insecure-cookies.js +64 -0
- package/dist/rules/owasp-a07/insecure-cookies.js.map +1 -0
- package/dist/rules/owasp-a07/jwt-none-alg.d.ts +3 -0
- package/dist/rules/owasp-a07/jwt-none-alg.d.ts.map +1 -0
- package/dist/rules/owasp-a07/jwt-none-alg.js +81 -0
- package/dist/rules/owasp-a07/jwt-none-alg.js.map +1 -0
- package/dist/rules/owasp-a07/no-password-hashing.d.ts +3 -0
- package/dist/rules/owasp-a07/no-password-hashing.d.ts.map +1 -0
- package/dist/rules/owasp-a07/no-password-hashing.js +70 -0
- package/dist/rules/owasp-a07/no-password-hashing.js.map +1 -0
- package/dist/rules/owasp-a07/weak-session.d.ts +3 -0
- package/dist/rules/owasp-a07/weak-session.d.ts.map +1 -0
- package/dist/rules/owasp-a07/weak-session.js +64 -0
- package/dist/rules/owasp-a07/weak-session.js.map +1 -0
- package/dist/rules/owasp-a08/unsafe-deserialization.d.ts +3 -0
- package/dist/rules/owasp-a08/unsafe-deserialization.d.ts.map +1 -0
- package/dist/rules/owasp-a08/unsafe-deserialization.js +78 -0
- package/dist/rules/owasp-a08/unsafe-deserialization.js.map +1 -0
- package/dist/rules/owasp-a08/unsafe-eval.d.ts +3 -0
- package/dist/rules/owasp-a08/unsafe-eval.d.ts.map +1 -0
- package/dist/rules/owasp-a08/unsafe-eval.js +73 -0
- package/dist/rules/owasp-a08/unsafe-eval.js.map +1 -0
- package/dist/rules/owasp-a09/log-sensitive-data.d.ts +3 -0
- package/dist/rules/owasp-a09/log-sensitive-data.d.ts.map +1 -0
- package/dist/rules/owasp-a09/log-sensitive-data.js +73 -0
- package/dist/rules/owasp-a09/log-sensitive-data.js.map +1 -0
- package/dist/rules/owasp-a09/missing-error-handling.d.ts +3 -0
- package/dist/rules/owasp-a09/missing-error-handling.d.ts.map +1 -0
- package/dist/rules/owasp-a09/missing-error-handling.js +84 -0
- package/dist/rules/owasp-a09/missing-error-handling.js.map +1 -0
- package/dist/rules/owasp-a10/open-redirect.d.ts +3 -0
- package/dist/rules/owasp-a10/open-redirect.d.ts.map +1 -0
- package/dist/rules/owasp-a10/open-redirect.js +67 -0
- package/dist/rules/owasp-a10/open-redirect.js.map +1 -0
- package/dist/rules/owasp-a10/unvalidated-fetch.d.ts +3 -0
- package/dist/rules/owasp-a10/unvalidated-fetch.d.ts.map +1 -0
- package/dist/rules/owasp-a10/unvalidated-fetch.js +85 -0
- package/dist/rules/owasp-a10/unvalidated-fetch.js.map +1 -0
- package/dist/rules/registry.d.ts +20 -0
- package/dist/rules/registry.d.ts.map +1 -0
- package/dist/rules/registry.js +142 -0
- package/dist/rules/registry.js.map +1 -0
- package/dist/scanner/engine.d.ts +21 -0
- package/dist/scanner/engine.d.ts.map +1 -0
- package/dist/scanner/engine.js +260 -0
- package/dist/scanner/engine.js.map +1 -0
- package/dist/scanner/file-walker.d.ts +7 -0
- package/dist/scanner/file-walker.d.ts.map +1 -0
- package/dist/scanner/file-walker.js +81 -0
- package/dist/scanner/file-walker.js.map +1 -0
- package/dist/scanner/language-detect.d.ts +5 -0
- package/dist/scanner/language-detect.d.ts.map +1 -0
- package/dist/scanner/language-detect.js +91 -0
- package/dist/scanner/language-detect.js.map +1 -0
- package/dist/scanner/sca-scanner.d.ts +38 -0
- package/dist/scanner/sca-scanner.d.ts.map +1 -0
- package/dist/scanner/sca-scanner.js +223 -0
- package/dist/scanner/sca-scanner.js.map +1 -0
- package/dist/types/index.d.ts +114 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +25 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/pattern-matcher.d.ts +4 -0
- package/dist/utils/pattern-matcher.d.ts.map +1 -0
- package/dist/utils/pattern-matcher.js +72 -0
- package/dist/utils/pattern-matcher.js.map +1 -0
- package/dist/utils/scoring.d.ts +8 -0
- package/dist/utils/scoring.d.ts.map +1 -0
- package/dist/utils/scoring.js +76 -0
- package/dist/utils/scoring.js.map +1 -0
- package/dist/utils/suppression.d.ts +3 -0
- package/dist/utils/suppression.d.ts.map +1 -0
- package/dist/utils/suppression.js +33 -0
- package/dist/utils/suppression.js.map +1 -0
- package/package.json +94 -0
|
@@ -0,0 +1,580 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// AST Queries — structural sink/source detection + AST-based taint
|
|
3
|
+
//
|
|
4
|
+
// Two detection modes:
|
|
5
|
+
//
|
|
6
|
+
// 1. Direct detection: user input appears directly in a sink arg
|
|
7
|
+
// `db.query("SELECT..." + req.query.id)`
|
|
8
|
+
// `exec(\`ping ${req.query.host}\`)`
|
|
9
|
+
//
|
|
10
|
+
// 2. AST taint propagation: user input assigned to variable, used in sink
|
|
11
|
+
// `const userId = req.query.id;` ← source node: variable_declarator
|
|
12
|
+
// `const query = "SELECT..." + userId;` ← propagation: binary_expression
|
|
13
|
+
// `db.query(query);` ← sink arg is a tainted identifier
|
|
14
|
+
//
|
|
15
|
+
// Both use tree-sitter AST nodes — no regex string matching for variable tracking.
|
|
16
|
+
// This eliminates false positives from comment lines and string contents.
|
|
17
|
+
// ============================================================
|
|
18
|
+
import { findAllNodes } from './ast-parser.js';
|
|
19
|
+
// ---- Source patterns ----
|
|
20
|
+
// These match the TEXT of AST nodes that represent user-controlled input.
|
|
21
|
+
const JS_SOURCE_RE = /\breq(?:uest)?\.(?:query|body|params)\b|\bevent\.target\.value\b|\bprocess\.argv\b|\blocalStorage\.getItem\b|\bsessionStorage\.getItem\b|\bsearchParams\.get\b/;
|
|
22
|
+
const PY_SOURCE_RE = /\brequest\.(?:args|form|json|values|data|files)\b|\brequest\.(?:GET|POST|body)\b|\binput\s*\(|\bsys\.argv\b/;
|
|
23
|
+
function hasUserInput(node, language) {
|
|
24
|
+
const re = language === 'python' ? PY_SOURCE_RE : JS_SOURCE_RE;
|
|
25
|
+
return re.test(node.text);
|
|
26
|
+
}
|
|
27
|
+
// ---- Cross-file taint source collection ----
|
|
28
|
+
/**
|
|
29
|
+
* Scan a single file's AST and collect the names of exported functions/variables
|
|
30
|
+
* whose bodies contain direct user-input sources.
|
|
31
|
+
*
|
|
32
|
+
* Used for cross-file taint tracking: if file A exports `getUserId(req)` which
|
|
33
|
+
* reads `req.query.id`, and file B calls `getUserId(req)`, the return value in
|
|
34
|
+
* file B should be treated as tainted.
|
|
35
|
+
*/
|
|
36
|
+
export function collectExportedTaintSources(rootNode, language) {
|
|
37
|
+
const sources = new Map();
|
|
38
|
+
for (const exportStmt of findAllNodes(rootNode, 'export_statement')) {
|
|
39
|
+
// export function NAME(req, ...) { ... req.query ... }
|
|
40
|
+
for (const funcDecl of findAllNodes(exportStmt, 'function_declaration')) {
|
|
41
|
+
const nameNode = funcDecl.childForFieldName('name');
|
|
42
|
+
const bodyNode = funcDecl.childForFieldName('body');
|
|
43
|
+
if (nameNode && bodyNode && hasUserInput(bodyNode, language)) {
|
|
44
|
+
sources.set(nameNode.text, `exported fn '${nameNode.text}' reads user input`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// export const NAME = (req) => req.body.x OR export const NAME = function(req) { ... }
|
|
48
|
+
for (const varDecl of findAllNodes(exportStmt, 'variable_declarator')) {
|
|
49
|
+
const nameNode = varDecl.childForFieldName('name');
|
|
50
|
+
const valueNode = varDecl.childForFieldName('value');
|
|
51
|
+
if (!nameNode || !valueNode || nameNode.type !== 'identifier')
|
|
52
|
+
continue;
|
|
53
|
+
if ((valueNode.type === 'arrow_function' || valueNode.type === 'function') &&
|
|
54
|
+
hasUserInput(valueNode, language)) {
|
|
55
|
+
sources.set(nameNode.text, `exported arrow fn '${nameNode.text}' reads user input`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// Also: module.exports.NAME = function(req) { ... } (CommonJS)
|
|
60
|
+
for (const assign of findAllNodes(rootNode, 'assignment_expression')) {
|
|
61
|
+
const left = assign.childForFieldName('left');
|
|
62
|
+
const right = assign.childForFieldName('right');
|
|
63
|
+
if (!left || !right)
|
|
64
|
+
continue;
|
|
65
|
+
// left must be `module.exports.NAME` or `exports.NAME`
|
|
66
|
+
if (left.type !== 'member_expression')
|
|
67
|
+
continue;
|
|
68
|
+
const leftText = left.text;
|
|
69
|
+
if (!/\b(?:module\.exports|exports)\.\w+/.test(leftText))
|
|
70
|
+
continue;
|
|
71
|
+
const propName = left.childForFieldName('property')?.text;
|
|
72
|
+
if (!propName)
|
|
73
|
+
continue;
|
|
74
|
+
if ((right.type === 'function' || right.type === 'arrow_function') &&
|
|
75
|
+
hasUserInput(right, language)) {
|
|
76
|
+
sources.set(propName, `module.exports.${propName} reads user input`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return sources;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Walk all variable declarations and assignments in the AST.
|
|
83
|
+
* When the right-hand side is/contains a user input source, mark the
|
|
84
|
+
* left-hand variable name(s) as tainted.
|
|
85
|
+
*
|
|
86
|
+
* crossFileSources: optional map of function names from other files that return
|
|
87
|
+
* tainted data (built by collectExportedTaintSources in the pre-pass).
|
|
88
|
+
*
|
|
89
|
+
* Returns the initial (un-propagated) taint map.
|
|
90
|
+
*/
|
|
91
|
+
export function buildInitialTaintMap(rootNode, language, crossFileSources) {
|
|
92
|
+
const tainted = new Map();
|
|
93
|
+
if (language === 'javascript' || language === 'typescript') {
|
|
94
|
+
// --- variable_declarator: `const/let/var NAME = VALUE` ---
|
|
95
|
+
for (const decl of findAllNodes(rootNode, 'variable_declarator')) {
|
|
96
|
+
const nameNode = decl.childForFieldName('name');
|
|
97
|
+
const valueNode = decl.childForFieldName('value');
|
|
98
|
+
if (!nameNode || !valueNode)
|
|
99
|
+
continue;
|
|
100
|
+
// Cross-file taint must be checked BEFORE the hasUserInput guard,
|
|
101
|
+
// because `getUserId(req)` doesn't contain req.query directly.
|
|
102
|
+
if (crossFileSources && nameNode.type === 'identifier' && valueNode.type === 'call_expression') {
|
|
103
|
+
const callFuncNode = valueNode.childForFieldName('function');
|
|
104
|
+
if (callFuncNode) {
|
|
105
|
+
const calleeName = callFuncNode.type === 'member_expression'
|
|
106
|
+
? (callFuncNode.childForFieldName('property')?.text ?? '')
|
|
107
|
+
: callFuncNode.text;
|
|
108
|
+
if (crossFileSources.has(calleeName)) {
|
|
109
|
+
tainted.set(nameNode.text, `return value of cross-file fn '${calleeName}' (${crossFileSources.get(calleeName)})`);
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (!hasUserInput(valueNode, language))
|
|
115
|
+
continue;
|
|
116
|
+
// Simple identifier: const userId = req.query.id
|
|
117
|
+
if (nameNode.type === 'identifier') {
|
|
118
|
+
tainted.set(nameNode.text, `assigned from ${valueNode.text.slice(0, 60)}`);
|
|
119
|
+
}
|
|
120
|
+
// Destructuring: const { id, name } = req.query
|
|
121
|
+
if (nameNode.type === 'object_pattern') {
|
|
122
|
+
for (const prop of findAllNodes(nameNode, 'shorthand_property_identifier_pattern')) {
|
|
123
|
+
tainted.set(prop.text, `destructured from ${valueNode.text.slice(0, 40)}`);
|
|
124
|
+
}
|
|
125
|
+
// Also handle: const { id: userId } = req.query
|
|
126
|
+
for (const prop of findAllNodes(nameNode, 'pair_pattern')) {
|
|
127
|
+
const val = prop.childForFieldName('value');
|
|
128
|
+
if (val?.type === 'identifier') {
|
|
129
|
+
tainted.set(val.text, `destructured from ${valueNode.text.slice(0, 40)}`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// Array destructuring: const [a, b] = req.body.items
|
|
134
|
+
if (nameNode.type === 'array_pattern') {
|
|
135
|
+
for (const elem of nameNode.namedChildren) {
|
|
136
|
+
if (elem.type === 'identifier') {
|
|
137
|
+
tainted.set(elem.text, `array-destructured from ${valueNode.text.slice(0, 40)}`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
// --- assignment_expression: `NAME = VALUE` (reassignment) ---
|
|
143
|
+
for (const assign of findAllNodes(rootNode, 'assignment_expression')) {
|
|
144
|
+
const left = assign.childForFieldName('left');
|
|
145
|
+
const right = assign.childForFieldName('right');
|
|
146
|
+
if (!left || !right)
|
|
147
|
+
continue;
|
|
148
|
+
if (left.type !== 'identifier')
|
|
149
|
+
continue;
|
|
150
|
+
if (hasUserInput(right, language)) {
|
|
151
|
+
tainted.set(left.text, `reassigned from ${right.text.slice(0, 60)}`);
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
// Cross-file: taintedVar = crossFileFn(...)
|
|
155
|
+
if (crossFileSources && right.type === 'call_expression') {
|
|
156
|
+
const callFuncNode = right.childForFieldName('function');
|
|
157
|
+
if (callFuncNode) {
|
|
158
|
+
const calleeName = callFuncNode.type === 'member_expression'
|
|
159
|
+
? (callFuncNode.childForFieldName('property')?.text ?? '')
|
|
160
|
+
: callFuncNode.text;
|
|
161
|
+
if (crossFileSources.has(calleeName)) {
|
|
162
|
+
tainted.set(left.text, `reassigned from cross-file fn '${calleeName}'`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
if (language === 'python') {
|
|
169
|
+
// Python: `assignment` node → identifier = value
|
|
170
|
+
for (const assign of findAllNodes(rootNode, 'assignment')) {
|
|
171
|
+
const left = assign.namedChildren[0];
|
|
172
|
+
const right = assign.namedChildren[assign.namedChildren.length - 1];
|
|
173
|
+
if (!left || !right || left === right)
|
|
174
|
+
continue;
|
|
175
|
+
if (left.type !== 'identifier')
|
|
176
|
+
continue;
|
|
177
|
+
if (!hasUserInput(right, language))
|
|
178
|
+
continue;
|
|
179
|
+
tainted.set(left.text, `assigned from ${right.text.slice(0, 60)}`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return tainted;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Fixed-point propagation: if the RHS of an assignment contains a tainted
|
|
186
|
+
* identifier, the LHS variable becomes tainted too.
|
|
187
|
+
*
|
|
188
|
+
* Mutates `tainted` in place. Runs until no new taints are added (max 10 passes).
|
|
189
|
+
*/
|
|
190
|
+
export function propagateTaint(rootNode, tainted, language) {
|
|
191
|
+
function rhsContainsTainted(valueNode) {
|
|
192
|
+
for (const identNode of findAllNodes(valueNode, 'identifier')) {
|
|
193
|
+
if (tainted.has(identNode.text))
|
|
194
|
+
return identNode.text;
|
|
195
|
+
}
|
|
196
|
+
// Template substitutions: `${taintedVar}`
|
|
197
|
+
for (const sub of findAllNodes(valueNode, 'template_substitution')) {
|
|
198
|
+
for (const identNode of findAllNodes(sub, 'identifier')) {
|
|
199
|
+
if (tainted.has(identNode.text))
|
|
200
|
+
return identNode.text;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
let changed = true;
|
|
206
|
+
let passes = 0;
|
|
207
|
+
while (changed && passes < 10) {
|
|
208
|
+
changed = false;
|
|
209
|
+
passes++;
|
|
210
|
+
if (language === 'javascript' || language === 'typescript') {
|
|
211
|
+
for (const decl of findAllNodes(rootNode, 'variable_declarator')) {
|
|
212
|
+
const nameNode = decl.childForFieldName('name');
|
|
213
|
+
const valueNode = decl.childForFieldName('value');
|
|
214
|
+
if (!nameNode || !valueNode)
|
|
215
|
+
continue;
|
|
216
|
+
if (nameNode.type !== 'identifier')
|
|
217
|
+
continue;
|
|
218
|
+
if (tainted.has(nameNode.text))
|
|
219
|
+
continue;
|
|
220
|
+
const fromVar = rhsContainsTainted(valueNode);
|
|
221
|
+
if (fromVar) {
|
|
222
|
+
tainted.set(nameNode.text, `derived from tainted '${fromVar}'`);
|
|
223
|
+
changed = true;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
for (const assign of findAllNodes(rootNode, 'assignment_expression')) {
|
|
227
|
+
const left = assign.childForFieldName('left');
|
|
228
|
+
const right = assign.childForFieldName('right');
|
|
229
|
+
if (!left || !right)
|
|
230
|
+
continue;
|
|
231
|
+
if (left.type !== 'identifier')
|
|
232
|
+
continue;
|
|
233
|
+
if (tainted.has(left.text))
|
|
234
|
+
continue;
|
|
235
|
+
const fromVar = rhsContainsTainted(right);
|
|
236
|
+
if (fromVar) {
|
|
237
|
+
tainted.set(left.text, `derived from tainted '${fromVar}'`);
|
|
238
|
+
changed = true;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
if (language === 'python') {
|
|
243
|
+
for (const assign of findAllNodes(rootNode, 'assignment')) {
|
|
244
|
+
const left = assign.namedChildren[0];
|
|
245
|
+
const right = assign.namedChildren[assign.namedChildren.length - 1];
|
|
246
|
+
if (!left || !right || left === right)
|
|
247
|
+
continue;
|
|
248
|
+
if (left.type !== 'identifier')
|
|
249
|
+
continue;
|
|
250
|
+
if (tainted.has(left.text))
|
|
251
|
+
continue;
|
|
252
|
+
const fromVar = rhsContainsTainted(right);
|
|
253
|
+
if (fromVar) {
|
|
254
|
+
tainted.set(left.text, `derived from tainted '${fromVar}'`);
|
|
255
|
+
changed = true;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Build the full taint map: initial sources + propagated chains.
|
|
263
|
+
* crossFileSources: optional function names from other files that return tainted data.
|
|
264
|
+
*/
|
|
265
|
+
export function buildTaintMap(rootNode, language, crossFileSources) {
|
|
266
|
+
const tainted = buildInitialTaintMap(rootNode, language, crossFileSources);
|
|
267
|
+
if (tainted.size > 0) {
|
|
268
|
+
propagateTaint(rootNode, tainted, language);
|
|
269
|
+
}
|
|
270
|
+
return tainted;
|
|
271
|
+
}
|
|
272
|
+
// ---- Taint-aware argument checking ----
|
|
273
|
+
/**
|
|
274
|
+
* Check if a call argument is or contains a tainted identifier from the taint map.
|
|
275
|
+
* Returns the tainted variable name if found, null otherwise.
|
|
276
|
+
*/
|
|
277
|
+
function argIsTainted(argNode, tainted) {
|
|
278
|
+
// Direct identifier: db.query(taintedVar)
|
|
279
|
+
if (argNode.type === 'identifier' && tainted.has(argNode.text)) {
|
|
280
|
+
return argNode.text;
|
|
281
|
+
}
|
|
282
|
+
// Any identifier within the arg expression
|
|
283
|
+
for (const identNode of findAllNodes(argNode, 'identifier')) {
|
|
284
|
+
if (tainted.has(identNode.text))
|
|
285
|
+
return identNode.text;
|
|
286
|
+
}
|
|
287
|
+
// Template substitution: `...${taintedVar}...`
|
|
288
|
+
for (const sub of findAllNodes(argNode, 'template_substitution')) {
|
|
289
|
+
for (const identNode of findAllNodes(sub, 'identifier')) {
|
|
290
|
+
if (tainted.has(identNode.text))
|
|
291
|
+
return identNode.text;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
const SINK_RULES = [
|
|
297
|
+
{
|
|
298
|
+
ruleId: 'OWASP-A03-001',
|
|
299
|
+
owasp: 'A03:2021',
|
|
300
|
+
severity: 'CRITICAL',
|
|
301
|
+
description: 'Direct user input in SQL query function',
|
|
302
|
+
jsMethods: new Set(['query', 'execute', 'raw', 'run', 'queryRawUnsafe', 'executemany']),
|
|
303
|
+
pyFunctionRe: /\b(?:execute|executemany|raw)\b/,
|
|
304
|
+
// Only check arg[0] (the SQL string). arg[1] is the parameter bindings array — safe by design.
|
|
305
|
+
taintArgIndex: 0,
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
ruleId: 'OWASP-A03-002',
|
|
309
|
+
owasp: 'A03:2021',
|
|
310
|
+
severity: 'CRITICAL',
|
|
311
|
+
description: 'Direct user input in shell execution function',
|
|
312
|
+
jsMethods: new Set(['exec', 'execSync', 'execFile', 'execFileSync', 'spawnSync']),
|
|
313
|
+
jsFunctions: new Set(['exec', 'execSync', 'execFile', 'spawnSync']),
|
|
314
|
+
pyFunctionRe: /\b(?:os\.system|subprocess\.(?:run|call|Popen|check_output|check_call)|commands\.getoutput)\b/,
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
ruleId: 'OWASP-A10-001',
|
|
318
|
+
owasp: 'A10:2021',
|
|
319
|
+
severity: 'HIGH',
|
|
320
|
+
description: 'Direct user input in HTTP fetch call (SSRF)',
|
|
321
|
+
jsFunctions: new Set(['fetch']),
|
|
322
|
+
jsMethods: new Set(['get', 'post', 'put', 'patch', 'delete', 'request']),
|
|
323
|
+
// Only match real HTTP clients — NOT Express/Koa router.get('/path', handler)
|
|
324
|
+
jsObjectFilter: /^(axios|http|https|got|superagent|agent|nodeFetch|node-fetch|ky|request|urllib)\b/i,
|
|
325
|
+
// Only check arg[0] (the URL). Without this, handler function bodies with `req` get flagged.
|
|
326
|
+
taintArgIndex: 0,
|
|
327
|
+
pyFunctionRe: /\b(?:requests\.(?:get|post|put|delete|request|head)|urllib\.request\.urlopen|urlopen)\b/,
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
ruleId: 'OWASP-A08-001',
|
|
331
|
+
owasp: 'A08:2021',
|
|
332
|
+
severity: 'CRITICAL',
|
|
333
|
+
description: 'Direct user input in eval() (code injection)',
|
|
334
|
+
jsFunctions: new Set(['eval']),
|
|
335
|
+
pyFunctionRe: /\b(?:eval|exec)\b/,
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
ruleId: 'OWASP-A03-005',
|
|
339
|
+
owasp: 'A03:2021',
|
|
340
|
+
severity: 'HIGH',
|
|
341
|
+
description: 'Direct user input in template render (SSTI)',
|
|
342
|
+
jsMethods: new Set(['render']),
|
|
343
|
+
pyFunctionRe: /\b(?:render_template_string|Template)\b/,
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
ruleId: 'OWASP-A01-002',
|
|
347
|
+
owasp: 'A01:2021',
|
|
348
|
+
severity: 'HIGH',
|
|
349
|
+
description: 'Direct user input used as file path (path traversal)',
|
|
350
|
+
jsMethods: new Set(['readFile', 'writeFile', 'readFileSync', 'writeFileSync', 'unlink', 'stat', 'open']),
|
|
351
|
+
pyFunctionRe: /\b(?:open|os\.path\.join|pathlib\.Path)\b/,
|
|
352
|
+
},
|
|
353
|
+
];
|
|
354
|
+
// ---- JS/TS call expression analysis ----
|
|
355
|
+
function analyzeJSCall(callNode, sourceLines, results, language, tainted) {
|
|
356
|
+
const funcNode = callNode.childForFieldName('function');
|
|
357
|
+
const argsNode = callNode.childForFieldName('arguments');
|
|
358
|
+
if (!funcNode || !argsNode)
|
|
359
|
+
return;
|
|
360
|
+
// Determine sink name
|
|
361
|
+
let sinkName = '';
|
|
362
|
+
let matchedSink;
|
|
363
|
+
if (funcNode.type === 'member_expression') {
|
|
364
|
+
const propNode = funcNode.childForFieldName('property') ??
|
|
365
|
+
funcNode.namedChild(funcNode.namedChildCount - 1);
|
|
366
|
+
if (propNode) {
|
|
367
|
+
sinkName = propNode.text;
|
|
368
|
+
matchedSink = SINK_RULES.find((r) => r.jsMethods?.has(sinkName));
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
else if (funcNode.type === 'identifier') {
|
|
372
|
+
sinkName = funcNode.text;
|
|
373
|
+
matchedSink = SINK_RULES.find((r) => r.jsFunctions?.has(sinkName));
|
|
374
|
+
}
|
|
375
|
+
if (!matchedSink)
|
|
376
|
+
return;
|
|
377
|
+
// If the sink requires the callee object to match a specific pattern (e.g. SSRF: only real
|
|
378
|
+
// HTTP clients, not Express router.get(path, handler)), enforce it here.
|
|
379
|
+
if (matchedSink.jsObjectFilter && funcNode.type === 'member_expression') {
|
|
380
|
+
const objectNode = funcNode.childForFieldName('object');
|
|
381
|
+
if (!objectNode || !matchedSink.jsObjectFilter.test(objectNode.text))
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
// Check each argument: direct user input OR tainted variable
|
|
385
|
+
// For sinks with taintArgIndex, only check that specific argument (e.g. SQL: arg[0] only)
|
|
386
|
+
const argsToCheck = matchedSink.taintArgIndex !== undefined
|
|
387
|
+
? [argsNode.namedChildren[matchedSink.taintArgIndex]].filter(Boolean)
|
|
388
|
+
: argsNode.namedChildren;
|
|
389
|
+
for (const arg of argsToCheck) {
|
|
390
|
+
const directHit = argContainsUserInput(arg, language);
|
|
391
|
+
const taintedVar = !directHit ? argIsTainted(arg, tainted) : null;
|
|
392
|
+
if (directHit || taintedVar) {
|
|
393
|
+
const line = callNode.startPosition.row + 1;
|
|
394
|
+
const taintInfo = taintedVar
|
|
395
|
+
? ` (tainted via '${taintedVar}': ${tainted.get(taintedVar).slice(0, 60)})`
|
|
396
|
+
: '';
|
|
397
|
+
results.push({
|
|
398
|
+
ruleId: matchedSink.ruleId,
|
|
399
|
+
owasp: matchedSink.owasp,
|
|
400
|
+
severity: matchedSink.severity,
|
|
401
|
+
description: matchedSink.description + taintInfo,
|
|
402
|
+
line,
|
|
403
|
+
column: callNode.startPosition.column + 1,
|
|
404
|
+
snippet: (sourceLines[line - 1] ?? callNode.text.slice(0, 120)).trim(),
|
|
405
|
+
argText: arg.text.slice(0, 120),
|
|
406
|
+
sinkName,
|
|
407
|
+
taintPath: taintedVar
|
|
408
|
+
? [`Source: '${taintedVar}' — ${tainted.get(taintedVar)}`, `Sink: ${sinkName}(${arg.text.slice(0, 60)})`]
|
|
409
|
+
: undefined,
|
|
410
|
+
});
|
|
411
|
+
break; // One finding per call
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
// Check if an argument node contains user input, structurally
|
|
416
|
+
function argContainsUserInput(argNode, language) {
|
|
417
|
+
// Direct user input reference (req.query.id, request.args.get('id'), etc.)
|
|
418
|
+
if (hasUserInput(argNode, language))
|
|
419
|
+
return true;
|
|
420
|
+
// String concatenation: "SELECT..." + req.query.id
|
|
421
|
+
if (argNode.type === 'binary_expression') {
|
|
422
|
+
for (const child of argNode.namedChildren) {
|
|
423
|
+
if (argContainsUserInput(child, language))
|
|
424
|
+
return true;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
// Template literal: `SELECT... ${req.query.id}`
|
|
428
|
+
if (argNode.type === 'template_string') {
|
|
429
|
+
for (const sub of findAllNodes(argNode, 'template_substitution')) {
|
|
430
|
+
if (hasUserInput(sub, language))
|
|
431
|
+
return true;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
// Python: f-string or binary operator
|
|
435
|
+
if (argNode.type === 'binary_operator' || argNode.type === 'concatenated_string') {
|
|
436
|
+
for (const child of argNode.namedChildren) {
|
|
437
|
+
if (argContainsUserInput(child, language))
|
|
438
|
+
return true;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
// Python: formatted string (f-string) — represented as `string` with interpolation nodes
|
|
442
|
+
if (argNode.type === 'string' && argNode.text.startsWith('f')) {
|
|
443
|
+
if (hasUserInput(argNode, language))
|
|
444
|
+
return true;
|
|
445
|
+
}
|
|
446
|
+
return false;
|
|
447
|
+
}
|
|
448
|
+
// ---- Python call expression analysis ----
|
|
449
|
+
function analyzePythonCall(callNode, sourceLines, results, tainted) {
|
|
450
|
+
const funcNode = callNode.childForFieldName('function');
|
|
451
|
+
const argsNode = callNode.childForFieldName('arguments');
|
|
452
|
+
if (!funcNode || !argsNode)
|
|
453
|
+
return;
|
|
454
|
+
const funcText = funcNode.text;
|
|
455
|
+
const matchedSink = SINK_RULES.find((r) => r.pyFunctionRe && r.pyFunctionRe.test(funcText));
|
|
456
|
+
if (!matchedSink)
|
|
457
|
+
return;
|
|
458
|
+
// Check arguments: direct user input OR tainted variable
|
|
459
|
+
// For sinks with taintArgIndex, only check that specific argument
|
|
460
|
+
const pyArgTarget = matchedSink.taintArgIndex !== undefined
|
|
461
|
+
? (argsNode.namedChildren[matchedSink.taintArgIndex] ?? argsNode)
|
|
462
|
+
: argsNode;
|
|
463
|
+
const directHit = argContainsUserInput(pyArgTarget, 'python');
|
|
464
|
+
const taintedVar = !directHit ? argIsTainted(pyArgTarget, tainted) : null;
|
|
465
|
+
if (directHit || taintedVar) {
|
|
466
|
+
const line = callNode.startPosition.row + 1;
|
|
467
|
+
const taintInfo = taintedVar
|
|
468
|
+
? ` (tainted via '${taintedVar}': ${tainted.get(taintedVar).slice(0, 60)})`
|
|
469
|
+
: '';
|
|
470
|
+
results.push({
|
|
471
|
+
ruleId: matchedSink.ruleId,
|
|
472
|
+
owasp: matchedSink.owasp,
|
|
473
|
+
severity: matchedSink.severity,
|
|
474
|
+
description: matchedSink.description + taintInfo,
|
|
475
|
+
line,
|
|
476
|
+
column: callNode.startPosition.column + 1,
|
|
477
|
+
snippet: (sourceLines[line - 1] ?? callNode.text.slice(0, 120)).trim(),
|
|
478
|
+
argText: argsNode.text.slice(0, 120),
|
|
479
|
+
sinkName: funcText,
|
|
480
|
+
taintPath: taintedVar
|
|
481
|
+
? [`Source: '${taintedVar}' — ${tainted.get(taintedVar)}`, `Sink: ${funcText}(${argsNode.text.slice(0, 60)})`]
|
|
482
|
+
: undefined,
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
// ---- Middleware-aware suppression ----
|
|
487
|
+
// Names that strongly suggest input validation/sanitization middleware
|
|
488
|
+
const VALIDATION_MIDDLEWARE_RE = /\b(?:validate|sanitize|check|verif(?:y|ied)|authenti(?:cat|c)|authori[sz]|protect|guard|permit|restrict|rateLimit|rateLimiter|helmet|csrf|xss|escape|clean(?:se|er)|strip|purif|dompurif)\w*\b/i;
|
|
489
|
+
/**
|
|
490
|
+
* Collect line numbers of route handler functions that are protected by
|
|
491
|
+
* a validation/auth middleware in their Express/Koa route definition.
|
|
492
|
+
*
|
|
493
|
+
* e.g.: router.get('/users', authenticate, validateInput, handler)
|
|
494
|
+
* → handler's body line numbers are "protected"
|
|
495
|
+
*
|
|
496
|
+
* Returns a Set of line numbers (1-based) that are inside protected handlers.
|
|
497
|
+
*/
|
|
498
|
+
function collectProtectedLines(rootNode) {
|
|
499
|
+
const protected_ = new Set();
|
|
500
|
+
for (const call of findAllNodes(rootNode, 'call_expression')) {
|
|
501
|
+
const func = call.childForFieldName('function');
|
|
502
|
+
const args = call.childForFieldName('arguments');
|
|
503
|
+
if (!func || !args)
|
|
504
|
+
continue;
|
|
505
|
+
// Match: router.get / app.post / router.use etc.
|
|
506
|
+
if (func.type !== 'member_expression')
|
|
507
|
+
continue;
|
|
508
|
+
const method = func.childForFieldName('property')?.text ?? '';
|
|
509
|
+
if (!/^(get|post|put|patch|delete|use|all)$/.test(method))
|
|
510
|
+
continue;
|
|
511
|
+
const argChildren = args.namedChildren;
|
|
512
|
+
if (argChildren.length < 2)
|
|
513
|
+
continue;
|
|
514
|
+
// Check if any non-last argument contains a validation middleware name
|
|
515
|
+
const middlewares = argChildren.slice(0, -1);
|
|
516
|
+
const hasValidationMiddleware = middlewares.some((m) => VALIDATION_MIDDLEWARE_RE.test(m.text));
|
|
517
|
+
if (!hasValidationMiddleware)
|
|
518
|
+
continue;
|
|
519
|
+
// The last argument is the route handler — mark all its lines as protected
|
|
520
|
+
const handler = argChildren[argChildren.length - 1];
|
|
521
|
+
if (!handler)
|
|
522
|
+
continue;
|
|
523
|
+
const startLine = handler.startPosition.row + 1;
|
|
524
|
+
const endLine = handler.endPosition.row + 1;
|
|
525
|
+
for (let ln = startLine; ln <= endLine; ln++) {
|
|
526
|
+
protected_.add(ln);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
return protected_;
|
|
530
|
+
}
|
|
531
|
+
// ---- Main export ----
|
|
532
|
+
/**
|
|
533
|
+
* Scan a parsed AST for vulnerabilities.
|
|
534
|
+
* Combines two detection modes:
|
|
535
|
+
* 1. Direct: user input appears directly in a sink argument
|
|
536
|
+
* 2. Taint: user input was assigned to a variable that reaches the sink
|
|
537
|
+
*
|
|
538
|
+
* The taint map is built via AST node traversal (not regex), so it is
|
|
539
|
+
* precise — handles destructuring, reassignment, template literals.
|
|
540
|
+
* Middleware-aware: handlers guarded by validate/auth middleware get LOW confidence.
|
|
541
|
+
*
|
|
542
|
+
* crossFileSources: optional map of function names from other scanned files that
|
|
543
|
+
* return tainted data (populated by the two-pass scanDirectory pre-pass).
|
|
544
|
+
*/
|
|
545
|
+
export function findVulnerableCalls(rootNode, language, sourceLines, crossFileSources) {
|
|
546
|
+
const results = [];
|
|
547
|
+
// Build AST-based taint map (sources + fixed-point propagation + cross-file sources)
|
|
548
|
+
const tainted = buildTaintMap(rootNode, language, crossFileSources);
|
|
549
|
+
// Collect lines inside middleware-protected route handlers (JS/TS only)
|
|
550
|
+
const protectedLines = (language === 'javascript' || language === 'typescript')
|
|
551
|
+
? collectProtectedLines(rootNode)
|
|
552
|
+
: new Set();
|
|
553
|
+
if (language === 'javascript' || language === 'typescript') {
|
|
554
|
+
for (const callNode of findAllNodes(rootNode, 'call_expression')) {
|
|
555
|
+
analyzeJSCall(callNode, sourceLines, results, language, tainted);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
else if (language === 'python') {
|
|
559
|
+
for (const callNode of findAllNodes(rootNode, 'call')) {
|
|
560
|
+
analyzePythonCall(callNode, sourceLines, results, tainted);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
// Downgrade confidence for findings inside middleware-protected handlers
|
|
564
|
+
for (const finding of results) {
|
|
565
|
+
if (protectedLines.has(finding.line)) {
|
|
566
|
+
finding.suppressedByMiddleware = true;
|
|
567
|
+
finding.description = finding.description + ' [middleware may sanitize this input]';
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
// Deduplicate by line + ruleId
|
|
571
|
+
const seen = new Set();
|
|
572
|
+
return results.filter((r) => {
|
|
573
|
+
const key = `${r.ruleId}:${r.line}`;
|
|
574
|
+
if (seen.has(key))
|
|
575
|
+
return false;
|
|
576
|
+
seen.add(key);
|
|
577
|
+
return true;
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
//# sourceMappingURL=ast-queries.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ast-queries.js","sourceRoot":"","sources":["../../src/parsers/ast-queries.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ScanResult } from '../types/index.js';
|
|
2
|
+
export interface ConsoleReporterOptions {
|
|
3
|
+
verbose: boolean;
|
|
4
|
+
noColor: boolean;
|
|
5
|
+
showFix: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare function reportConsole(result: ScanResult, options: ConsoleReporterOptions): void;
|
|
8
|
+
//# sourceMappingURL=console.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"console.d.ts","sourceRoot":"","sources":["../../src/reporter/console.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAqB,MAAM,mBAAmB,CAAC;AA+HvE,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,sBAAsB,GAAG,IAAI,CAuCvF"}
|