web3crit-scanner 7.0.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.
Files changed (42) hide show
  1. package/README.md +685 -0
  2. package/bin/web3crit +10 -0
  3. package/package.json +59 -0
  4. package/src/analyzers/control-flow.js +256 -0
  5. package/src/analyzers/data-flow.js +720 -0
  6. package/src/analyzers/exploit-chain.js +751 -0
  7. package/src/analyzers/immunefi-classifier.js +515 -0
  8. package/src/analyzers/poc-validator.js +396 -0
  9. package/src/analyzers/solodit-enricher.js +1122 -0
  10. package/src/cli.js +546 -0
  11. package/src/detectors/access-control-enhanced.js +458 -0
  12. package/src/detectors/base-detector.js +213 -0
  13. package/src/detectors/callback-reentrancy.js +362 -0
  14. package/src/detectors/cross-contract-reentrancy.js +697 -0
  15. package/src/detectors/delegatecall.js +167 -0
  16. package/src/detectors/deprecated-functions.js +62 -0
  17. package/src/detectors/flash-loan.js +408 -0
  18. package/src/detectors/frontrunning.js +553 -0
  19. package/src/detectors/gas-griefing.js +701 -0
  20. package/src/detectors/governance-attacks.js +366 -0
  21. package/src/detectors/integer-overflow.js +487 -0
  22. package/src/detectors/oracle-manipulation.js +524 -0
  23. package/src/detectors/permit-exploits.js +368 -0
  24. package/src/detectors/precision-loss.js +408 -0
  25. package/src/detectors/price-manipulation-advanced.js +548 -0
  26. package/src/detectors/proxy-vulnerabilities.js +651 -0
  27. package/src/detectors/readonly-reentrancy.js +473 -0
  28. package/src/detectors/rebasing-token-vault.js +416 -0
  29. package/src/detectors/reentrancy-enhanced.js +359 -0
  30. package/src/detectors/selfdestruct.js +259 -0
  31. package/src/detectors/share-manipulation.js +412 -0
  32. package/src/detectors/signature-replay.js +409 -0
  33. package/src/detectors/storage-collision.js +446 -0
  34. package/src/detectors/timestamp-dependence.js +494 -0
  35. package/src/detectors/toctou.js +427 -0
  36. package/src/detectors/token-standard-compliance.js +465 -0
  37. package/src/detectors/unchecked-call.js +214 -0
  38. package/src/detectors/vault-inflation.js +421 -0
  39. package/src/index.js +42 -0
  40. package/src/package-lock.json +2874 -0
  41. package/src/package.json +39 -0
  42. package/src/scanner-enhanced.js +816 -0
