circle-ir 3.1.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/LICENSE +15 -0
- package/README.md +200 -0
- package/configs/sinks/code_injection.yaml +672 -0
- package/configs/sinks/command.yaml +917 -0
- package/configs/sinks/deserialization.yaml +105 -0
- package/configs/sinks/ldap.yaml +136 -0
- package/configs/sinks/nodejs.json +629 -0
- package/configs/sinks/path.yaml +715 -0
- package/configs/sinks/python.json +501 -0
- package/configs/sinks/rust.json +339 -0
- package/configs/sinks/sql.yaml +233 -0
- package/configs/sinks/ssrf.yaml +160 -0
- package/configs/sinks/xpath.yaml +121 -0
- package/configs/sinks/xss.yaml +727 -0
- package/configs/sources/db_sources.yaml +90 -0
- package/configs/sources/env_sources.yaml +94 -0
- package/configs/sources/express.json +197 -0
- package/configs/sources/file_sources.yaml +164 -0
- package/configs/sources/http_sources.yaml +379 -0
- package/configs/sources/io_sources.yaml +519 -0
- package/configs/sources/network_sources.yaml +99 -0
- package/configs/sources/python.json +230 -0
- package/configs/sources/rust.json +286 -0
- package/configs/sources/spring.yaml +70 -0
- package/dist/analysis/advisory-db.d.ts +86 -0
- package/dist/analysis/advisory-db.js +104 -0
- package/dist/analysis/advisory-db.js.map +1 -0
- package/dist/analysis/cargo-parser.d.ts +42 -0
- package/dist/analysis/cargo-parser.js +102 -0
- package/dist/analysis/cargo-parser.js.map +1 -0
- package/dist/analysis/config-loader.d.ts +37 -0
- package/dist/analysis/config-loader.js +1561 -0
- package/dist/analysis/config-loader.js.map +1 -0
- package/dist/analysis/constant-propagation/ast-utils.d.ts +25 -0
- package/dist/analysis/constant-propagation/ast-utils.js +34 -0
- package/dist/analysis/constant-propagation/ast-utils.js.map +1 -0
- package/dist/analysis/constant-propagation/evaluator.d.ts +32 -0
- package/dist/analysis/constant-propagation/evaluator.js +296 -0
- package/dist/analysis/constant-propagation/evaluator.js.map +1 -0
- package/dist/analysis/constant-propagation/index.d.ts +62 -0
- package/dist/analysis/constant-propagation/index.js +152 -0
- package/dist/analysis/constant-propagation/index.js.map +1 -0
- package/dist/analysis/constant-propagation/patterns.d.ts +8 -0
- package/dist/analysis/constant-propagation/patterns.js +126 -0
- package/dist/analysis/constant-propagation/patterns.js.map +1 -0
- package/dist/analysis/constant-propagation/propagator.d.ts +180 -0
- package/dist/analysis/constant-propagation/propagator.js +1985 -0
- package/dist/analysis/constant-propagation/propagator.js.map +1 -0
- package/dist/analysis/constant-propagation/types.d.ts +63 -0
- package/dist/analysis/constant-propagation/types.js +5 -0
- package/dist/analysis/constant-propagation/types.js.map +1 -0
- package/dist/analysis/constant-propagation.d.ts +9 -0
- package/dist/analysis/constant-propagation.js +18 -0
- package/dist/analysis/constant-propagation.js.map +1 -0
- package/dist/analysis/dependency-scanner.d.ts +79 -0
- package/dist/analysis/dependency-scanner.js +122 -0
- package/dist/analysis/dependency-scanner.js.map +1 -0
- package/dist/analysis/dfg-verifier.d.ts +116 -0
- package/dist/analysis/dfg-verifier.js +399 -0
- package/dist/analysis/dfg-verifier.js.map +1 -0
- package/dist/analysis/findings.d.ts +11 -0
- package/dist/analysis/findings.js +228 -0
- package/dist/analysis/findings.js.map +1 -0
- package/dist/analysis/index.d.ts +16 -0
- package/dist/analysis/index.js +18 -0
- package/dist/analysis/index.js.map +1 -0
- package/dist/analysis/interprocedural.d.ts +99 -0
- package/dist/analysis/interprocedural.js +526 -0
- package/dist/analysis/interprocedural.js.map +1 -0
- package/dist/analysis/path-finder.d.ts +133 -0
- package/dist/analysis/path-finder.js +354 -0
- package/dist/analysis/path-finder.js.map +1 -0
- package/dist/analysis/rules.d.ts +75 -0
- package/dist/analysis/rules.js +332 -0
- package/dist/analysis/rules.js.map +1 -0
- package/dist/analysis/semver.d.ts +27 -0
- package/dist/analysis/semver.js +127 -0
- package/dist/analysis/semver.js.map +1 -0
- package/dist/analysis/taint-matcher.d.ts +15 -0
- package/dist/analysis/taint-matcher.js +634 -0
- package/dist/analysis/taint-matcher.js.map +1 -0
- package/dist/analysis/taint-propagation.d.ts +67 -0
- package/dist/analysis/taint-propagation.js +298 -0
- package/dist/analysis/taint-propagation.js.map +1 -0
- package/dist/analysis/unresolved.d.ts +14 -0
- package/dist/analysis/unresolved.js +202 -0
- package/dist/analysis/unresolved.js.map +1 -0
- package/dist/analyzer.d.ts +43 -0
- package/dist/analyzer.js +1010 -0
- package/dist/analyzer.js.map +1 -0
- package/dist/browser/circle-ir.js +16576 -0
- package/dist/browser.d.ts +38 -0
- package/dist/browser.js +38 -0
- package/dist/browser.js.map +1 -0
- package/dist/core/circle-ir-core.cjs +13626 -0
- package/dist/core/circle-ir-core.d.ts +59 -0
- package/dist/core/circle-ir-core.js +13591 -0
- package/dist/core/extractors/calls.d.ts +13 -0
- package/dist/core/extractors/calls.js +1429 -0
- package/dist/core/extractors/calls.js.map +1 -0
- package/dist/core/extractors/cfg.d.ts +9 -0
- package/dist/core/extractors/cfg.js +519 -0
- package/dist/core/extractors/cfg.js.map +1 -0
- package/dist/core/extractors/dfg.d.ts +12 -0
- package/dist/core/extractors/dfg.js +1081 -0
- package/dist/core/extractors/dfg.js.map +1 -0
- package/dist/core/extractors/exports.d.ts +14 -0
- package/dist/core/extractors/exports.js +80 -0
- package/dist/core/extractors/exports.js.map +1 -0
- package/dist/core/extractors/imports.d.ts +9 -0
- package/dist/core/extractors/imports.js +739 -0
- package/dist/core/extractors/imports.js.map +1 -0
- package/dist/core/extractors/index.d.ts +10 -0
- package/dist/core/extractors/index.js +11 -0
- package/dist/core/extractors/index.js.map +1 -0
- package/dist/core/extractors/meta.d.ts +10 -0
- package/dist/core/extractors/meta.js +109 -0
- package/dist/core/extractors/meta.js.map +1 -0
- package/dist/core/extractors/types.d.ts +10 -0
- package/dist/core/extractors/types.js +1479 -0
- package/dist/core/extractors/types.js.map +1 -0
- package/dist/core/index.d.ts +5 -0
- package/dist/core/index.js +8 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/parser.d.ts +84 -0
- package/dist/core/parser.js +250 -0
- package/dist/core/parser.js.map +1 -0
- package/dist/core-lib.d.ts +59 -0
- package/dist/core-lib.js +62 -0
- package/dist/core-lib.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/languages/index.d.ts +11 -0
- package/dist/languages/index.js +14 -0
- package/dist/languages/index.js.map +1 -0
- package/dist/languages/plugins/base.d.ts +44 -0
- package/dist/languages/plugins/base.js +82 -0
- package/dist/languages/plugins/base.js.map +1 -0
- package/dist/languages/plugins/index.d.ts +14 -0
- package/dist/languages/plugins/index.js +25 -0
- package/dist/languages/plugins/index.js.map +1 -0
- package/dist/languages/plugins/java.d.ts +49 -0
- package/dist/languages/plugins/java.js +402 -0
- package/dist/languages/plugins/java.js.map +1 -0
- package/dist/languages/plugins/javascript.d.ts +48 -0
- package/dist/languages/plugins/javascript.js +445 -0
- package/dist/languages/plugins/javascript.js.map +1 -0
- package/dist/languages/plugins/python.d.ts +47 -0
- package/dist/languages/plugins/python.js +480 -0
- package/dist/languages/plugins/python.js.map +1 -0
- package/dist/languages/plugins/rust.d.ts +47 -0
- package/dist/languages/plugins/rust.js +405 -0
- package/dist/languages/plugins/rust.js.map +1 -0
- package/dist/languages/registry.d.ts +30 -0
- package/dist/languages/registry.js +80 -0
- package/dist/languages/registry.js.map +1 -0
- package/dist/languages/types.d.ts +184 -0
- package/dist/languages/types.js +8 -0
- package/dist/languages/types.js.map +1 -0
- package/dist/resolution/cross-file.d.ts +146 -0
- package/dist/resolution/cross-file.js +439 -0
- package/dist/resolution/cross-file.js.map +1 -0
- package/dist/resolution/index.d.ts +12 -0
- package/dist/resolution/index.js +10 -0
- package/dist/resolution/index.js.map +1 -0
- package/dist/resolution/symbol-table.d.ts +136 -0
- package/dist/resolution/symbol-table.js +336 -0
- package/dist/resolution/symbol-table.js.map +1 -0
- package/dist/resolution/type-hierarchy.d.ts +124 -0
- package/dist/resolution/type-hierarchy.js +515 -0
- package/dist/resolution/type-hierarchy.js.map +1 -0
- package/dist/types/config.d.ts +45 -0
- package/dist/types/config.js +5 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/index.d.ts +392 -0
- package/dist/types/index.js +7 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/logger.d.ts +85 -0
- package/dist/utils/logger.js +198 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/wasm/tree-sitter-java.wasm +0 -0
- package/dist/wasm/tree-sitter-javascript.wasm +0 -0
- package/dist/wasm/tree-sitter-python.wasm +0 -0
- package/dist/wasm/tree-sitter-rust.wasm +0 -0
- package/dist/wasm/web-tree-sitter.wasm +0 -0
- package/docs/SPEC.md +1021 -0
- package/examples/browser-example.html +610 -0
- package/examples/node-example.ts +215 -0
- package/package.json +107 -0
- package/wasm/tree-sitter-java.wasm +0 -0
- package/wasm/tree-sitter-javascript.wasm +0 -0
- package/wasm/tree-sitter-python.wasm +0 -0
- package/wasm/tree-sitter-rust.wasm +0 -0
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DFG Verifier - Track 2 validation using def-use chains
|
|
3
|
+
*
|
|
4
|
+
* Verifies that taint actually flows from source to sink by following
|
|
5
|
+
* the data flow graph. This provides a more precise validation than
|
|
6
|
+
* pattern matching alone.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* DFGVerifier - Verifies taint flows using def-use chains
|
|
10
|
+
*/
|
|
11
|
+
export class DFGVerifier {
|
|
12
|
+
dfg;
|
|
13
|
+
calls;
|
|
14
|
+
sanitizers;
|
|
15
|
+
config;
|
|
16
|
+
// Lookup maps
|
|
17
|
+
defById = new Map();
|
|
18
|
+
defsByLine = new Map();
|
|
19
|
+
defsByVar = new Map();
|
|
20
|
+
usesByDefId = new Map();
|
|
21
|
+
usesByLine = new Map();
|
|
22
|
+
callsByLine = new Map();
|
|
23
|
+
sanitizerLines = new Set();
|
|
24
|
+
// Chain lookup for faster traversal
|
|
25
|
+
chainsByFromDef = new Map();
|
|
26
|
+
constructor(dfg, calls, sanitizers, config = {}) {
|
|
27
|
+
this.dfg = dfg;
|
|
28
|
+
this.calls = calls;
|
|
29
|
+
this.sanitizers = sanitizers;
|
|
30
|
+
this.config = {
|
|
31
|
+
maxDepth: config.maxDepth ?? 30,
|
|
32
|
+
requireDirectFlow: config.requireDirectFlow ?? false,
|
|
33
|
+
allowFieldFlows: config.allowFieldFlows ?? true,
|
|
34
|
+
};
|
|
35
|
+
this.buildLookupMaps();
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Build lookup maps for efficient querying
|
|
39
|
+
*/
|
|
40
|
+
buildLookupMaps() {
|
|
41
|
+
for (const def of this.dfg.defs) {
|
|
42
|
+
this.defById.set(def.id, def);
|
|
43
|
+
const byLine = this.defsByLine.get(def.line) ?? [];
|
|
44
|
+
byLine.push(def);
|
|
45
|
+
this.defsByLine.set(def.line, byLine);
|
|
46
|
+
const byVar = this.defsByVar.get(def.variable) ?? [];
|
|
47
|
+
byVar.push(def);
|
|
48
|
+
this.defsByVar.set(def.variable, byVar);
|
|
49
|
+
}
|
|
50
|
+
for (const use of this.dfg.uses) {
|
|
51
|
+
const byLine = this.usesByLine.get(use.line) ?? [];
|
|
52
|
+
byLine.push(use);
|
|
53
|
+
this.usesByLine.set(use.line, byLine);
|
|
54
|
+
if (use.def_id !== null) {
|
|
55
|
+
const byDefId = this.usesByDefId.get(use.def_id) ?? [];
|
|
56
|
+
byDefId.push(use);
|
|
57
|
+
this.usesByDefId.set(use.def_id, byDefId);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
for (const call of this.calls) {
|
|
61
|
+
const byLine = this.callsByLine.get(call.location.line) ?? [];
|
|
62
|
+
byLine.push(call);
|
|
63
|
+
this.callsByLine.set(call.location.line, byLine);
|
|
64
|
+
}
|
|
65
|
+
for (const sanitizer of this.sanitizers) {
|
|
66
|
+
this.sanitizerLines.add(sanitizer.line);
|
|
67
|
+
}
|
|
68
|
+
// Build chain lookup
|
|
69
|
+
if (this.dfg.chains) {
|
|
70
|
+
for (const chain of this.dfg.chains) {
|
|
71
|
+
const byFromDef = this.chainsByFromDef.get(chain.from_def) ?? [];
|
|
72
|
+
byFromDef.push(chain);
|
|
73
|
+
this.chainsByFromDef.set(chain.from_def, byFromDef);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Verify if taint flows from source to sink
|
|
79
|
+
*/
|
|
80
|
+
verify(source, sink) {
|
|
81
|
+
// Find definitions at the source line
|
|
82
|
+
const sourceDefs = this.defsByLine.get(source.line) ?? [];
|
|
83
|
+
if (sourceDefs.length === 0) {
|
|
84
|
+
return {
|
|
85
|
+
verified: false,
|
|
86
|
+
confidence: 0,
|
|
87
|
+
reason: `No variable definition found at source line ${source.line}`,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
// Try to find a path from any source definition to the sink
|
|
91
|
+
const allPaths = [];
|
|
92
|
+
for (const sourceDef of sourceDefs) {
|
|
93
|
+
const path = this.findPath(sourceDef, sink);
|
|
94
|
+
if (path) {
|
|
95
|
+
allPaths.push(path);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (allPaths.length === 0) {
|
|
99
|
+
return {
|
|
100
|
+
verified: false,
|
|
101
|
+
confidence: 0.2, // Some confidence since pattern matched
|
|
102
|
+
reason: `No def-use chain found from source (line ${source.line}) to sink (line ${sink.line})`,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
// Find the best path (shortest, direct if possible)
|
|
106
|
+
const bestPath = this.selectBestPath(allPaths);
|
|
107
|
+
// Check for sanitizers in path
|
|
108
|
+
const sanitizerInPath = this.checkSanitizers(bestPath);
|
|
109
|
+
if (sanitizerInPath) {
|
|
110
|
+
return {
|
|
111
|
+
verified: false,
|
|
112
|
+
confidence: 0.1,
|
|
113
|
+
reason: `Flow sanitized at line ${sanitizerInPath.line} by ${sanitizerInPath.method}`,
|
|
114
|
+
path: bestPath,
|
|
115
|
+
alternativePaths: allPaths.length - 1,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
// Calculate confidence based on path characteristics
|
|
119
|
+
const confidence = this.calculateConfidence(bestPath);
|
|
120
|
+
return {
|
|
121
|
+
verified: true,
|
|
122
|
+
confidence,
|
|
123
|
+
reason: `Verified: ${bestPath.length}-step flow from line ${source.line} to line ${sink.line}`,
|
|
124
|
+
path: bestPath,
|
|
125
|
+
alternativePaths: allPaths.length - 1,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Find a path from a definition to a sink using BFS
|
|
130
|
+
*/
|
|
131
|
+
findPath(sourceDef, sink) {
|
|
132
|
+
const initialStep = {
|
|
133
|
+
defId: sourceDef.id,
|
|
134
|
+
variable: sourceDef.variable,
|
|
135
|
+
line: sourceDef.line,
|
|
136
|
+
kind: sourceDef.kind,
|
|
137
|
+
flowType: 'direct',
|
|
138
|
+
};
|
|
139
|
+
const queue = [{
|
|
140
|
+
def: sourceDef,
|
|
141
|
+
steps: [initialStep],
|
|
142
|
+
visited: new Set([sourceDef.id]),
|
|
143
|
+
}];
|
|
144
|
+
while (queue.length > 0) {
|
|
145
|
+
const state = queue.shift();
|
|
146
|
+
// Check depth limit
|
|
147
|
+
if (state.steps.length > this.config.maxDepth) {
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
// Check if current definition reaches the sink
|
|
151
|
+
if (this.reachesSink(state.def, sink)) {
|
|
152
|
+
return {
|
|
153
|
+
steps: state.steps,
|
|
154
|
+
length: state.steps.length,
|
|
155
|
+
hasDirectFlow: state.steps.every(s => s.flowType === 'direct' || s.flowType === 'assignment'),
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
// Explore via def-use chains (if available)
|
|
159
|
+
const chains = this.chainsByFromDef.get(state.def.id) ?? [];
|
|
160
|
+
for (const chain of chains) {
|
|
161
|
+
const nextDef = this.defById.get(chain.to_def);
|
|
162
|
+
if (!nextDef || state.visited.has(nextDef.id))
|
|
163
|
+
continue;
|
|
164
|
+
const step = {
|
|
165
|
+
defId: nextDef.id,
|
|
166
|
+
variable: nextDef.variable,
|
|
167
|
+
line: nextDef.line,
|
|
168
|
+
kind: nextDef.kind,
|
|
169
|
+
flowType: 'assignment',
|
|
170
|
+
};
|
|
171
|
+
const newVisited = new Set(state.visited);
|
|
172
|
+
newVisited.add(nextDef.id);
|
|
173
|
+
queue.push({
|
|
174
|
+
def: nextDef,
|
|
175
|
+
steps: [...state.steps, step],
|
|
176
|
+
visited: newVisited,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
// Explore via uses of the current definition
|
|
180
|
+
const uses = this.usesByDefId.get(state.def.id) ?? [];
|
|
181
|
+
for (const use of uses) {
|
|
182
|
+
// Find definitions at the use line
|
|
183
|
+
const nextDefs = this.defsByLine.get(use.line) ?? [];
|
|
184
|
+
for (const nextDef of nextDefs) {
|
|
185
|
+
if (state.visited.has(nextDef.id))
|
|
186
|
+
continue;
|
|
187
|
+
// Skip field flows if not allowed
|
|
188
|
+
if (!this.config.allowFieldFlows && nextDef.kind === 'field') {
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
const flowType = this.determineFlowType(state.def, nextDef, use.line);
|
|
192
|
+
const step = {
|
|
193
|
+
defId: nextDef.id,
|
|
194
|
+
variable: nextDef.variable,
|
|
195
|
+
line: nextDef.line,
|
|
196
|
+
kind: nextDef.kind,
|
|
197
|
+
flowType,
|
|
198
|
+
};
|
|
199
|
+
const newVisited = new Set(state.visited);
|
|
200
|
+
newVisited.add(nextDef.id);
|
|
201
|
+
queue.push({
|
|
202
|
+
def: nextDef,
|
|
203
|
+
steps: [...state.steps, step],
|
|
204
|
+
visited: newVisited,
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
// Explore same-variable definitions at later lines
|
|
209
|
+
const laterDefs = (this.defsByVar.get(state.def.variable) ?? [])
|
|
210
|
+
.filter(d => d.line > state.def.line && d.line <= sink.line && !state.visited.has(d.id))
|
|
211
|
+
.slice(0, 5); // Limit branching
|
|
212
|
+
for (const nextDef of laterDefs) {
|
|
213
|
+
const step = {
|
|
214
|
+
defId: nextDef.id,
|
|
215
|
+
variable: nextDef.variable,
|
|
216
|
+
line: nextDef.line,
|
|
217
|
+
kind: nextDef.kind,
|
|
218
|
+
flowType: 'assignment',
|
|
219
|
+
};
|
|
220
|
+
const newVisited = new Set(state.visited);
|
|
221
|
+
newVisited.add(nextDef.id);
|
|
222
|
+
queue.push({
|
|
223
|
+
def: nextDef,
|
|
224
|
+
steps: [...state.steps, step],
|
|
225
|
+
visited: newVisited,
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Check if a definition reaches a sink
|
|
233
|
+
*/
|
|
234
|
+
reachesSink(def, sink) {
|
|
235
|
+
// Check uses at sink line
|
|
236
|
+
const uses = this.usesByLine.get(sink.line) ?? [];
|
|
237
|
+
for (const use of uses) {
|
|
238
|
+
if (use.variable === def.variable || use.def_id === def.id) {
|
|
239
|
+
return true;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
// Check call arguments at sink line
|
|
243
|
+
const calls = this.callsByLine.get(sink.line) ?? [];
|
|
244
|
+
for (const call of calls) {
|
|
245
|
+
for (const arg of call.arguments) {
|
|
246
|
+
if (arg.variable === def.variable) {
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
// Check if definition is at or before sink line with same variable
|
|
252
|
+
if (def.line <= sink.line) {
|
|
253
|
+
const laterDefs = (this.defsByVar.get(def.variable) ?? [])
|
|
254
|
+
.filter(d => d.line > def.line && d.line <= sink.line);
|
|
255
|
+
// If no redefinition between def and sink, it reaches
|
|
256
|
+
if (laterDefs.length === 0) {
|
|
257
|
+
return true;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
return false;
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Determine the type of flow between two definitions
|
|
264
|
+
*/
|
|
265
|
+
determineFlowType(fromDef, toDef, useLine) {
|
|
266
|
+
// Check for call at the line
|
|
267
|
+
const calls = this.callsByLine.get(useLine) ?? [];
|
|
268
|
+
if (calls.length > 0) {
|
|
269
|
+
// If the variable changed, it's a return assignment
|
|
270
|
+
if (fromDef.variable !== toDef.variable) {
|
|
271
|
+
return 'return';
|
|
272
|
+
}
|
|
273
|
+
return 'call';
|
|
274
|
+
}
|
|
275
|
+
// Check for field access
|
|
276
|
+
if (toDef.kind === 'field') {
|
|
277
|
+
return 'field';
|
|
278
|
+
}
|
|
279
|
+
// Simple assignment
|
|
280
|
+
if (fromDef.variable === toDef.variable) {
|
|
281
|
+
return 'direct';
|
|
282
|
+
}
|
|
283
|
+
return 'assignment';
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Select the best path from multiple candidates
|
|
287
|
+
*/
|
|
288
|
+
selectBestPath(paths) {
|
|
289
|
+
// Prefer direct flows
|
|
290
|
+
const directPaths = paths.filter(p => p.hasDirectFlow);
|
|
291
|
+
if (directPaths.length > 0) {
|
|
292
|
+
return directPaths.reduce((a, b) => a.length <= b.length ? a : b);
|
|
293
|
+
}
|
|
294
|
+
// Otherwise, prefer shortest path
|
|
295
|
+
return paths.reduce((a, b) => a.length <= b.length ? a : b);
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Check if any sanitizer is in the path
|
|
299
|
+
*/
|
|
300
|
+
checkSanitizers(path) {
|
|
301
|
+
for (const step of path.steps) {
|
|
302
|
+
if (this.sanitizerLines.has(step.line)) {
|
|
303
|
+
return this.sanitizers.find(s => s.line === step.line) || null;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
return null;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Calculate confidence based on path characteristics
|
|
310
|
+
*/
|
|
311
|
+
calculateConfidence(path) {
|
|
312
|
+
let confidence = 0.9; // Base confidence for verified flow
|
|
313
|
+
// Bonus for direct flow
|
|
314
|
+
if (path.hasDirectFlow) {
|
|
315
|
+
confidence += 0.05;
|
|
316
|
+
}
|
|
317
|
+
// Penalty for long paths
|
|
318
|
+
if (path.length > 5) {
|
|
319
|
+
confidence -= 0.05;
|
|
320
|
+
}
|
|
321
|
+
if (path.length > 10) {
|
|
322
|
+
confidence -= 0.1;
|
|
323
|
+
}
|
|
324
|
+
// Penalty for field flows
|
|
325
|
+
const fieldSteps = path.steps.filter(s => s.flowType === 'field').length;
|
|
326
|
+
confidence -= fieldSteps * 0.05;
|
|
327
|
+
return Math.max(0.5, Math.min(1.0, confidence));
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Batch verify multiple source-sink pairs
|
|
331
|
+
*/
|
|
332
|
+
verifyAll(sources, sinks) {
|
|
333
|
+
const results = new Map();
|
|
334
|
+
for (const source of sources) {
|
|
335
|
+
for (const sink of sinks) {
|
|
336
|
+
const key = `${source.line}:${sink.line}`;
|
|
337
|
+
const result = this.verify(source, sink);
|
|
338
|
+
results.set(key, result);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
return results;
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Get verification statistics
|
|
345
|
+
*/
|
|
346
|
+
getStats(results) {
|
|
347
|
+
let verified = 0;
|
|
348
|
+
let notVerified = 0;
|
|
349
|
+
let sanitized = 0;
|
|
350
|
+
let totalConfidence = 0;
|
|
351
|
+
for (const result of results.values()) {
|
|
352
|
+
if (result.verified) {
|
|
353
|
+
verified++;
|
|
354
|
+
totalConfidence += result.confidence;
|
|
355
|
+
}
|
|
356
|
+
else if (result.reason.includes('sanitized')) {
|
|
357
|
+
sanitized++;
|
|
358
|
+
}
|
|
359
|
+
else {
|
|
360
|
+
notVerified++;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
return {
|
|
364
|
+
total: results.size,
|
|
365
|
+
verified,
|
|
366
|
+
notVerified,
|
|
367
|
+
sanitized,
|
|
368
|
+
avgConfidence: verified > 0 ? totalConfidence / verified : 0,
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Convenience function to verify a single flow
|
|
374
|
+
*/
|
|
375
|
+
export function verifyTaintFlow(dfg, calls, source, sink, sanitizers = [], config = {}) {
|
|
376
|
+
const verifier = new DFGVerifier(dfg, calls, sanitizers, config);
|
|
377
|
+
return verifier.verify(source, sink);
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Format verification result for display
|
|
381
|
+
*/
|
|
382
|
+
export function formatVerificationResult(result) {
|
|
383
|
+
const lines = [];
|
|
384
|
+
const status = result.verified ? '✓ VERIFIED' : '✗ NOT VERIFIED';
|
|
385
|
+
lines.push(`${status} (${Math.round(result.confidence * 100)}% confidence)`);
|
|
386
|
+
lines.push(`Reason: ${result.reason}`);
|
|
387
|
+
if (result.path) {
|
|
388
|
+
lines.push(`Path length: ${result.path.length} steps`);
|
|
389
|
+
lines.push('Steps:');
|
|
390
|
+
for (const step of result.path.steps) {
|
|
391
|
+
lines.push(` - Line ${step.line}: ${step.variable} (${step.flowType})`);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
if (result.alternativePaths && result.alternativePaths > 0) {
|
|
395
|
+
lines.push(`Alternative paths found: ${result.alternativePaths}`);
|
|
396
|
+
}
|
|
397
|
+
return lines.join('\n');
|
|
398
|
+
}
|
|
399
|
+
//# sourceMappingURL=dfg-verifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dfg-verifier.js","sourceRoot":"","sources":["../../src/analysis/dfg-verifier.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAqDH;;GAEG;AACH,MAAM,OAAO,WAAW;IACd,GAAG,CAAM;IACT,KAAK,CAAa;IAClB,UAAU,CAAmB;IAC7B,MAAM,CAA2B;IAEzC,cAAc;IACN,OAAO,GAAwB,IAAI,GAAG,EAAE,CAAC;IACzC,UAAU,GAA0B,IAAI,GAAG,EAAE,CAAC;IAC9C,SAAS,GAA0B,IAAI,GAAG,EAAE,CAAC;IAC7C,WAAW,GAA0B,IAAI,GAAG,EAAE,CAAC;IAC/C,UAAU,GAA0B,IAAI,GAAG,EAAE,CAAC;IAC9C,WAAW,GAA4B,IAAI,GAAG,EAAE,CAAC;IACjD,cAAc,GAAgB,IAAI,GAAG,EAAE,CAAC;IAEhD,oCAAoC;IAC5B,eAAe,GAA4B,IAAI,GAAG,EAAE,CAAC;IAE7D,YACE,GAAQ,EACR,KAAiB,EACjB,UAA4B,EAC5B,SAAyB,EAAE;QAE3B,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,MAAM,GAAG;YACZ,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,EAAE;YAC/B,iBAAiB,EAAE,MAAM,CAAC,iBAAiB,IAAI,KAAK;YACpD,eAAe,EAAE,MAAM,CAAC,eAAe,IAAI,IAAI;SAChD,CAAC;QAEF,IAAI,CAAC,eAAe,EAAE,CAAC;IACzB,CAAC;IAED;;OAEG;IACK,eAAe;QACrB,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;YAChC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;YAE9B,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YACnD,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACjB,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YAEtC,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;YACrD,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAChB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAC1C,CAAC;QAED,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;YAChC,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YACnD,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACjB,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YAEtC,IAAI,GAAG,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;gBACxB,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;gBACvD,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBAClB,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YAC5C,CAAC;QACH,CAAC;QAED,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC9B,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YAC9D,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClB,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACnD,CAAC;QAED,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACxC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAC1C,CAAC;QAED,qBAAqB;QACrB,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;YACpB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;gBACpC,MAAM,SAAS,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;gBACjE,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACtB,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;YACtD,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,MAAmB,EAAE,IAAe;QACzC,sCAAsC;QACtC,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAE1D,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5B,OAAO;gBACL,QAAQ,EAAE,KAAK;gBACf,UAAU,EAAE,CAAC;gBACb,MAAM,EAAE,+CAA+C,MAAM,CAAC,IAAI,EAAE;aACrE,CAAC;QACJ,CAAC;QAED,4DAA4D;QAC5D,MAAM,QAAQ,GAAuB,EAAE,CAAC;QAExC,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YACnC,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;YAC5C,IAAI,IAAI,EAAE,CAAC;gBACT,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACtB,CAAC;QACH,CAAC;QAED,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO;gBACL,QAAQ,EAAE,KAAK;gBACf,UAAU,EAAE,GAAG,EAAG,wCAAwC;gBAC1D,MAAM,EAAE,4CAA4C,MAAM,CAAC,IAAI,mBAAmB,IAAI,CAAC,IAAI,GAAG;aAC/F,CAAC;QACJ,CAAC;QAED,oDAAoD;QACpD,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;QAE/C,+BAA+B;QAC/B,MAAM,eAAe,GAAG,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;QACvD,IAAI,eAAe,EAAE,CAAC;YACpB,OAAO;gBACL,QAAQ,EAAE,KAAK;gBACf,UAAU,EAAE,GAAG;gBACf,MAAM,EAAE,0BAA0B,eAAe,CAAC,IAAI,OAAO,eAAe,CAAC,MAAM,EAAE;gBACrF,IAAI,EAAE,QAAQ;gBACd,gBAAgB,EAAE,QAAQ,CAAC,MAAM,GAAG,CAAC;aACtC,CAAC;QACJ,CAAC;QAED,qDAAqD;QACrD,MAAM,UAAU,GAAG,IAAI,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC;QAEtD,OAAO;YACL,QAAQ,EAAE,IAAI;YACd,UAAU;YACV,MAAM,EAAE,aAAa,QAAQ,CAAC,MAAM,wBAAwB,MAAM,CAAC,IAAI,YAAY,IAAI,CAAC,IAAI,EAAE;YAC9F,IAAI,EAAE,QAAQ;YACd,gBAAgB,EAAE,QAAQ,CAAC,MAAM,GAAG,CAAC;SACtC,CAAC;IACJ,CAAC;IAED;;OAEG;IACK,QAAQ,CAAC,SAAiB,EAAE,IAAe;QAOjD,MAAM,WAAW,GAAqB;YACpC,KAAK,EAAE,SAAS,CAAC,EAAE;YACnB,QAAQ,EAAE,SAAS,CAAC,QAAQ;YAC5B,IAAI,EAAE,SAAS,CAAC,IAAI;YACpB,IAAI,EAAE,SAAS,CAAC,IAAI;YACpB,QAAQ,EAAE,QAAQ;SACnB,CAAC;QAEF,MAAM,KAAK,GAAkB,CAAC;gBAC5B,GAAG,EAAE,SAAS;gBACd,KAAK,EAAE,CAAC,WAAW,CAAC;gBACpB,OAAO,EAAE,IAAI,GAAG,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;aACjC,CAAC,CAAC;QAEH,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,EAAG,CAAC;YAE7B,oBAAoB;YACpB,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;gBAC9C,SAAS;YACX,CAAC;YAED,+CAA+C;YAC/C,IAAI,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,CAAC;gBACtC,OAAO;oBACL,KAAK,EAAE,KAAK,CAAC,KAAK;oBAClB,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM;oBAC1B,aAAa,EAAE,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,CAAC,QAAQ,KAAK,YAAY,CAAC;iBAC9F,CAAC;YACJ,CAAC;YAED,4CAA4C;YAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;YAC5D,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;gBAC3B,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;gBAC/C,IAAI,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;oBAAE,SAAS;gBAExD,MAAM,IAAI,GAAqB;oBAC7B,KAAK,EAAE,OAAO,CAAC,EAAE;oBACjB,QAAQ,EAAE,OAAO,CAAC,QAAQ;oBAC1B,IAAI,EAAE,OAAO,CAAC,IAAI;oBAClB,IAAI,EAAE,OAAO,CAAC,IAAI;oBAClB,QAAQ,EAAE,YAAY;iBACvB,CAAC;gBAEF,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;gBAC1C,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;gBAE3B,KAAK,CAAC,IAAI,CAAC;oBACT,GAAG,EAAE,OAAO;oBACZ,KAAK,EAAE,CAAC,GAAG,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC;oBAC7B,OAAO,EAAE,UAAU;iBACpB,CAAC,CAAC;YACL,CAAC;YAED,6CAA6C;YAC7C,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;YACtD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;gBACvB,mCAAmC;gBACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;gBAErD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;oBAC/B,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;wBAAE,SAAS;oBAE5C,kCAAkC;oBAClC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,eAAe,IAAI,OAAO,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;wBAC7D,SAAS;oBACX,CAAC;oBAED,MAAM,QAAQ,GAAG,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;oBAEtE,MAAM,IAAI,GAAqB;wBAC7B,KAAK,EAAE,OAAO,CAAC,EAAE;wBACjB,QAAQ,EAAE,OAAO,CAAC,QAAQ;wBAC1B,IAAI,EAAE,OAAO,CAAC,IAAI;wBAClB,IAAI,EAAE,OAAO,CAAC,IAAI;wBAClB,QAAQ;qBACT,CAAC;oBAEF,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;oBAC1C,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;oBAE3B,KAAK,CAAC,IAAI,CAAC;wBACT,GAAG,EAAE,OAAO;wBACZ,KAAK,EAAE,CAAC,GAAG,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC;wBAC7B,OAAO,EAAE,UAAU;qBACpB,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;YAED,mDAAmD;YACnD,MAAM,SAAS,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;iBAC7D,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;iBACvF,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAE,kBAAkB;YAEnC,KAAK,MAAM,OAAO,IAAI,SAAS,EAAE,CAAC;gBAChC,MAAM,IAAI,GAAqB;oBAC7B,KAAK,EAAE,OAAO,CAAC,EAAE;oBACjB,QAAQ,EAAE,OAAO,CAAC,QAAQ;oBAC1B,IAAI,EAAE,OAAO,CAAC,IAAI;oBAClB,IAAI,EAAE,OAAO,CAAC,IAAI;oBAClB,QAAQ,EAAE,YAAY;iBACvB,CAAC;gBAEF,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;gBAC1C,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;gBAE3B,KAAK,CAAC,IAAI,CAAC;oBACT,GAAG,EAAE,OAAO;oBACZ,KAAK,EAAE,CAAC,GAAG,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC;oBAC7B,OAAO,EAAE,UAAU;iBACpB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACK,WAAW,CAAC,GAAW,EAAE,IAAe;QAC9C,0BAA0B;QAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAClD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,GAAG,CAAC,QAAQ,KAAK,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,CAAC,EAAE,EAAE,CAAC;gBAC3D,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QAED,oCAAoC;QACpC,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QACpD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;gBACjC,IAAI,GAAG,CAAC,QAAQ,KAAK,GAAG,CAAC,QAAQ,EAAE,CAAC;oBAClC,OAAO,IAAI,CAAC;gBACd,CAAC;YACH,CAAC;QACH,CAAC;QAED,mEAAmE;QACnE,IAAI,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YAC1B,MAAM,SAAS,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;iBACvD,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC;YAEzD,sDAAsD;YACtD,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC3B,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;OAEG;IACK,iBAAiB,CACvB,OAAe,EACf,KAAa,EACb,OAAe;QAEf,6BAA6B;QAC7B,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QAClD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACrB,oDAAoD;YACpD,IAAI,OAAO,CAAC,QAAQ,KAAK,KAAK,CAAC,QAAQ,EAAE,CAAC;gBACxC,OAAO,QAAQ,CAAC;YAClB,CAAC;YACD,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,yBAAyB;QACzB,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAC3B,OAAO,OAAO,CAAC;QACjB,CAAC;QAED,oBAAoB;QACpB,IAAI,OAAO,CAAC,QAAQ,KAAK,KAAK,CAAC,QAAQ,EAAE,CAAC;YACxC,OAAO,QAAQ,CAAC;QAClB,CAAC;QAED,OAAO,YAAY,CAAC;IACtB,CAAC;IAED;;OAEG;IACK,cAAc,CAAC,KAAyB;QAC9C,sBAAsB;QACtB,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;QACvD,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3B,OAAO,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACpE,CAAC;QAED,kCAAkC;QAClC,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9D,CAAC;IAED;;OAEG;IACK,eAAe,CAAC,IAAsB;QAC5C,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC9B,IAAI,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBACvC,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC;YACjE,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACK,mBAAmB,CAAC,IAAsB;QAChD,IAAI,UAAU,GAAG,GAAG,CAAC,CAAE,oCAAoC;QAE3D,wBAAwB;QACxB,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACvB,UAAU,IAAI,IAAI,CAAC;QACrB,CAAC;QAED,yBAAyB;QACzB,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpB,UAAU,IAAI,IAAI,CAAC;QACrB,CAAC;QACD,IAAI,IAAI,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;YACrB,UAAU,IAAI,GAAG,CAAC;QACpB,CAAC;QAED,0BAA0B;QAC1B,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,MAAM,CAAC;QACzE,UAAU,IAAI,UAAU,GAAG,IAAI,CAAC;QAEhC,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC,CAAC;IAClD,CAAC;IAED;;OAEG;IACH,SAAS,CACP,OAAsB,EACtB,KAAkB;QAElB,MAAM,OAAO,GAAG,IAAI,GAAG,EAA8B,CAAC;QAEtD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;gBACzC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;OAEG;IACH,QAAQ,CAAC,OAAwC;QAO/C,IAAI,QAAQ,GAAG,CAAC,CAAC;QACjB,IAAI,WAAW,GAAG,CAAC,CAAC;QACpB,IAAI,SAAS,GAAG,CAAC,CAAC;QAClB,IAAI,eAAe,GAAG,CAAC,CAAC;QAExB,KAAK,MAAM,MAAM,IAAI,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;YACtC,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;gBACpB,QAAQ,EAAE,CAAC;gBACX,eAAe,IAAI,MAAM,CAAC,UAAU,CAAC;YACvC,CAAC;iBAAM,IAAI,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;gBAC/C,SAAS,EAAE,CAAC;YACd,CAAC;iBAAM,CAAC;gBACN,WAAW,EAAE,CAAC;YAChB,CAAC;QACH,CAAC;QAED,OAAO;YACL,KAAK,EAAE,OAAO,CAAC,IAAI;YACnB,QAAQ;YACR,WAAW;YACX,SAAS;YACT,aAAa,EAAE,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,eAAe,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;SAC7D,CAAC;IACJ,CAAC;CACF;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAC7B,GAAQ,EACR,KAAiB,EACjB,MAAmB,EACnB,IAAe,EACf,aAA+B,EAAE,EACjC,SAAyB,EAAE;IAE3B,MAAM,QAAQ,GAAG,IAAI,WAAW,CAAC,GAAG,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;IACjE,OAAO,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AACvC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,wBAAwB,CAAC,MAA0B;IACjE,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,gBAAgB,CAAC;IACjE,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,KAAK,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,GAAG,GAAG,CAAC,eAAe,CAAC,CAAC;IAC7E,KAAK,CAAC,IAAI,CAAC,WAAW,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IAEvC,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;QAChB,KAAK,CAAC,IAAI,CAAC,gBAAgB,MAAM,CAAC,IAAI,CAAC,MAAM,QAAQ,CAAC,CAAC;QACvD,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACrB,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YACrC,KAAK,CAAC,IAAI,CAAC,YAAY,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC;QAC3E,CAAC;IACH,CAAC;IAED,IAAI,MAAM,CAAC,gBAAgB,IAAI,MAAM,CAAC,gBAAgB,GAAG,CAAC,EAAE,CAAC;QAC3D,KAAK,CAAC,IAAI,CAAC,4BAA4B,MAAM,CAAC,gBAAgB,EAAE,CAAC,CAAC;IACpE,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finding generator
|
|
3
|
+
*
|
|
4
|
+
* Combines taint sources, sinks, and data flow analysis to generate
|
|
5
|
+
* vulnerability findings with paths and remediation suggestions.
|
|
6
|
+
*/
|
|
7
|
+
import type { TaintSource, TaintSink, DFG, Finding } from '../types/index.js';
|
|
8
|
+
/**
|
|
9
|
+
* Generate vulnerability findings from taint analysis results.
|
|
10
|
+
*/
|
|
11
|
+
export declare function generateFindings(sources: TaintSource[], sinks: TaintSink[], dfg: DFG, fileName: string): Finding[];
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finding generator
|
|
3
|
+
*
|
|
4
|
+
* Combines taint sources, sinks, and data flow analysis to generate
|
|
5
|
+
* vulnerability findings with paths and remediation suggestions.
|
|
6
|
+
*/
|
|
7
|
+
import { calculateSeverity as calcSeverity, getRemediation, getSourceDescription, getSinkDescription, } from './rules.js';
|
|
8
|
+
/**
|
|
9
|
+
* Generate vulnerability findings from taint analysis results.
|
|
10
|
+
*/
|
|
11
|
+
export function generateFindings(sources, sinks, dfg, fileName) {
|
|
12
|
+
const findings = [];
|
|
13
|
+
let findingId = 1;
|
|
14
|
+
// For each source, find potential paths to sinks
|
|
15
|
+
for (const source of sources) {
|
|
16
|
+
for (const sink of sinks) {
|
|
17
|
+
// Check if this source type can reach this sink type
|
|
18
|
+
if (!canSourceReachSink(source.type, sink.type)) {
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
// Try to find a path through the DFG
|
|
22
|
+
const pathResult = findTaintPath(source, sink, dfg);
|
|
23
|
+
if (pathResult.pathExists || isProximityVulnerability(source, sink)) {
|
|
24
|
+
const severity = calcSeverity({
|
|
25
|
+
sourceType: source.type,
|
|
26
|
+
sinkType: sink.type,
|
|
27
|
+
pathExists: pathResult.pathExists,
|
|
28
|
+
});
|
|
29
|
+
const confidence = calculateConfidence(source, sink, pathResult);
|
|
30
|
+
findings.push({
|
|
31
|
+
id: `vuln${findingId++}`,
|
|
32
|
+
type: sink.type,
|
|
33
|
+
cwe: sink.cwe,
|
|
34
|
+
severity,
|
|
35
|
+
confidence,
|
|
36
|
+
source: {
|
|
37
|
+
file: fileName,
|
|
38
|
+
line: source.line,
|
|
39
|
+
code: source.location,
|
|
40
|
+
},
|
|
41
|
+
sink: {
|
|
42
|
+
file: fileName,
|
|
43
|
+
line: sink.line,
|
|
44
|
+
code: sink.location,
|
|
45
|
+
},
|
|
46
|
+
path: pathResult.hops.length > 0 ? pathResult.hops : undefined,
|
|
47
|
+
exploitable: pathResult.pathExists && confidence > 0.7,
|
|
48
|
+
explanation: generateExplanation(source, sink, pathResult),
|
|
49
|
+
remediation: getRemediation(sink.type),
|
|
50
|
+
verification: {
|
|
51
|
+
graph_path_exists: pathResult.pathExists,
|
|
52
|
+
llm_verified: false,
|
|
53
|
+
llm_confidence: 0,
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// Sort by severity and confidence
|
|
60
|
+
findings.sort((a, b) => {
|
|
61
|
+
const severityOrder = { critical: 0, high: 1, medium: 2, low: 3 };
|
|
62
|
+
const severityDiff = severityOrder[a.severity] - severityOrder[b.severity];
|
|
63
|
+
if (severityDiff !== 0)
|
|
64
|
+
return severityDiff;
|
|
65
|
+
return b.confidence - a.confidence;
|
|
66
|
+
});
|
|
67
|
+
return findings;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Check if a source type can potentially reach a sink type.
|
|
71
|
+
*/
|
|
72
|
+
function canSourceReachSink(sourceType, sinkType) {
|
|
73
|
+
const sourceToSinkMapping = {
|
|
74
|
+
http_param: ['sql_injection', 'command_injection', 'path_traversal', 'xss', 'xpath_injection', 'ldap_injection', 'ssrf'],
|
|
75
|
+
http_body: ['sql_injection', 'command_injection', 'deserialization', 'xxe', 'xss', 'code_injection'],
|
|
76
|
+
http_header: ['sql_injection', 'xss', 'ssrf'],
|
|
77
|
+
http_cookie: ['sql_injection', 'xss'],
|
|
78
|
+
http_path: ['path_traversal', 'sql_injection', 'ssrf'],
|
|
79
|
+
http_query: ['sql_injection', 'command_injection', 'xss', 'ssrf'],
|
|
80
|
+
io_input: ['command_injection', 'path_traversal', 'deserialization', 'xxe', 'code_injection', 'xss'],
|
|
81
|
+
env_input: ['command_injection', 'path_traversal'],
|
|
82
|
+
db_input: ['xss', 'sql_injection'], // Second-order injection
|
|
83
|
+
file_input: ['deserialization', 'xxe', 'path_traversal', 'command_injection', 'code_injection'],
|
|
84
|
+
network_input: ['sql_injection', 'command_injection', 'xss', 'ssrf'],
|
|
85
|
+
config_param: ['sql_injection', 'command_injection', 'path_traversal', 'xss', 'ssrf'], // Servlet init params
|
|
86
|
+
interprocedural_param: ['sql_injection', 'command_injection', 'path_traversal', 'xss', 'xpath_injection', 'ldap_injection', 'ssrf', 'code_injection'], // Cross-method taint
|
|
87
|
+
plugin_param: ['sql_injection', 'command_injection', 'path_traversal', 'xss', 'code_injection'], // Plugin/config parameters
|
|
88
|
+
};
|
|
89
|
+
const validSinks = sourceToSinkMapping[sourceType];
|
|
90
|
+
return validSinks ? validSinks.includes(sinkType) : false;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Find a taint path from source to sink through the DFG.
|
|
94
|
+
*/
|
|
95
|
+
function findTaintPath(source, sink, dfg) {
|
|
96
|
+
const hops = [];
|
|
97
|
+
const variables = [];
|
|
98
|
+
// Find definitions near the source line
|
|
99
|
+
const sourceDefs = dfg.defs.filter(d => d.line >= source.line - 1 && d.line <= source.line + 1);
|
|
100
|
+
// Find uses near the sink line
|
|
101
|
+
const sinkUses = dfg.uses.filter(u => u.line >= sink.line - 1 && u.line <= sink.line + 1);
|
|
102
|
+
if (sourceDefs.length === 0 || sinkUses.length === 0) {
|
|
103
|
+
return { pathExists: false, hops: [], variables: [] };
|
|
104
|
+
}
|
|
105
|
+
// Use DFG chains to find path
|
|
106
|
+
const chains = dfg.chains ?? [];
|
|
107
|
+
// Try to find a path from any source def to any sink use
|
|
108
|
+
for (const sourceDef of sourceDefs) {
|
|
109
|
+
for (const sinkUse of sinkUses) {
|
|
110
|
+
const path = findPathThroughChains(sourceDef.id, sinkUse.def_id, chains, dfg);
|
|
111
|
+
if (path.length > 0) {
|
|
112
|
+
// Build hops from path
|
|
113
|
+
for (const defId of path) {
|
|
114
|
+
const def = dfg.defs.find(d => d.id === defId);
|
|
115
|
+
if (def) {
|
|
116
|
+
hops.push({
|
|
117
|
+
file: '', // Will be filled by caller
|
|
118
|
+
method: '',
|
|
119
|
+
line: def.line,
|
|
120
|
+
code: `${def.variable} = ...`,
|
|
121
|
+
variable: def.variable,
|
|
122
|
+
});
|
|
123
|
+
variables.push(def.variable);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return { pathExists: true, hops, variables };
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// Fallback: check for simple proximity-based path
|
|
131
|
+
// If source and sink are close, there might be a direct flow
|
|
132
|
+
if (Math.abs(source.line - sink.line) <= 10) {
|
|
133
|
+
// Look for common variables
|
|
134
|
+
const sourceVars = new Set(sourceDefs.map(d => d.variable));
|
|
135
|
+
const sinkVars = new Set(sinkUses.map(u => u.variable));
|
|
136
|
+
for (const v of sourceVars) {
|
|
137
|
+
if (sinkVars.has(v)) {
|
|
138
|
+
hops.push({
|
|
139
|
+
file: '',
|
|
140
|
+
method: '',
|
|
141
|
+
line: source.line,
|
|
142
|
+
code: `${v} = <source>`,
|
|
143
|
+
variable: v,
|
|
144
|
+
});
|
|
145
|
+
hops.push({
|
|
146
|
+
file: '',
|
|
147
|
+
method: '',
|
|
148
|
+
line: sink.line,
|
|
149
|
+
code: `sink(${v})`,
|
|
150
|
+
variable: v,
|
|
151
|
+
});
|
|
152
|
+
variables.push(v);
|
|
153
|
+
return { pathExists: true, hops, variables };
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return { pathExists: false, hops: [], variables: [] };
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Find a path through DFG chains from source def to target def.
|
|
161
|
+
*/
|
|
162
|
+
function findPathThroughChains(fromDefId, toDefId, chains, dfg, visited = new Set(), path = []) {
|
|
163
|
+
if (toDefId === null)
|
|
164
|
+
return [];
|
|
165
|
+
if (fromDefId === toDefId)
|
|
166
|
+
return [...path, fromDefId];
|
|
167
|
+
if (visited.has(fromDefId))
|
|
168
|
+
return [];
|
|
169
|
+
visited.add(fromDefId);
|
|
170
|
+
path.push(fromDefId);
|
|
171
|
+
// Find chains that start from this def
|
|
172
|
+
const outgoingChains = chains.filter(c => c.from_def === fromDefId);
|
|
173
|
+
for (const chain of outgoingChains) {
|
|
174
|
+
const result = findPathThroughChains(chain.to_def, toDefId, chains, dfg, visited, [...path]);
|
|
175
|
+
if (result.length > 0) {
|
|
176
|
+
return result;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return [];
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Check if source and sink are close enough to suggest vulnerability.
|
|
183
|
+
*/
|
|
184
|
+
function isProximityVulnerability(source, sink) {
|
|
185
|
+
// Within same method (roughly 50 lines for complex functions)
|
|
186
|
+
return Math.abs(source.line - sink.line) <= 50;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Calculate confidence score.
|
|
190
|
+
*/
|
|
191
|
+
function calculateConfidence(source, sink, pathResult) {
|
|
192
|
+
let confidence = 0.5; // Base confidence
|
|
193
|
+
// Path exists: high confidence
|
|
194
|
+
if (pathResult.pathExists) {
|
|
195
|
+
confidence += 0.3;
|
|
196
|
+
}
|
|
197
|
+
// More hops = more confidence in the path
|
|
198
|
+
if (pathResult.hops.length > 0) {
|
|
199
|
+
confidence += Math.min(pathResult.hops.length * 0.05, 0.1);
|
|
200
|
+
}
|
|
201
|
+
// Source and sink confidence
|
|
202
|
+
confidence = confidence * source.confidence * sink.confidence;
|
|
203
|
+
// Proximity bonus
|
|
204
|
+
const lineDiff = Math.abs(source.line - sink.line);
|
|
205
|
+
if (lineDiff <= 5) {
|
|
206
|
+
confidence += 0.1;
|
|
207
|
+
}
|
|
208
|
+
else if (lineDiff <= 15) {
|
|
209
|
+
confidence += 0.05;
|
|
210
|
+
}
|
|
211
|
+
return Math.min(confidence, 1.0);
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Generate explanation for the finding.
|
|
215
|
+
*/
|
|
216
|
+
function generateExplanation(source, sink, pathResult) {
|
|
217
|
+
const sourceDesc = getSourceDescription(source.type);
|
|
218
|
+
const sinkDesc = getSinkDescription(sink.type);
|
|
219
|
+
if (pathResult.pathExists && pathResult.variables.length > 0) {
|
|
220
|
+
const vars = pathResult.variables.join(' -> ');
|
|
221
|
+
return `${sourceDesc} flows through variables (${vars}) to ${sinkDesc} without proper sanitization.`;
|
|
222
|
+
}
|
|
223
|
+
if (pathResult.pathExists) {
|
|
224
|
+
return `${sourceDesc} flows to ${sinkDesc} without proper sanitization.`;
|
|
225
|
+
}
|
|
226
|
+
return `${sourceDesc} may reach ${sinkDesc}. Manual verification recommended.`;
|
|
227
|
+
}
|
|
228
|
+
//# sourceMappingURL=findings.js.map
|