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,816 @@
1
+ const parser = require('@solidity-parser/parser');
2
+ const fs = require('fs').promises;
3
+ const path = require('path');
4
+
5
+ // Import enhanced analyzers
6
+ const ControlFlowAnalyzer = require('./analyzers/control-flow');
7
+ const DataFlowAnalyzer = require('./analyzers/data-flow');
8
+
9
+ // Import Immunefi classifier and exploit chain modeler
10
+ const ImmunefiClassifier = require('./analyzers/immunefi-classifier');
11
+ const ExploitChainModeler = require('./analyzers/exploit-chain');
12
+ const PocValidator = require('./analyzers/poc-validator');
13
+ const SoloditEnricher = require('./analyzers/solodit-enricher');
14
+
15
+ // Import enhanced detectors only
16
+ const ReentrancyEnhancedDetector = require('./detectors/reentrancy-enhanced');
17
+ const AccessControlEnhancedDetector = require('./detectors/access-control-enhanced');
18
+
19
+ // Keep critical detectors that don't need enhancement
20
+ const UncheckedCallDetector = require('./detectors/unchecked-call');
21
+ const DelegateCallDetector = require('./detectors/delegatecall');
22
+ const UnprotectedSelfdestruct = require('./detectors/selfdestruct');
23
+
24
+ // Advanced Web3 vulnerability detectors
25
+ const IntegerOverflowDetector = require('./detectors/integer-overflow');
26
+ const FlashLoanDetector = require('./detectors/flash-loan');
27
+ const OracleManipulationDetector = require('./detectors/oracle-manipulation');
28
+ const FrontRunningDetector = require('./detectors/frontrunning');
29
+ const TimestampDependenceDetector = require('./detectors/timestamp-dependence');
30
+ const GasGriefingDetector = require('./detectors/gas-griefing');
31
+ const DeprecatedFunctionsDetector = require('./detectors/deprecated-functions');
32
+
33
+ // High-value TVL contract detectors
34
+ const ProxyVulnerabilitiesDetector = require('./detectors/proxy-vulnerabilities');
35
+ const SignatureReplayDetector = require('./detectors/signature-replay');
36
+ const CrossContractReentrancyDetector = require('./detectors/cross-contract-reentrancy');
37
+ const TokenStandardComplianceDetector = require('./detectors/token-standard-compliance');
38
+ const TOCTOUDetector = require('./detectors/toctou');
39
+
40
+ // Immunefi-tier detectors (NEW)
41
+ const GovernanceAttackDetector = require('./detectors/governance-attacks');
42
+ const ShareManipulationDetector = require('./detectors/share-manipulation');
43
+ const PermitExploitsDetector = require('./detectors/permit-exploits');
44
+
45
+ // Advanced high-TVL detectors (Production-grade)
46
+ const CallbackReentrancyDetector = require('./detectors/callback-reentrancy');
47
+ const RebasingTokenVaultDetector = require('./detectors/rebasing-token-vault');
48
+ const AdvancedPriceManipulationDetector = require('./detectors/price-manipulation-advanced');
49
+
50
+ /**
51
+ * Enhanced Web3CRIT Scanner v6.0 (Production-Grade)
52
+ * Top-tier exploit-driven scanner for high TVL contracts ($5M+)
53
+ * Only reports findings that qualify for Immunefi High/Critical payouts
54
+ *
55
+ * PRODUCTION MODE RULES (--production flag):
56
+ * - HIGH/CRITICAL only emitted if Foundry PoC compiles, executes, and proves impact
57
+ * - Impact = fund drain, unauthorized transfer, role takeover, invariant break, or permanent DoS
58
+ * - If PoC fails to compile, run, or show impact → discarded silently
59
+ * - Severity derived from observed PoC results, not heuristics
60
+ *
61
+ * Features:
62
+ * - Control flow and data flow analysis
63
+ * - Immunefi severity classification
64
+ * - Concrete exploit chain modeling
65
+ * - Assumes adversarial capabilities (flash loans, MEV, malicious contracts)
66
+ * - Foundry PoC execution with impact verification
67
+ */
68
+ class Web3CRITScannerEnhanced {
69
+ constructor(options = {}) {
70
+ this.options = {
71
+ verbose: options.verbose || false,
72
+ severity: options.severity || 'all',
73
+ outputFormat: options.outputFormat || 'json',
74
+ onProgress: options.onProgress || null,
75
+ // Exploit-driven mode (only Immunefi High/Critical)
76
+ // Default OFF for backwards compatibility, use --immunefi flag to enable
77
+ exploitDriven: options.exploitDriven || false,
78
+ immunefiOnly: options.immunefiOnly || false, // Strict Immunefi mode
79
+ // PRODUCTION MODE: Strict PoC gating for HIGH/CRITICAL
80
+ productionMode: options.productionMode || false,
81
+ // Foundry PoC validation
82
+ pocValidate: options.pocValidate || false,
83
+ pocRequirePass: options.pocRequirePass || false,
84
+ pocMode: options.pocMode || 'test', // 'test' or 'build'
85
+ foundryRoot: options.foundryRoot || null,
86
+ pocKeepTemp: options.pocKeepTemp || false,
87
+ forkUrl: options.forkUrl || null, // RPC URL for fork testing
88
+ ...options
89
+ };
90
+
91
+ // In production mode, automatically enable exploit-driven and poc validation
92
+ if (this.options.productionMode) {
93
+ this.options.exploitDriven = true;
94
+ this.options.immunefiOnly = true;
95
+ this.options.pocValidate = true;
96
+ this.options.pocRequirePass = true;
97
+ }
98
+
99
+ // Initialize Immunefi classifier
100
+ this.immunefiClassifier = new ImmunefiClassifier();
101
+ this.pocValidator = new PocValidator({
102
+ enabled: this.options.pocValidate || this.options.productionMode,
103
+ requirePass: this.options.pocRequirePass || this.options.productionMode,
104
+ productionMode: this.options.productionMode || false,
105
+ mode: this.options.pocMode || 'test',
106
+ foundryRoot: this.options.foundryRoot || null,
107
+ keepTemp: this.options.pocKeepTemp || false,
108
+ forkUrl: this.options.forkUrl || null
109
+ });
110
+
111
+ // Initialize Solodit enricher for real-world vulnerability correlation
112
+ this.soloditEnricher = new SoloditEnricher({
113
+ apiKey: this.options.soloditApiKey || process.env.SOLODIT_API_KEY,
114
+ baseUrl: this.options.soloditBaseUrl || process.env.SOLODIT_API_URL,
115
+ enabled: this.options.soloditEnrich || false,
116
+ verbose: this.options.verbose,
117
+ timeout: this.options.soloditTimeout || 10000,
118
+ minConfidenceThreshold: this.options.soloditMinConfidence || 0.3
119
+ });
120
+
121
+ // Initialize enhanced detectors - ordered by Immunefi severity
122
+ // Production-grade for high-TVL DeFi targets
123
+ this.detectors = [
124
+ // CRITICAL: Direct theft of funds (highest priority)
125
+ new ReentrancyEnhancedDetector(),
126
+ new CallbackReentrancyDetector(), // NEW: ERC777/ERC1155 callback reentrancy
127
+ new AccessControlEnhancedDetector(),
128
+ new DelegateCallDetector(),
129
+ new UnprotectedSelfdestruct(),
130
+ new ProxyVulnerabilitiesDetector(),
131
+ new CrossContractReentrancyDetector(),
132
+
133
+ // CRITICAL: Protocol insolvency / Governance takeover
134
+ new GovernanceAttackDetector(),
135
+ new ShareManipulationDetector(),
136
+ new RebasingTokenVaultDetector(), // NEW: Aave/Lido rebasing token issues
137
+ new FlashLoanDetector(),
138
+ new OracleManipulationDetector(),
139
+ new AdvancedPriceManipulationDetector(), // NEW: LP token, Curve, Balancer manipulation
140
+
141
+ // HIGH: Theft of yield / Manipulation profit
142
+ new SignatureReplayDetector(),
143
+ new PermitExploitsDetector(),
144
+ new UncheckedCallDetector(),
145
+ new TOCTOUDetector(),
146
+
147
+ // HIGH: Price manipulation
148
+ new FrontRunningDetector(),
149
+ new IntegerOverflowDetector(),
150
+
151
+ // MEDIUM: Conditional inclusion (filtered in exploit-driven mode)
152
+ new TimestampDependenceDetector(),
153
+ new GasGriefingDetector(),
154
+ new DeprecatedFunctionsDetector(),
155
+ new TokenStandardComplianceDetector()
156
+ ];
157
+
158
+ this.findings = [];
159
+ this.stats = {
160
+ filesScanned: 0,
161
+ totalFindings: 0,
162
+ critical: 0,
163
+ high: 0,
164
+ medium: 0,
165
+ low: 0,
166
+ info: 0,
167
+ exploitable: 0
168
+ };
169
+ }
170
+
171
+ async scanFile(filePath) {
172
+ try {
173
+ const content = await fs.readFile(filePath, 'utf8');
174
+ return await this.scanSource(content, filePath);
175
+ } catch (error) {
176
+ throw new Error(`Failed to read file ${filePath}: ${error.message}`);
177
+ }
178
+ }
179
+
180
+ async scanSource(sourceCode, fileName = 'contract.sol') {
181
+ this.stats.filesScanned++;
182
+
183
+ // Progress: Parsing
184
+ if (this.options.onProgress) {
185
+ this.options.onProgress({
186
+ stage: 'parsing',
187
+ message: 'Parsing Solidity code...',
188
+ fileName
189
+ });
190
+ }
191
+
192
+ let ast;
193
+ try {
194
+ ast = parser.parse(sourceCode, {
195
+ loc: true,
196
+ range: true,
197
+ tolerant: true
198
+ });
199
+ } catch (error) {
200
+ throw new Error(`Failed to parse Solidity code: ${error.message}`);
201
+ }
202
+
203
+ // Progress: Building control flow graph
204
+ if (this.options.onProgress) {
205
+ this.options.onProgress({
206
+ stage: 'analyzing',
207
+ message: 'Building control flow graph...',
208
+ fileName
209
+ });
210
+ }
211
+
212
+ // Build control flow graph
213
+ const cfgAnalyzer = new ControlFlowAnalyzer();
214
+ const cfg = cfgAnalyzer.analyze(ast, sourceCode);
215
+
216
+ // Progress: Data flow analysis
217
+ if (this.options.onProgress) {
218
+ this.options.onProgress({
219
+ stage: 'analyzing',
220
+ message: 'Performing data flow analysis...',
221
+ fileName
222
+ });
223
+ }
224
+
225
+ // Perform data flow analysis
226
+ const dataFlowAnalyzer = new DataFlowAnalyzer(cfg);
227
+ const dataFlow = dataFlowAnalyzer.analyze();
228
+
229
+ const contractFindings = [];
230
+ const totalDetectors = this.detectors.length;
231
+
232
+ // Run enhanced detectors with CFG and data flow info
233
+ for (let i = 0; i < this.detectors.length; i++) {
234
+ const detector = this.detectors[i];
235
+
236
+ // Progress: Running detector
237
+ if (this.options.onProgress) {
238
+ this.options.onProgress({
239
+ stage: 'detecting',
240
+ message: `Running detector: ${detector.name}`,
241
+ detector: detector.name,
242
+ current: i + 1,
243
+ total: totalDetectors,
244
+ fileName
245
+ });
246
+ }
247
+
248
+ try {
249
+ // Pass CFG and data flow to enhanced detectors
250
+ const detectorFindings = await detector.detect(ast, sourceCode, fileName, cfg, dataFlow);
251
+ contractFindings.push(...detectorFindings);
252
+ } catch (error) {
253
+ if (this.options.verbose) {
254
+ console.error(`Detector ${detector.name} failed: ${error.message}`);
255
+ }
256
+ }
257
+ }
258
+
259
+ // Progress: Analyzing results
260
+ if (this.options.onProgress) {
261
+ this.options.onProgress({
262
+ stage: 'filtering',
263
+ message: 'Classifying for Immunefi payout eligibility...',
264
+ fileName
265
+ });
266
+ }
267
+
268
+ // Apply exploit-driven filtering with Immunefi classification
269
+ let filteredFindings;
270
+ if (this.options.exploitDriven || this.options.immunefiOnly || this.options.productionMode) {
271
+ // Model exploit chains
272
+ const exploitModeler = new ExploitChainModeler(cfg, dataFlow);
273
+ const withExploitChains = exploitModeler.modelExploitChains(contractFindings);
274
+
275
+ // Classify for Immunefi payouts
276
+ filteredFindings = this.immunefiClassifier.filterToPayoutLevel(withExploitChains);
277
+
278
+ // In strict immunefi mode, only keep Critical/High
279
+ if (this.options.immunefiOnly || this.options.productionMode) {
280
+ filteredFindings = filteredFindings.filter(f =>
281
+ f.payoutTier === 'Critical' || f.payoutTier === 'High'
282
+ );
283
+ }
284
+
285
+ // PRODUCTION MODE: Gate ALL HIGH/CRITICAL behind PoC execution with impact proof
286
+ if (this.options.productionMode) {
287
+ // Progress: PoC validation
288
+ if (this.options.onProgress) {
289
+ this.options.onProgress({
290
+ stage: 'poc-validation',
291
+ message: 'Validating Foundry PoCs (production mode)...',
292
+ fileName
293
+ });
294
+ }
295
+
296
+ const validation = this.pocValidator.validateForProduction(filteredFindings, {
297
+ scanTargetPath: fileName
298
+ });
299
+
300
+ filteredFindings = validation.findings;
301
+
302
+ // Track stats
303
+ this.stats.pocValidated = validation.stats.validatedHighSeverity;
304
+ this.stats.pocDropped = validation.stats.droppedCount;
305
+ this.stats.productionMode = true;
306
+
307
+ // In production mode, only keep findings with proven impact
308
+ filteredFindings = filteredFindings.filter(f => {
309
+ if (['CRITICAL', 'HIGH'].includes(f.severity)) {
310
+ // Must have PoC validation that passed with proven impact
311
+ return f.pocValidation?.ok === true && f.provenImpact;
312
+ }
313
+ // Lower severity findings are still included
314
+ return true;
315
+ });
316
+ } else if (this.options.pocValidate) {
317
+ // Non-production PoC validation (optional)
318
+ const validation = this.pocValidator.validateFindings(filteredFindings, { scanTargetPath: fileName });
319
+ filteredFindings = validation.kept;
320
+ // Track dropped findings for reporting
321
+ this.stats.pocDropped = (this.stats.pocDropped || 0) + validation.dropped.length;
322
+ this.stats.pocKept = (this.stats.pocKept || 0) + validation.kept.length;
323
+ }
324
+
325
+ // Solodit enrichment: correlate with real-world exploits
326
+ if (this.soloditEnricher.enabled) {
327
+ // Progress: Solodit enrichment
328
+ if (this.options.onProgress) {
329
+ this.options.onProgress({
330
+ stage: 'solodit-enrichment',
331
+ message: 'Correlating with Solodit vulnerability database...',
332
+ fileName
333
+ });
334
+ }
335
+
336
+ filteredFindings = await this.soloditEnricher.enrichFindings(filteredFindings);
337
+
338
+ // Track Solodit stats
339
+ const soloditStats = this.soloditEnricher.getStats();
340
+ this.stats.soloditEnriched = soloditStats.findingsEnriched;
341
+ this.stats.soloditConfirmedInWild = soloditStats.confirmedInWild;
342
+ this.stats.soloditTheoretical = soloditStats.theoretical;
343
+ }
344
+ } else {
345
+ // Legacy filtering mode
346
+ filteredFindings = this.filterFindings(contractFindings);
347
+ }
348
+
349
+ // Update statistics
350
+ this.updateStats(filteredFindings);
351
+ this.findings.push(...filteredFindings);
352
+
353
+ return filteredFindings;
354
+ }
355
+
356
+ async sleep(ms) {
357
+ return new Promise(resolve => setTimeout(resolve, ms));
358
+ }
359
+
360
+ async scanDirectory(dirPath) {
361
+ const files = await this.getSolidityFiles(dirPath);
362
+ const allFindings = [];
363
+ const totalFiles = files.length;
364
+
365
+ // Progress: Found files
366
+ if (this.options.onProgress) {
367
+ this.options.onProgress({
368
+ stage: 'discovery',
369
+ message: `Found ${totalFiles} Solidity file(s)`,
370
+ totalFiles
371
+ });
372
+ }
373
+
374
+ for (let i = 0; i < files.length; i++) {
375
+ const file = files[i];
376
+
377
+ // Progress: Scanning file
378
+ if (this.options.onProgress) {
379
+ this.options.onProgress({
380
+ stage: 'file-scan',
381
+ message: `Scanning file ${i + 1}/${totalFiles}`,
382
+ fileName: file,
383
+ currentFile: i + 1,
384
+ totalFiles
385
+ });
386
+ }
387
+
388
+ try {
389
+ const findings = await this.scanFile(file);
390
+ allFindings.push(...findings);
391
+ } catch (error) {
392
+ if (this.options.verbose) {
393
+ console.error(`Error scanning ${file}: ${error.message}`);
394
+ }
395
+ }
396
+ }
397
+
398
+ return allFindings;
399
+ }
400
+
401
+ async getSolidityFiles(dirPath) {
402
+ const files = [];
403
+
404
+ async function traverse(currentPath) {
405
+ const entries = await fs.readdir(currentPath, { withFileTypes: true });
406
+
407
+ for (const entry of entries) {
408
+ const fullPath = path.join(currentPath, entry.name);
409
+
410
+ if (entry.isDirectory() && !entry.name.startsWith('.') && entry.name !== 'node_modules') {
411
+ await traverse(fullPath);
412
+ } else if (entry.isFile() && entry.name.endsWith('.sol')) {
413
+ files.push(fullPath);
414
+ }
415
+ }
416
+ }
417
+
418
+ await traverse(dirPath);
419
+ return files;
420
+ }
421
+
422
+ /**
423
+ * Filter findings by severity, exploitability, and confidence
424
+ * HARDENED: Aggressive filtering to report only real, exploitable vulnerabilities
425
+ * Optimized for precision over recall (fewer false positives)
426
+ */
427
+ filterFindings(findings) {
428
+ // Filter by severity level
429
+ let filtered = this.filterBySeverity(findings);
430
+
431
+ // Deduplicate findings by location (same file:line)
432
+ const seenLocations = new Set();
433
+ filtered = filtered.filter(finding => {
434
+ const locationKey = `${finding.fileName}:${finding.line}:${finding.title}`;
435
+ if (seenLocations.has(locationKey)) {
436
+ return false;
437
+ }
438
+ seenLocations.add(locationKey);
439
+ return true;
440
+ });
441
+
442
+ // Apply exploitability-based filtering (HARDENED)
443
+ filtered = filtered.filter(finding => {
444
+ // Always report high-confidence findings with PoC
445
+ if (finding.isHighConfidence === true) {
446
+ return true;
447
+ }
448
+
449
+ // CRITICAL severity: require exploitable flag AND (HIGH confidence OR score >= 70)
450
+ if (finding.severity === 'CRITICAL') {
451
+ if (finding.exploitable !== true) return false;
452
+ if (finding.confidence === 'HIGH') return true;
453
+ if (finding.exploitabilityScore >= 70) return true;
454
+ return false;
455
+ }
456
+
457
+ // HIGH severity: require HIGH confidence OR (MEDIUM confidence AND exploitable AND score >= 65)
458
+ if (finding.severity === 'HIGH') {
459
+ if (finding.confidence === 'HIGH' && finding.exploitable === true) return true;
460
+ if (finding.confidence === 'MEDIUM' && finding.exploitable === true && finding.exploitabilityScore >= 65) return true;
461
+ return false;
462
+ }
463
+
464
+ // MEDIUM severity: require HIGH confidence AND exploitable AND score >= 70
465
+ if (finding.severity === 'MEDIUM') {
466
+ if (finding.confidence === 'HIGH' && finding.exploitable === true && finding.exploitabilityScore >= 70) return true;
467
+ return false;
468
+ }
469
+
470
+ // LOW/INFO: Only include with very high score (rare)
471
+ if (finding.severity === 'LOW' || finding.severity === 'INFO') {
472
+ return finding.exploitabilityScore >= 80 && finding.confidence === 'HIGH';
473
+ }
474
+
475
+ // Default: filter out
476
+ return false;
477
+ });
478
+
479
+ // Sort by exploitability score (highest first)
480
+ filtered.sort((a, b) => {
481
+ // First by severity
482
+ const severityOrder = { 'CRITICAL': 5, 'HIGH': 4, 'MEDIUM': 3, 'LOW': 2, 'INFO': 1 };
483
+ const severityDiff = (severityOrder[b.severity] || 0) - (severityOrder[a.severity] || 0);
484
+ if (severityDiff !== 0) return severityDiff;
485
+
486
+ // Then by confidence
487
+ const confOrder = { 'HIGH': 3, 'MEDIUM': 2, 'LOW': 1 };
488
+ const confDiff = (confOrder[b.confidence] || 0) - (confOrder[a.confidence] || 0);
489
+ if (confDiff !== 0) return confDiff;
490
+
491
+ // Then by exploitability score
492
+ return (b.exploitabilityScore || 0) - (a.exploitabilityScore || 0);
493
+ });
494
+
495
+ return filtered;
496
+ }
497
+
498
+ filterBySeverity(findings) {
499
+ if (this.options.severity === 'all') {
500
+ return findings;
501
+ }
502
+
503
+ const severityLevels = {
504
+ critical: 5,
505
+ high: 4,
506
+ medium: 3,
507
+ low: 2,
508
+ info: 1
509
+ };
510
+
511
+ const minLevel = severityLevels[this.options.severity] || 0;
512
+
513
+ return findings.filter(f =>
514
+ severityLevels[f.severity.toLowerCase()] >= minLevel
515
+ );
516
+ }
517
+
518
+ updateStats(findings) {
519
+ findings.forEach(finding => {
520
+ this.stats.totalFindings++;
521
+ const severity = finding.severity.toLowerCase();
522
+ if (this.stats[severity] !== undefined) {
523
+ this.stats[severity]++;
524
+ }
525
+ if (finding.exploitable === true) {
526
+ this.stats.exploitable++;
527
+ }
528
+ // Track Immunefi payout eligibility
529
+ if (finding.payoutTier === 'Critical') {
530
+ this.stats.immunefiCritical = (this.stats.immunefiCritical || 0) + 1;
531
+ } else if (finding.payoutTier === 'High') {
532
+ this.stats.immunefiHigh = (this.stats.immunefiHigh || 0) + 1;
533
+ }
534
+ });
535
+ }
536
+
537
+ /**
538
+ * Get Immunefi-focused summary for bug bounty submission
539
+ * Groups findings by payout category with exploit chains
540
+ */
541
+ getImmunefiReport() {
542
+ const criticalFindings = this.findings.filter(f => f.payoutTier === 'Critical');
543
+ const highFindings = this.findings.filter(f => f.payoutTier === 'High');
544
+
545
+ const formatFinding = (f, index) => ({
546
+ id: index + 1,
547
+ title: f.title,
548
+ severity: f.severity,
549
+ payoutTier: f.payoutTier,
550
+ immunefiCategory: f.immunefiClassification?.category?.name || 'Unknown',
551
+ impact: f.immunefiClassification?.impactDescription || f.description,
552
+ location: f.location,
553
+ file: `${f.fileName}:${f.line}`,
554
+ exploitChain: f.exploitChain ? {
555
+ attackerRequirements: f.exploitChain.requirements,
556
+ steps: f.exploitChain.steps?.map(s => s.action) || [],
557
+ profitMechanism: f.exploitChain.profitPath?.mechanism
558
+ } : null,
559
+ recommendation: f.recommendation,
560
+ poc: f.foundryPoC ? 'Included' : 'Not generated'
561
+ });
562
+
563
+ return {
564
+ summary: {
565
+ totalFindings: this.findings.length,
566
+ criticalCount: criticalFindings.length,
567
+ highCount: highFindings.length,
568
+ scanMode: this.options.immunefiOnly ? 'Immunefi Strict' : 'Exploit-Driven'
569
+ },
570
+ criticalFindings: criticalFindings.map(formatFinding),
571
+ highFindings: highFindings.map(formatFinding),
572
+ attackVectors: this.getAttackVectorSummary(),
573
+ generatedAt: new Date().toISOString()
574
+ };
575
+ }
576
+
577
+ /**
578
+ * Get summary by attack vector for Immunefi submission
579
+ */
580
+ getAttackVectorSummary() {
581
+ const vectors = {};
582
+ for (const finding of this.findings) {
583
+ const vector = finding.attackVector || 'other';
584
+ if (!vectors[vector]) {
585
+ vectors[vector] = { count: 0, critical: 0, high: 0 };
586
+ }
587
+ vectors[vector].count++;
588
+ if (finding.payoutTier === 'Critical') vectors[vector].critical++;
589
+ if (finding.payoutTier === 'High') vectors[vector].high++;
590
+ }
591
+ return vectors;
592
+ }
593
+
594
+ getFindings() {
595
+ // Separate by Immunefi payout tier
596
+ const criticalFindings = this.findings.filter(f => f.payoutTier === 'Critical');
597
+ const highFindings = this.findings.filter(f => f.payoutTier === 'High');
598
+ const highConfidenceFindings = this.findings.filter(f => f.isHighConfidence);
599
+
600
+ // Solodit validation status breakdown
601
+ const soloditConfirmedInWild = this.findings.filter(f =>
602
+ f.soloditMetadata?.validationStatus?.status === 'confirmed_in_wild'
603
+ );
604
+ const soloditConfirmedPattern = this.findings.filter(f =>
605
+ f.soloditMetadata?.validationStatus?.status === 'confirmed_pattern'
606
+ );
607
+ const soloditTheoretical = this.findings.filter(f =>
608
+ f.soloditMetadata?.validationStatus?.status === 'theoretical' ||
609
+ !f.soloditMetadata?.matched
610
+ );
611
+
612
+ // Build features list
613
+ const features = [
614
+ 'Immunefi Severity Classification',
615
+ 'Concrete Exploit Chain Modeling',
616
+ 'Adversarial Capability Modeling (Flash Loans, MEV)',
617
+ 'Control Flow Analysis',
618
+ 'Data Flow Analysis',
619
+ 'Cross-Function Reentrancy Detection',
620
+ 'Cross-Contract Reentrancy Detection',
621
+ 'Governance Attack Detection',
622
+ 'Vault/Share Manipulation Detection',
623
+ 'Permit/Approval Exploit Detection',
624
+ 'Modifier Logic Validation',
625
+ 'Exploitability Scoring (0-100)',
626
+ 'Attack Vector Classification',
627
+ 'Foundry PoC Generation',
628
+ 'Flash Loan Attack Detection',
629
+ 'Front-Running/MEV Protection',
630
+ 'Proxy Contract Vulnerabilities (UUPS, Transparent)',
631
+ 'Signature Replay Protection',
632
+ 'First Depositor Attack Detection'
633
+ ];
634
+
635
+ // Add Solodit feature if enabled
636
+ if (this.soloditEnricher.enabled) {
637
+ features.push('Solodit Real-World Vulnerability Correlation');
638
+ }
639
+
640
+ return {
641
+ findings: this.findings,
642
+ // Immunefi categorization
643
+ immunefiCritical: criticalFindings,
644
+ immunefiHigh: highFindings,
645
+ highConfidenceFindings: highConfidenceFindings,
646
+ // Solodit validation breakdown
647
+ solodit: this.soloditEnricher.enabled ? {
648
+ confirmedInWild: soloditConfirmedInWild,
649
+ confirmedPattern: soloditConfirmedPattern,
650
+ theoretical: soloditTheoretical,
651
+ stats: this.soloditEnricher.getStats()
652
+ } : null,
653
+ stats: {
654
+ ...this.stats,
655
+ // Immunefi stats
656
+ immunefiCritical: criticalFindings.length,
657
+ immunefiHigh: highFindings.length,
658
+ totalPayoutEligible: criticalFindings.length + highFindings.length,
659
+ highConfidence: highConfidenceFindings.length,
660
+ withPoC: this.findings.filter(f => f.foundryPoC).length,
661
+ withExploitChain: this.findings.filter(f => f.exploitChain).length,
662
+ // Solodit stats
663
+ soloditEnabled: this.soloditEnricher.enabled,
664
+ soloditConfirmedInWild: soloditConfirmedInWild.length,
665
+ soloditConfirmedPattern: soloditConfirmedPattern.length,
666
+ soloditTheoretical: soloditTheoretical.length
667
+ },
668
+ analysis: {
669
+ engine: 'exploit-driven',
670
+ version: '6.0.0',
671
+ mode: this.options.immunefiOnly ? 'immunefi-strict' : 'exploit-driven',
672
+ soloditEnabled: this.soloditEnricher.enabled,
673
+ features: features
674
+ }
675
+ };
676
+ }
677
+
678
+ /**
679
+ * Get high-confidence findings with Foundry PoC templates
680
+ * Only returns findings that meet the high-confidence threshold
681
+ */
682
+ getHighConfidenceFindings() {
683
+ return this.findings.filter(f => f.isHighConfidence && f.foundryPoC);
684
+ }
685
+
686
+ /**
687
+ * Generate Foundry test file with all high-confidence PoCs
688
+ * @param {string} contractName - Name for the test file
689
+ * @returns {string} Complete Foundry test file content
690
+ */
691
+ generateFoundryTestFile(contractName = 'VulnerabilityExploits') {
692
+ const pocFindings = this.getHighConfidenceFindings();
693
+
694
+ if (pocFindings.length === 0) {
695
+ return null;
696
+ }
697
+
698
+ const criticalCount = pocFindings.filter(f => f.payoutTier === 'Critical').length;
699
+ const highCount = pocFindings.filter(f => f.payoutTier === 'High').length;
700
+
701
+ const header = `// SPDX-License-Identifier: MIT
702
+ pragma solidity ^0.8.0;
703
+
704
+ import "forge-std/Test.sol";
705
+
706
+ /**
707
+ * Foundry Proof of Concept Tests
708
+ * Generated by Web3CRIT Scanner v6.0.0 (Exploit-Driven Mode)
709
+ *
710
+ * Immunefi Payout-Eligible Findings: ${pocFindings.length}
711
+ * - Critical: ${criticalCount}
712
+ * - High: ${highCount}
713
+ *
714
+ * To run: forge test --match-contract ${contractName} -vvv
715
+ */
716
+ `;
717
+
718
+ const contracts = pocFindings.map((finding, index) => {
719
+ const testName = this.sanitizeTestName(finding.title);
720
+ const attackVector = finding.attackVector || 'unknown';
721
+
722
+ return `
723
+ /**
724
+ * Finding #${index + 1}: ${finding.title}
725
+ * Severity: ${finding.severity}
726
+ * Confidence: ${finding.confidence}
727
+ * Exploitability Score: ${finding.exploitabilityScore}/100
728
+ * Attack Vector: ${attackVector}
729
+ * File: ${finding.fileName}:${finding.line}
730
+ *
731
+ * Description: ${finding.description}
732
+ */
733
+ ${finding.foundryPoC}
734
+ `;
735
+ }).join('\n');
736
+
737
+ return header + contracts;
738
+ }
739
+
740
+ /**
741
+ * Sanitize a title into a valid Solidity test function name
742
+ */
743
+ sanitizeTestName(title) {
744
+ return title
745
+ .replace(/[^a-zA-Z0-9\s]/g, '')
746
+ .split(/\s+/)
747
+ .map((word, i) => i === 0 ? word.toLowerCase() : word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
748
+ .join('');
749
+ }
750
+
751
+ /**
752
+ * Get summary of findings by attack vector
753
+ */
754
+ getFindingsSummary() {
755
+ const byVector = {};
756
+ const bySeverity = {};
757
+
758
+ for (const finding of this.findings) {
759
+ // By attack vector
760
+ const vector = finding.attackVector || 'unknown';
761
+ if (!byVector[vector]) {
762
+ byVector[vector] = { count: 0, highConfidence: 0, findings: [] };
763
+ }
764
+ byVector[vector].count++;
765
+ if (finding.isHighConfidence) {
766
+ byVector[vector].highConfidence++;
767
+ }
768
+ byVector[vector].findings.push({
769
+ title: finding.title,
770
+ severity: finding.severity,
771
+ exploitabilityScore: finding.exploitabilityScore
772
+ });
773
+
774
+ // By severity
775
+ const severity = finding.severity;
776
+ if (!bySeverity[severity]) {
777
+ bySeverity[severity] = 0;
778
+ }
779
+ bySeverity[severity]++;
780
+ }
781
+
782
+ return {
783
+ total: this.findings.length,
784
+ highConfidence: this.findings.filter(f => f.isHighConfidence).length,
785
+ withPoC: this.findings.filter(f => f.foundryPoC).length,
786
+ byAttackVector: byVector,
787
+ bySeverity: bySeverity,
788
+ topExploitable: this.findings
789
+ .filter(f => f.exploitabilityScore >= 70)
790
+ .sort((a, b) => b.exploitabilityScore - a.exploitabilityScore)
791
+ .slice(0, 5)
792
+ .map(f => ({
793
+ title: f.title,
794
+ severity: f.severity,
795
+ score: f.exploitabilityScore,
796
+ vector: f.attackVector
797
+ }))
798
+ };
799
+ }
800
+
801
+ reset() {
802
+ this.findings = [];
803
+ this.stats = {
804
+ filesScanned: 0,
805
+ totalFindings: 0,
806
+ critical: 0,
807
+ high: 0,
808
+ medium: 0,
809
+ low: 0,
810
+ info: 0,
811
+ exploitable: 0
812
+ };
813
+ }
814
+ }
815
+
816
+ module.exports = Web3CRITScannerEnhanced;