@@ -0,0 +1,167 @@
1
+ const BaseDetector = require('./base-detector');
2
+
3
+ class DelegateCallDetector extends BaseDetector {
4
+ constructor() {
5
+ super(
6
+ 'Dangerous Delegatecall',
7
+ 'Detects unsafe delegatecall usage that could lead to contract takeover',
8
+ 'CRITICAL'
9
+ );
10
+ }
11
+
12
+ visitFunctionCall(node) {
13
+ const code = this.getCodeSnippet(node.loc);
14
+
15
+ if (code.includes('delegatecall(')) {
16
+ this.checkDelegatecall(node, code);
17
+ }
18
+ }
19
+
20
+ checkDelegatecall(node, code) {
21
+ const codeLower = code.toLowerCase();
22
+
23
+ // Skip delegatecall in fallback/receive functions with assembly (standard proxy pattern)
24
+ if (codeLower.includes('fallback') || codeLower.includes('receive')) {
25
+ if (codeLower.includes('assembly') || codeLower.includes('calldatacopy')) {
26
+ // This is a standard proxy pattern - check if implementation is validated
27
+ const funcCode = this.getCodeSnippet(node.loc);
28
+ if (funcCode && (funcCode.includes('require') && funcCode.includes('implementation'))) {
29
+ return; // Secure proxy pattern
30
+ }
31
+ // Also check if it's in a function that validates implementation
32
+ if (this.hasWhitelistValidation(node)) {
33
+ return; // Has validation
34
+ }
35
+ }
36
+ }
37
+
38
+ // Check if delegatecall target is controlled by user input
39
+ if (this.hasUserControlledTarget(node, code)) {
40
+ // Check if there's whitelist validation in the function
41
+ if (!this.hasWhitelistValidation(node)) {
42
+ this.addFinding({
43
+ title: 'User-Controlled Delegatecall',
44
+ description: 'Delegatecall is made to a user-controlled address. This allows attackers to execute arbitrary code in the context of this contract, potentially taking full control.',
45
+ location: this.getLocationString(node.loc),
46
+ line: node.loc ? node.loc.start.line : 0,
47
+ column: node.loc ? node.loc.start.column : 0,
48
+ code: code,
49
+ recommendation: 'Never allow user input to control delegatecall targets. Use a whitelist of trusted contract addresses or avoid delegatecall entirely.',
50
+ references: [
51
+ 'https://swcregistry.io/docs/SWC-112',
52
+ 'https://blog.openzeppelin.com/on-the-parity-wallet-multisig-hack-405a8c12e8f7'
53
+ ]
54
+ });
55
+ }
56
+ }
57
+
58
+ // Check if return value is checked
59
+ if (!this.isReturnValueChecked(node)) {
60
+ this.addFinding({
61
+ title: 'Unchecked Delegatecall Return Value',
62
+ description: 'Delegatecall return value is not checked. Failed delegatecalls will be silently ignored.',
63
+ location: this.getLocationString(node.loc),
64
+ line: node.loc ? node.loc.start.line : 0,
65
+ column: node.loc ? node.loc.start.column : 0,
66
+ code: code,
67
+ recommendation: 'Always check delegatecall return value: (bool success, ) = target.delegatecall(...); require(success, "Delegatecall failed");',
68
+ references: [
69
+ 'https://swcregistry.io/docs/SWC-104'
70
+ ]
71
+ });
72
+ }
73
+ }
74
+
75
+ hasWhitelistValidation(node) {
76
+ // Check if the function containing this delegatecall has whitelist validation
77
+ // Look for patterns like: require(trustedAddresses[target], ...) or require(isApproved[target], ...)
78
+ const lineNum = node.loc ? node.loc.start.line : 0;
79
+ const funcCode = this.getCodeSnippet(node.loc);
80
+
81
+ // Check the function code for whitelist patterns
82
+ const whitelistPatterns = [
83
+ /require\s*\(\s*[^)]*\b(trusted|approved|whitelist|allowed|authorized)\w*\[/i,
84
+ /require\s*\(\s*[^)]*\b(trusted|approved|whitelist|allowed|authorized)\w*\s*\(/i,
85
+ /mapping\s*\([^)]*\)\s*public\s*(trusted|approved|whitelist|allowed)/i,
86
+ /trustedImplementations\[/i,
87
+ /approvedImplementations\[/i
88
+ ];
89
+
90
+ if (whitelistPatterns.some(pattern => pattern.test(funcCode))) {
91
+ return true;
92
+ }
93
+
94
+ // Check a few lines before the delegatecall for validation
95
+ for (let i = Math.max(1, lineNum - 10); i < lineNum; i++) {
96
+ const line = this.getLineContent(i);
97
+ // Look for whitelist patterns
98
+ if (whitelistPatterns.some(pattern => pattern.test(line))) {
99
+ return true;
100
+ }
101
+ }
102
+
103
+ return false;
104
+ }
105
+
106
+ hasUserControlledTarget(node, code) {
107
+ // Check for common patterns of user-controlled addresses
108
+ if (node.expression && node.expression.type === 'MemberAccess') {
109
+ const target = node.expression.expression;
110
+
111
+ if (target) {
112
+ // Check if target is a parameter, msg.sender related, or mapping access
113
+ if (target.type === 'Identifier') {
114
+ const targetCode = this.getCodeSnippet(target.loc);
115
+
116
+ // Check if it looks like a function parameter or user-influenced variable
117
+ if (targetCode.includes('_') || // Common parameter naming
118
+ this.looksLikeFunctionParameter(targetCode)) {
119
+ return true;
120
+ }
121
+ }
122
+
123
+ // Check if accessing mapping or array with user input
124
+ if (target.type === 'IndexAccess') {
125
+ return true;
126
+ }
127
+ }
128
+ }
129
+
130
+ // Check if the delegatecall includes parameters that might be user-controlled
131
+ if (code.match(/delegatecall\([^)]*\b(msg\.sender|_\w+|\w+\[\w+\])/)) {
132
+ return true;
133
+ }
134
+
135
+ return false;
136
+ }
137
+
138
+ looksLikeFunctionParameter(code) {
139
+ // Simple heuristic: parameters often start with underscore or are simple names
140
+ return code.startsWith('_') ||
141
+ code === 'target' ||
142
+ code === 'destination' ||
143
+ code === 'implementation' ||
144
+ code === 'logic';
145
+ }
146
+
147
+ isReturnValueChecked(node) {
148
+ // This is a simplified check - would need parent context analysis for full accuracy
149
+ // We'll look for assignment to variable or usage in require/if
150
+
151
+ // Check if the node is part of an assignment
152
+ // This is difficult without parent reference, so we'll check the surrounding code
153
+ const line = this.getLineContent(node.loc ? node.loc.start.line : 0);
154
+
155
+ return line.includes('bool') ||
156
+ line.includes('success') ||
157
+ line.includes('require(') ||
158
+ line.includes('if (');
159
+ }
160
+
161
+ getLocationString(loc) {
162
+ if (!loc || !loc.start) return 'Unknown';
163
+ return `Line ${loc.start.line}, Column ${loc.start.column}`;
164
+ }
165
+ }
166
+
167
+ module.exports = DelegateCallDetector;
@@ -0,0 +1,62 @@
1
+ const BaseDetector = require('./base-detector');
2
+
3
+ /**
4
+ * Detector for deprecated functions
5
+ *
6
+ * This detector finds usage of deprecated functions like `tx.origin` for authorization,
7
+ * `selfdestruct` (in favor of CREATE2), and other patterns that are discouraged.
8
+ */
9
+ class DeprecatedFunctionsDetector extends BaseDetector {
10
+ constructor() {
11
+ super(
12
+ 'Deprecated Functions',
13
+ 'Finds usage of deprecated or discouraged Solidity functions and patterns',
14
+ 'LOW' // Default severity
15
+ );
16
+
17
+ this.deprecatedPatterns = {
18
+ 'tx.origin': {
19
+ severity: 'HIGH',
20
+ description: 'Authorization using tx.origin is insecure and can be exploited by phishing attacks.',
21
+ confidence: 'HIGH'
22
+ },
23
+ selfdestruct: {
24
+ severity: 'MEDIUM',
25
+ description:
26
+ 'selfdestruct is discouraged. Consider using CREATE2 for contract removal or disabling the contract instead.',
27
+ confidence: 'MEDIUM'
28
+ },
29
+ 'block.timestamp': {
30
+ severity: 'LOW',
31
+ description:
32
+ 'block.timestamp can be manipulated by miners. Do not rely on it for critical logic or entropy.',
33
+ confidence: 'LOW'
34
+ }
35
+ };
36
+ }
37
+
38
+ visitMemberAccess(node) {
39
+ const expression = this.getSourceFromNode(node);
40
+ if (this.deprecatedPatterns[expression]) {
41
+ const { severity, description, confidence } = this.deprecatedPatterns[expression];
42
+ this.addFinding({
43
+ title: `Usage of deprecated or insecure pattern: ${expression}`,
44
+ description: description,
45
+ severity: severity,
46
+ confidence: confidence,
47
+ location: node.loc,
48
+ line: node.loc.start.line,
49
+ column: node.loc.start.column,
50
+ code: this.getCodeSnippet(node.loc)
51
+ });
52
+ }
53
+ }
54
+
55
+ // Helper to get source from a node
56
+ getSourceFromNode(node) {
57
+ if (!node || !node.range || !this.sourceCode) return '';
58
+ return this.sourceCode.substring(node.range[0], node.range[1] + 1);
59
+ }
60
+ }
61
+
62
+ module.exports = DeprecatedFunctionsDetector;
@@ -0,0 +1,408 @@
1
+ const BaseDetector = require('./base-detector');
2
+
3
+ /**
4
+ * Flash Loan Attack Pattern Detector (Enhanced)
5
+ * Detects patterns vulnerable to flash loan manipulation with context awareness
6
+ * to reduce false positives and classify real exploitable issues.
7
+ */
8
+ class FlashLoanDetector extends BaseDetector {
9
+ constructor() {
10
+ super(
11
+ 'Flash Loan Vulnerability',
12
+ 'Detects patterns vulnerable to flash loan attacks',
13
+ 'CRITICAL'
14
+ );
15
+ this.currentContract = null;
16
+ this.currentFunction = null;
17
+ this.currentFunctionNode = null;
18
+ this.cfg = null;
19
+ this.balanceUsages = [];
20
+ this.priceCalculations = [];
21
+ this.valueFlows = [];
22
+ }
23
+
24
+ async detect(ast, sourceCode, fileName, cfg, dataFlow) {
25
+ this.findings = [];
26
+ this.ast = ast;
27
+ this.sourceCode = sourceCode;
28
+ this.fileName = fileName;
29
+ this.sourceLines = sourceCode.split('\n');
30
+ this.cfg = cfg;
31
+ this.dataFlow = dataFlow;
32
+
33
+ this.traverse(ast);
34
+
35
+ return this.findings;
36
+ }
37
+
38
+ visitContractDefinition(node) {
39
+ this.currentContract = node.name;
40
+ // Reset per-contract tracking
41
+ this.balanceUsages = [];
42
+ this.priceCalculations = [];
43
+ }
44
+
45
+ visitFunctionDefinition(node) {
46
+ this.currentFunction = node.name || 'constructor';
47
+ this.currentFunctionNode = node;
48
+
49
+ // Reset per-function tracking
50
+ this.functionBalanceUsages = [];
51
+ this.functionDivisions = [];
52
+ this.functionExternalCalls = [];
53
+
54
+ // Analyze the full function for flash loan patterns
55
+ if (node.body) {
56
+ this.deepAnalyzeFunction(node);
57
+ }
58
+ }
59
+
60
+ /**
61
+ * Deep analysis of function to find actual exploitable flash loan patterns
62
+ * Only flags when: balance/reserves → division/calculation → value transfer/minting
63
+ */
64
+ deepAnalyzeFunction(funcNode) {
65
+ const funcCode = this.getCodeSnippet(funcNode.loc);
66
+ const funcCodeLower = funcCode.toLowerCase();
67
+
68
+ // Skip internal/private functions (not directly exploitable)
69
+ if (funcNode.visibility === 'private' || funcNode.visibility === 'internal') {
70
+ return;
71
+ }
72
+
73
+ // Skip view/pure functions (can't cause direct fund loss)
74
+ if (funcNode.stateMutability === 'view' || funcNode.stateMutability === 'pure') {
75
+ return;
76
+ }
77
+
78
+ // Check for known safe patterns that should be excluded
79
+ if (this.hasSafeGuards(funcCode)) {
80
+ return;
81
+ }
82
+
83
+ // Pattern 1: Spot price oracle for value calculations (HIGH confidence)
84
+ const spotPricePattern = this.detectSpotPriceOracle(funcCode, funcNode);
85
+
86
+ // Pattern 2: Balance-based pricing (MEDIUM-HIGH confidence depending on context)
87
+ const balancePricingPattern = this.detectBalanceBasedPricing(funcCode, funcNode);
88
+
89
+ // Pattern 3: Reserve ratio manipulation (HIGH confidence)
90
+ const reserveManipPattern = this.detectReserveManipulation(funcCode, funcNode);
91
+ }
92
+
93
+ /**
94
+ * Check for safe guards that mitigate flash loan attacks
95
+ */
96
+ hasSafeGuards(code) {
97
+ const safePatterns = [
98
+ // TWAP oracles
99
+ /observe\s*\(/i,
100
+ /consult\s*\(/i,
101
+ /twap/i,
102
+ /timeWeightedAverage/i,
103
+ // Chainlink oracles
104
+ /latestRoundData/i,
105
+ /priceFeed/i,
106
+ /AggregatorV3/i,
107
+ // Multi-block checks
108
+ /block\.number\s*-/i,
109
+ /previousBlock/i,
110
+ /lastUpdateBlock/i,
111
+ // Flash loan callbacks that indicate awareness
112
+ /onFlashLoan/i,
113
+ /flashLoanCallback/i,
114
+ // Internal accounting (safe pattern)
115
+ /internalBalance/i,
116
+ /_balance\[/i,
117
+ /balances\[/i,
118
+ ];
119
+
120
+ return safePatterns.some(pattern => pattern.test(code));
121
+ }
122
+
123
+ /**
124
+ * Detect spot price oracle usage that flows into value calculations
125
+ */
126
+ detectSpotPriceOracle(code, funcNode) {
127
+ // High-risk spot price functions
128
+ // Note: Don't use /g flag with test() as it causes stateful behavior
129
+ const spotPricePatterns = [
130
+ { pattern: /\.getReserves\s*\(\s*\)/, name: 'getReserves' },
131
+ { pattern: /\.getAmountsOut\s*\(/, name: 'getAmountsOut' },
132
+ { pattern: /\.getAmountOut\s*\(/, name: 'getAmountOut' },
133
+ { pattern: /\.getAmountsIn\s*\(/, name: 'getAmountsIn' },
134
+ { pattern: /\.quote\s*\(/, name: 'quote' },
135
+ ];
136
+
137
+ for (const { pattern, name } of spotPricePatterns) {
138
+ if (pattern.test(code)) {
139
+ // Check if result flows into value-affecting operations
140
+ const flowsToValue = this.checkValueFlow(code, name);
141
+
142
+ if (flowsToValue.isExploitable) {
143
+ this.addFinding({
144
+ title: 'Spot Price Oracle Manipulation',
145
+ description: `Function uses '${name}()' for price calculation which can be manipulated in a single transaction via flash loans. ${flowsToValue.reason}`,
146
+ location: `Contract: ${this.currentContract}, Function: ${this.currentFunction}`,
147
+ line: funcNode.loc ? funcNode.loc.start.line : 0,
148
+ column: funcNode.loc ? funcNode.loc.start.column : 0,
149
+ code: this.extractRelevantCode(code, name),
150
+ severity: 'CRITICAL',
151
+ confidence: 'HIGH',
152
+ exploitable: true,
153
+ exploitabilityScore: 85,
154
+ attackVector: 'flash-loan-oracle-manipulation',
155
+ recommendation: 'Replace spot price oracle with TWAP oracle (Uniswap V3 observe()) or Chainlink price feeds (latestRoundData). Never use single-block prices for value calculations.',
156
+ references: [
157
+ 'https://docs.chain.link/data-feeds',
158
+ 'https://docs.uniswap.org/concepts/protocol/oracle',
159
+ 'https://www.paradigm.xyz/2020/11/so-you-want-to-use-a-price-oracle'
160
+ ],
161
+ foundryPoC: this.generateSpotPricePoC(name, this.currentContract, this.currentFunction)
162
+ });
163
+ return true;
164
+ }
165
+ }
166
+ }
167
+ return false;
168
+ }
169
+
170
+ /**
171
+ * Detect balance-based pricing that could be manipulated
172
+ */
173
+ detectBalanceBasedPricing(code, funcNode) {
174
+ // Only flag if balance is used in division for pricing
175
+ const balanceInDivision = /(?:balanceOf|\.balance)[^;]*\/[^;]*|[^;]*\/[^;]*(?:balanceOf|\.balance)/gi;
176
+
177
+ if (!balanceInDivision.test(code)) {
178
+ return false;
179
+ }
180
+
181
+ // Check if this affects value transfers or minting
182
+ const valueAffecting = [
183
+ /\.transfer\s*\(/i,
184
+ /\.call\s*\{.*value/i,
185
+ /\.mint\s*\(/i,
186
+ /\.burn\s*\(/i,
187
+ /safeTransfer/i,
188
+ /_mint\s*\(/i,
189
+ /_burn\s*\(/i,
190
+ ];
191
+
192
+ const affectsValue = valueAffecting.some(pattern => pattern.test(code));
193
+
194
+ if (!affectsValue) {
195
+ // Balance used but doesn't affect value - likely internal accounting
196
+ return false;
197
+ }
198
+
199
+ // Check for price/rate/ratio context
200
+ const pricingContext = /(?:price|rate|ratio|exchange|collateral|liquidat)/i.test(code);
201
+
202
+ if (pricingContext) {
203
+ this.addFinding({
204
+ title: 'Balance-Based Pricing Vulnerable to Flash Loan',
205
+ description: `Function calculates price/rate using real-time balance which can be manipulated via flash loans, donations, or selfdestruct. The calculated value affects token transfers or minting.`,
206
+ location: `Contract: ${this.currentContract}, Function: ${this.currentFunction}`,
207
+ line: funcNode.loc ? funcNode.loc.start.line : 0,
208
+ column: funcNode.loc ? funcNode.loc.start.column : 0,
209
+ code: this.extractRelevantCode(code, 'balance'),
210
+ severity: 'HIGH',
211
+ confidence: 'HIGH',
212
+ exploitable: true,
213
+ exploitabilityScore: 75,
214
+ attackVector: 'flash-loan-balance-manipulation',
215
+ recommendation: 'Use internal balance tracking instead of actual balances. Implement deposit/withdraw pattern with state variables. Consider using TWAP for any pricing logic.',
216
+ references: [
217
+ 'https://swcregistry.io/docs/SWC-132',
218
+ 'https://consensys.github.io/smart-contract-best-practices/attacks/oracle-manipulation/'
219
+ ],
220
+ foundryPoC: this.generateBalanceManipulationPoC(this.currentContract, this.currentFunction)
221
+ });
222
+ return true;
223
+ }
224
+
225
+ return false;
226
+ }
227
+
228
+ /**
229
+ * Detect reserve ratio manipulation patterns
230
+ */
231
+ detectReserveManipulation(code, funcNode) {
232
+ // Pattern: reserve0 / reserve1 or similar calculations
233
+ const reserveRatio = /reserve[0-9]?\s*[*/]\s*reserve[0-9]?/gi;
234
+
235
+ if (!reserveRatio.test(code)) {
236
+ return false;
237
+ }
238
+
239
+ // Check for swap or exchange context
240
+ if (/swap|exchange|trade/i.test(code)) {
241
+ this.addFinding({
242
+ title: 'Reserve Ratio Manipulation Risk',
243
+ description: `Function uses reserve ratio calculation that can be manipulated within a single transaction. Attackers can inflate/deflate reserves using flash loans before this calculation.`,
244
+ location: `Contract: ${this.currentContract}, Function: ${this.currentFunction}`,
245
+ line: funcNode.loc ? funcNode.loc.start.line : 0,
246
+ column: funcNode.loc ? funcNode.loc.start.column : 0,
247
+ code: this.extractRelevantCode(code, 'reserve'),
248
+ severity: 'HIGH',
249
+ confidence: 'HIGH',
250
+ exploitable: true,
251
+ exploitabilityScore: 80,
252
+ attackVector: 'flash-loan-reserve-manipulation',
253
+ recommendation: 'Use TWAP pricing instead of spot reserve ratios. Implement slippage protection. Consider using Chainlink oracles for critical price data.',
254
+ references: [
255
+ 'https://www.paradigm.xyz/2020/11/so-you-want-to-use-a-price-oracle'
256
+ ]
257
+ });
258
+ return true;
259
+ }
260
+
261
+ return false;
262
+ }
263
+
264
+ /**
265
+ * Check if spot price result flows into value-affecting operations
266
+ */
267
+ checkValueFlow(code, priceFunctionName) {
268
+ // Check what happens after the price call
269
+ const valueOps = [
270
+ { pattern: /\.transfer\s*\(/i, reason: 'Price feeds into ETH/token transfer amount' },
271
+ { pattern: /\.call\s*\{.*value/i, reason: 'Price feeds into call value' },
272
+ { pattern: /\.mint\s*\(/i, reason: 'Price determines mint amount' },
273
+ { pattern: /\.burn\s*\(/i, reason: 'Price determines burn amount' },
274
+ { pattern: /safeTransfer/i, reason: 'Price determines transfer amount' },
275
+ { pattern: /collateral/i, reason: 'Price used for collateral valuation' },
276
+ { pattern: /liquidat/i, reason: 'Price triggers liquidation' },
277
+ { pattern: /borrow/i, reason: 'Price determines borrow capacity' },
278
+ ];
279
+
280
+ for (const { pattern, reason } of valueOps) {
281
+ if (pattern.test(code)) {
282
+ return { isExploitable: true, reason };
283
+ }
284
+ }
285
+
286
+ return { isExploitable: false, reason: '' };
287
+ }
288
+
289
+ /**
290
+ * Extract the most relevant code snippet around a pattern
291
+ */
292
+ extractRelevantCode(fullCode, keyword) {
293
+ const lines = fullCode.split('\n');
294
+ const keywordLower = keyword.toLowerCase();
295
+
296
+ let relevantLines = [];
297
+ let foundLine = -1;
298
+
299
+ for (let i = 0; i < lines.length; i++) {
300
+ if (lines[i].toLowerCase().includes(keywordLower)) {
301
+ foundLine = i;
302
+ break;
303
+ }
304
+ }
305
+
306
+ if (foundLine >= 0) {
307
+ const start = Math.max(0, foundLine - 2);
308
+ const end = Math.min(lines.length, foundLine + 3);
309
+ relevantLines = lines.slice(start, end);
310
+ }
311
+
312
+ return relevantLines.join('\n') || fullCode.substring(0, 200);
313
+ }
314
+
315
+ visitMemberAccess(node) {
316
+ // Detect spot price oracle usage at AST level for precise location
317
+ if (node.memberName === 'getReserves' ||
318
+ node.memberName === 'getAmountsOut' ||
319
+ node.memberName === 'getAmountOut') {
320
+ // Already handled in deepAnalyzeFunction with context
321
+ // This is kept for precise line number tracking
322
+ }
323
+ }
324
+
325
+ /**
326
+ * Generate Foundry PoC for spot price manipulation
327
+ */
328
+ generateSpotPricePoC(oracleFunction, contractName, functionName) {
329
+ return `// SPDX-License-Identifier: MIT
330
+ pragma solidity ^0.8.0;
331
+
332
+ import "forge-std/Test.sol";
333
+
334
+ /**
335
+ * Proof of Concept: Flash Loan Oracle Manipulation
336
+ * Target: ${contractName}.${functionName}()
337
+ * Attack Vector: Manipulate ${oracleFunction}() return value via flash loan
338
+ */
339
+ contract FlashLoanOracleExploit is Test {
340
+ // TODO: Set actual addresses
341
+ address constant TARGET = address(0); // ${contractName} address
342
+ address constant DEX_PAIR = address(0); // Uniswap/DEX pair for manipulation
343
+ address constant FLASH_LOAN_PROVIDER = address(0); // Aave/dYdX
344
+
345
+ function testExploit() public {
346
+ // 1. Take flash loan to get large amount of tokens
347
+ // flashLoan(FLASH_LOAN_PROVIDER, amount);
348
+
349
+ // 2. Manipulate DEX reserves to skew ${oracleFunction}()
350
+ // swap large amount to move price
351
+
352
+ // 3. Call vulnerable function while price is manipulated
353
+ // TARGET.${functionName}(...);
354
+
355
+ // 4. Reverse the manipulation
356
+ // swap back to restore price
357
+
358
+ // 5. Repay flash loan, keep profit
359
+
360
+ // Assert profit was made
361
+ // assertGt(profit, 0);
362
+ }
363
+ }`;
364
+ }
365
+
366
+ /**
367
+ * Generate Foundry PoC for balance manipulation
368
+ */
369
+ generateBalanceManipulationPoC(contractName, functionName) {
370
+ return `// SPDX-License-Identifier: MIT
371
+ pragma solidity ^0.8.0;
372
+
373
+ import "forge-std/Test.sol";
374
+
375
+ /**
376
+ * Proof of Concept: Balance Manipulation Attack
377
+ * Target: ${contractName}.${functionName}()
378
+ * Attack Vector: Manipulate contract balance before price calculation
379
+ */
380
+ contract BalanceManipulationExploit is Test {
381
+ address constant TARGET = address(0); // ${contractName} address
382
+
383
+ function testExploit() public {
384
+ // Method 1: Flash loan + donation
385
+ // 1. Take flash loan
386
+ // 2. Send tokens to target contract (donation)
387
+ // 3. Call vulnerable function (inflated balance = wrong price)
388
+ // 4. Extract value at manipulated price
389
+ // 5. Repay flash loan
390
+
391
+ // Method 2: Self-destruct (for ETH balance)
392
+ // Deploy contract with ETH, selfdestruct to target
393
+
394
+ // Assert profit was made
395
+ // assertGt(profit, 0);
396
+ }
397
+
398
+ // Helper: Self-destruct ETH sender
399
+ // contract Depositor {
400
+ // constructor(address target) payable {
401
+ // selfdestruct(payable(target));
402
+ // }
403
+ // }
404
+ }`;
405
+ }
406
+ }
407
+
408
+ module.exports = FlashLoanDetector;