vaspera 2.9.2 → 2.10.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.
Files changed (159) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/README.md +58 -1
  3. package/dist/__tests__/autofix/branch-manager.test.d.ts +2 -0
  4. package/dist/__tests__/autofix/branch-manager.test.d.ts.map +1 -0
  5. package/dist/__tests__/autofix/branch-manager.test.js +60 -0
  6. package/dist/__tests__/autofix/branch-manager.test.js.map +1 -0
  7. package/dist/__tests__/autofix/commit-generator.test.d.ts +2 -0
  8. package/dist/__tests__/autofix/commit-generator.test.d.ts.map +1 -0
  9. package/dist/__tests__/autofix/commit-generator.test.js +147 -0
  10. package/dist/__tests__/autofix/commit-generator.test.js.map +1 -0
  11. package/dist/__tests__/autofix/constitution.test.d.ts +9 -0
  12. package/dist/__tests__/autofix/constitution.test.d.ts.map +1 -0
  13. package/dist/__tests__/autofix/constitution.test.js +421 -0
  14. package/dist/__tests__/autofix/constitution.test.js.map +1 -0
  15. package/dist/__tests__/autofix/pr-generator.test.d.ts +2 -0
  16. package/dist/__tests__/autofix/pr-generator.test.d.ts.map +1 -0
  17. package/dist/__tests__/autofix/pr-generator.test.js +152 -0
  18. package/dist/__tests__/autofix/pr-generator.test.js.map +1 -0
  19. package/dist/__tests__/property-test-helpers.d.ts +87 -0
  20. package/dist/__tests__/property-test-helpers.d.ts.map +1 -0
  21. package/dist/__tests__/property-test-helpers.js +136 -0
  22. package/dist/__tests__/property-test-helpers.js.map +1 -0
  23. package/dist/__tests__/scanners/dast/index.test.d.ts +2 -0
  24. package/dist/__tests__/scanners/dast/index.test.d.ts.map +1 -0
  25. package/dist/__tests__/scanners/dast/index.test.js +183 -0
  26. package/dist/__tests__/scanners/dast/index.test.js.map +1 -0
  27. package/dist/__tests__/scanners/dast/nuclei.test.d.ts +2 -0
  28. package/dist/__tests__/scanners/dast/nuclei.test.d.ts.map +1 -0
  29. package/dist/__tests__/scanners/dast/nuclei.test.js +166 -0
  30. package/dist/__tests__/scanners/dast/nuclei.test.js.map +1 -0
  31. package/dist/__tests__/scanners/dast/zap.test.d.ts +2 -0
  32. package/dist/__tests__/scanners/dast/zap.test.d.ts.map +1 -0
  33. package/dist/__tests__/scanners/dast/zap.test.js +158 -0
  34. package/dist/__tests__/scanners/dast/zap.test.js.map +1 -0
  35. package/dist/__tests__/scanners/fp-feedback.test.d.ts +2 -0
  36. package/dist/__tests__/scanners/fp-feedback.test.d.ts.map +1 -0
  37. package/dist/__tests__/scanners/fp-feedback.test.js +202 -0
  38. package/dist/__tests__/scanners/fp-feedback.test.js.map +1 -0
  39. package/dist/__tests__/scanners/fp-filter.property.test.d.ts +9 -0
  40. package/dist/__tests__/scanners/fp-filter.property.test.d.ts.map +1 -0
  41. package/dist/__tests__/scanners/fp-filter.property.test.js +253 -0
  42. package/dist/__tests__/scanners/fp-filter.property.test.js.map +1 -0
  43. package/dist/__tests__/scanners/fp-filter.test.d.ts +2 -0
  44. package/dist/__tests__/scanners/fp-filter.test.d.ts.map +1 -0
  45. package/dist/__tests__/scanners/fp-filter.test.js +234 -0
  46. package/dist/__tests__/scanners/fp-filter.test.js.map +1 -0
  47. package/dist/__tests__/scanners/fp-tracker.test.d.ts +2 -0
  48. package/dist/__tests__/scanners/fp-tracker.test.d.ts.map +1 -0
  49. package/dist/__tests__/scanners/fp-tracker.test.js +262 -0
  50. package/dist/__tests__/scanners/fp-tracker.test.js.map +1 -0
  51. package/dist/__tests__/scanners/logic/endpoint-analyzer.property.test.d.ts +10 -0
  52. package/dist/__tests__/scanners/logic/endpoint-analyzer.property.test.d.ts.map +1 -0
  53. package/dist/__tests__/scanners/logic/endpoint-analyzer.property.test.js +238 -0
  54. package/dist/__tests__/scanners/logic/endpoint-analyzer.property.test.js.map +1 -0
  55. package/dist/__tests__/scanners/logic/endpoint-analyzer.test.d.ts +2 -0
  56. package/dist/__tests__/scanners/logic/endpoint-analyzer.test.d.ts.map +1 -0
  57. package/dist/__tests__/scanners/logic/endpoint-analyzer.test.js +55 -0
  58. package/dist/__tests__/scanners/logic/endpoint-analyzer.test.js.map +1 -0
  59. package/dist/__tests__/scanners/logic/index.test.d.ts +2 -0
  60. package/dist/__tests__/scanners/logic/index.test.d.ts.map +1 -0
  61. package/dist/__tests__/scanners/logic/index.test.js +165 -0
  62. package/dist/__tests__/scanners/logic/index.test.js.map +1 -0
  63. package/dist/__tests__/scanners/logic/types.test.d.ts +2 -0
  64. package/dist/__tests__/scanners/logic/types.test.d.ts.map +1 -0
  65. package/dist/__tests__/scanners/logic/types.test.js +85 -0
  66. package/dist/__tests__/scanners/logic/types.test.js.map +1 -0
  67. package/dist/action/pr-comment.test.js +4 -0
  68. package/dist/action/pr-comment.test.js.map +1 -1
  69. package/dist/action/sarif-upload.test.js +4 -0
  70. package/dist/action/sarif-upload.test.js.map +1 -1
  71. package/dist/autofix/branch-manager.d.ts +115 -0
  72. package/dist/autofix/branch-manager.d.ts.map +1 -0
  73. package/dist/autofix/branch-manager.js +308 -0
  74. package/dist/autofix/branch-manager.js.map +1 -0
  75. package/dist/autofix/commit-generator.d.ts +55 -0
  76. package/dist/autofix/commit-generator.d.ts.map +1 -0
  77. package/dist/autofix/commit-generator.js +277 -0
  78. package/dist/autofix/commit-generator.js.map +1 -0
  79. package/dist/autofix/constitution.d.ts +77 -0
  80. package/dist/autofix/constitution.d.ts.map +1 -0
  81. package/dist/autofix/constitution.js +261 -0
  82. package/dist/autofix/constitution.js.map +1 -0
  83. package/dist/autofix/constitution.schema.d.ts +441 -0
  84. package/dist/autofix/constitution.schema.d.ts.map +1 -0
  85. package/dist/autofix/constitution.schema.js +144 -0
  86. package/dist/autofix/constitution.schema.js.map +1 -0
  87. package/dist/autofix/index.d.ts +13 -0
  88. package/dist/autofix/index.d.ts.map +1 -0
  89. package/dist/autofix/index.js +15 -0
  90. package/dist/autofix/index.js.map +1 -0
  91. package/dist/autofix/pr-generator.d.ts +57 -0
  92. package/dist/autofix/pr-generator.d.ts.map +1 -0
  93. package/dist/autofix/pr-generator.js +597 -0
  94. package/dist/autofix/pr-generator.js.map +1 -0
  95. package/dist/autofix/types.d.ts +151 -0
  96. package/dist/autofix/types.d.ts.map +1 -0
  97. package/dist/autofix/types.js +22 -0
  98. package/dist/autofix/types.js.map +1 -0
  99. package/dist/eval/fixtures.d.ts +20 -0
  100. package/dist/eval/fixtures.d.ts.map +1 -1
  101. package/dist/eval/fixtures.js +430 -0
  102. package/dist/eval/fixtures.js.map +1 -1
  103. package/dist/scanners/cache.d.ts.map +1 -1
  104. package/dist/scanners/cache.js +4 -0
  105. package/dist/scanners/cache.js.map +1 -1
  106. package/dist/scanners/dast/index.d.ts +39 -0
  107. package/dist/scanners/dast/index.d.ts.map +1 -0
  108. package/dist/scanners/dast/index.js +259 -0
  109. package/dist/scanners/dast/index.js.map +1 -0
  110. package/dist/scanners/dast/nuclei.d.ts +26 -0
  111. package/dist/scanners/dast/nuclei.d.ts.map +1 -0
  112. package/dist/scanners/dast/nuclei.js +354 -0
  113. package/dist/scanners/dast/nuclei.js.map +1 -0
  114. package/dist/scanners/dast/types.d.ts +306 -0
  115. package/dist/scanners/dast/types.d.ts.map +1 -0
  116. package/dist/scanners/dast/types.js +52 -0
  117. package/dist/scanners/dast/types.js.map +1 -0
  118. package/dist/scanners/dast/zap.d.ts +26 -0
  119. package/dist/scanners/dast/zap.d.ts.map +1 -0
  120. package/dist/scanners/dast/zap.js +453 -0
  121. package/dist/scanners/dast/zap.js.map +1 -0
  122. package/dist/scanners/fp-feedback.d.ts +140 -0
  123. package/dist/scanners/fp-feedback.d.ts.map +1 -0
  124. package/dist/scanners/fp-feedback.js +292 -0
  125. package/dist/scanners/fp-feedback.js.map +1 -0
  126. package/dist/scanners/fp-filter.d.ts +94 -0
  127. package/dist/scanners/fp-filter.d.ts.map +1 -0
  128. package/dist/scanners/fp-filter.js +397 -0
  129. package/dist/scanners/fp-filter.js.map +1 -0
  130. package/dist/scanners/fp-tracker.d.ts +125 -0
  131. package/dist/scanners/fp-tracker.d.ts.map +1 -0
  132. package/dist/scanners/fp-tracker.js +330 -0
  133. package/dist/scanners/fp-tracker.js.map +1 -0
  134. package/dist/scanners/index.d.ts.map +1 -1
  135. package/dist/scanners/index.js +56 -0
  136. package/dist/scanners/index.js.map +1 -1
  137. package/dist/scanners/index.test.js +6 -6
  138. package/dist/scanners/index.test.js.map +1 -1
  139. package/dist/scanners/logic/auth-flow-analyzer.d.ts +18 -0
  140. package/dist/scanners/logic/auth-flow-analyzer.d.ts.map +1 -0
  141. package/dist/scanners/logic/auth-flow-analyzer.js +384 -0
  142. package/dist/scanners/logic/auth-flow-analyzer.js.map +1 -0
  143. package/dist/scanners/logic/endpoint-analyzer.d.ts +29 -0
  144. package/dist/scanners/logic/endpoint-analyzer.d.ts.map +1 -0
  145. package/dist/scanners/logic/endpoint-analyzer.js +528 -0
  146. package/dist/scanners/logic/endpoint-analyzer.js.map +1 -0
  147. package/dist/scanners/logic/index.d.ts +41 -0
  148. package/dist/scanners/logic/index.d.ts.map +1 -0
  149. package/dist/scanners/logic/index.js +268 -0
  150. package/dist/scanners/logic/index.js.map +1 -0
  151. package/dist/scanners/logic/types.d.ts +254 -0
  152. package/dist/scanners/logic/types.d.ts.map +1 -0
  153. package/dist/scanners/logic/types.js +142 -0
  154. package/dist/scanners/logic/types.js.map +1 -0
  155. package/dist/scanners/types.d.ts +1 -1
  156. package/dist/scanners/types.d.ts.map +1 -1
  157. package/dist/scanners/types.js +4 -0
  158. package/dist/scanners/types.js.map +1 -1
  159. package/package.json +5 -3
@@ -0,0 +1,259 @@
1
+ /**
2
+ * DAST Scanner Module
3
+ *
4
+ * Aggregates OWASP ZAP and Nuclei for dynamic application
5
+ * security testing.
6
+ *
7
+ * @module scanners/dast
8
+ */
9
+ import { logger } from "../../logger.js";
10
+ import { DEFAULT_DAST_POLICY } from "./types.js";
11
+ import { checkZapAvailable, runZap, getZapInstallInstructions } from "./zap.js";
12
+ import { checkNucleiAvailable, runNuclei, getNucleiInstallInstructions } from "./nuclei.js";
13
+ // Re-export types
14
+ export * from "./types.js";
15
+ // Re-export individual scanners
16
+ export { checkZapAvailable, runZap, getZapInstallInstructions } from "./zap.js";
17
+ export { checkNucleiAvailable, runNuclei, getNucleiInstallInstructions } from "./nuclei.js";
18
+ /**
19
+ * Check availability of all DAST tools
20
+ */
21
+ export async function checkDASTAvailability() {
22
+ const [zapResult, nucleiResult] = await Promise.all([
23
+ checkZapAvailable(),
24
+ checkNucleiAvailable(),
25
+ ]);
26
+ return [zapResult, nucleiResult];
27
+ }
28
+ /**
29
+ * Get installation instructions for missing DAST tools
30
+ */
31
+ export function getDASTInstallInstructions(availability) {
32
+ const instructions = [];
33
+ for (const scanner of availability) {
34
+ if (!scanner.available) {
35
+ if (scanner.scanner === "zap") {
36
+ instructions.push(getZapInstallInstructions());
37
+ }
38
+ else if (scanner.scanner === "nuclei") {
39
+ instructions.push(getNucleiInstallInstructions());
40
+ }
41
+ }
42
+ }
43
+ if (instructions.length === 0) {
44
+ return "All DAST tools are installed and available.";
45
+ }
46
+ return instructions.join("\n---\n");
47
+ }
48
+ /**
49
+ * Deduplicate findings based on URL and rule pattern
50
+ */
51
+ function deduplicateFindings(findings) {
52
+ const seen = new Map();
53
+ for (const finding of findings) {
54
+ // Create a unique key based on URL, severity, and rule pattern
55
+ const normalizedRuleId = finding.ruleId
56
+ .replace(/^zap-/, "")
57
+ .replace(/^nuclei-/, "")
58
+ .toLowerCase();
59
+ const key = `${finding.url}|${finding.severity}|${normalizedRuleId}`;
60
+ const existing = seen.get(key);
61
+ if (!existing || finding.confidence > existing.confidence) {
62
+ seen.set(key, finding);
63
+ }
64
+ }
65
+ return Array.from(seen.values());
66
+ }
67
+ /**
68
+ * Run DAST scan with specified scanners
69
+ */
70
+ export async function runDASTScan(target, options) {
71
+ const startTime = new Date();
72
+ const scanners = options.scanners || ["zap", "nuclei"];
73
+ const policy = { ...DEFAULT_DAST_POLICY, ...options.policy };
74
+ logger.info("dast.scan_start", {
75
+ target: target.url,
76
+ scanners,
77
+ passiveOnly: policy.passiveOnly,
78
+ });
79
+ // Authorization check
80
+ if (!options.authorized) {
81
+ throw new Error("DAST scan requires explicit authorization. Set 'authorized: true' to confirm you have permission to scan the target.");
82
+ }
83
+ // Run selected scanners
84
+ const scanResults = [];
85
+ const runPromises = [];
86
+ if (scanners.includes("zap")) {
87
+ runPromises.push(runZap(target, policy));
88
+ }
89
+ if (scanners.includes("nuclei")) {
90
+ runPromises.push(runNuclei(target, policy));
91
+ }
92
+ const results = await Promise.all(runPromises);
93
+ scanResults.push(...results);
94
+ // Aggregate findings
95
+ const allFindings = [];
96
+ for (const result of scanResults) {
97
+ allFindings.push(...result.findings);
98
+ }
99
+ // Deduplicate
100
+ const uniqueFindings = deduplicateFindings(allFindings);
101
+ // Calculate stats
102
+ const bySeverity = {};
103
+ for (const finding of uniqueFindings) {
104
+ bySeverity[finding.severity] = (bySeverity[finding.severity] || 0) + 1;
105
+ }
106
+ const byScanner = {
107
+ zap: 0,
108
+ nuclei: 0,
109
+ };
110
+ for (const result of scanResults) {
111
+ byScanner[result.scanner] = result.findings.length;
112
+ }
113
+ const failedScanners = scanResults
114
+ .filter((r) => !r.success)
115
+ .map((r) => r.scanner);
116
+ const totalDuration = scanResults.reduce((sum, r) => sum + r.duration, 0);
117
+ const aggregated = {
118
+ timestamp: startTime.toISOString(),
119
+ target,
120
+ scanners: scanResults,
121
+ totalFindings: allFindings.length,
122
+ uniqueFindings,
123
+ bySeverity,
124
+ byScanner,
125
+ totalDuration,
126
+ allSucceeded: failedScanners.length === 0,
127
+ failedScanners,
128
+ };
129
+ logger.info("dast.scan_complete", {
130
+ totalFindings: allFindings.length,
131
+ uniqueFindings: uniqueFindings.length,
132
+ totalDuration,
133
+ allSucceeded: aggregated.allSucceeded,
134
+ });
135
+ return aggregated;
136
+ }
137
+ /**
138
+ * Quick passive scan (no active attacks)
139
+ */
140
+ export async function runPassiveScan(target, options) {
141
+ return runDASTScan(target, {
142
+ ...options,
143
+ authorized: true,
144
+ policy: {
145
+ ...options?.policy,
146
+ passiveOnly: true,
147
+ },
148
+ });
149
+ }
150
+ /**
151
+ * Format DAST findings for display
152
+ */
153
+ export function formatDASTFindings(findings) {
154
+ if (findings.length === 0) {
155
+ return "No vulnerabilities found.";
156
+ }
157
+ const lines = [
158
+ `## DAST Scan Results\n`,
159
+ `Found ${findings.length} unique vulnerabilities:\n`,
160
+ ];
161
+ // Group by severity
162
+ const bySeverity = new Map();
163
+ for (const finding of findings) {
164
+ const existing = bySeverity.get(finding.severity) || [];
165
+ existing.push(finding);
166
+ bySeverity.set(finding.severity, existing);
167
+ }
168
+ const severityOrder = ["critical", "high", "medium", "low", "info"];
169
+ for (const severity of severityOrder) {
170
+ const group = bySeverity.get(severity);
171
+ if (!group || group.length === 0)
172
+ continue;
173
+ const emoji = {
174
+ critical: "🔴",
175
+ high: "🟠",
176
+ medium: "🟡",
177
+ low: "🔵",
178
+ info: "⚪",
179
+ }[severity] || "⚪";
180
+ lines.push(`\n### ${emoji} ${severity.toUpperCase()} (${group.length})\n`);
181
+ for (const finding of group) {
182
+ lines.push(`- **${finding.name}** (${finding.scanner})`);
183
+ lines.push(` - URL: ${finding.url}`);
184
+ if (finding.cweIds?.length) {
185
+ lines.push(` - CWE: ${finding.cweIds.join(", ")}`);
186
+ }
187
+ if (finding.solution) {
188
+ lines.push(` - Fix: ${finding.solution.slice(0, 200)}${finding.solution.length > 200 ? "..." : ""}`);
189
+ }
190
+ }
191
+ }
192
+ return lines.join("\n");
193
+ }
194
+ /**
195
+ * Convert DAST findings to SARIF format
196
+ */
197
+ export function convertToSARIF(results) {
198
+ const rules = [];
199
+ const rulesSeen = new Set();
200
+ const sarif = {
201
+ $schema: "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
202
+ version: "2.1.0",
203
+ runs: [
204
+ {
205
+ tool: {
206
+ driver: {
207
+ name: "Vaspera DAST",
208
+ informationUri: "https://github.com/vaspera/hardening",
209
+ version: "1.0.0",
210
+ rules,
211
+ },
212
+ },
213
+ results: results.uniqueFindings.map((finding) => {
214
+ // Add rule if not seen
215
+ if (!rulesSeen.has(finding.ruleId)) {
216
+ rulesSeen.add(finding.ruleId);
217
+ rules.push({
218
+ id: finding.ruleId,
219
+ name: finding.name,
220
+ shortDescription: { text: finding.name },
221
+ fullDescription: finding.description ? { text: finding.description } : undefined,
222
+ defaultConfiguration: {
223
+ level: finding.severity === "critical" || finding.severity === "high" ? "error" :
224
+ finding.severity === "medium" ? "warning" : "note",
225
+ },
226
+ properties: finding.tags ? { tags: finding.tags } : undefined,
227
+ });
228
+ }
229
+ return {
230
+ ruleId: finding.ruleId,
231
+ level: finding.severity === "critical" || finding.severity === "high" ? "error" :
232
+ finding.severity === "medium" ? "warning" : "note",
233
+ message: {
234
+ text: finding.description || finding.name,
235
+ },
236
+ locations: [
237
+ {
238
+ physicalLocation: {
239
+ artifactLocation: {
240
+ uri: finding.url,
241
+ },
242
+ },
243
+ },
244
+ ],
245
+ properties: {
246
+ scanner: finding.scanner,
247
+ confidence: finding.confidence,
248
+ cweIds: finding.cweIds,
249
+ cveIds: finding.cveIds,
250
+ evidence: finding.evidence,
251
+ },
252
+ };
253
+ }),
254
+ },
255
+ ],
256
+ };
257
+ return sarif;
258
+ }
259
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/scanners/dast/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Nuclei Scanner Integration
3
+ *
4
+ * Integrates with ProjectDiscovery's Nuclei for dynamic
5
+ * application security testing using template-based scanning.
6
+ *
7
+ * @module scanners/dast/nuclei
8
+ */
9
+ import type { DASTTarget, DASTPolicy, DASTScanResult, DASTFinding, DASTAvailability, NucleiResult } from "./types.js";
10
+ /**
11
+ * Check if Nuclei is available
12
+ */
13
+ export declare function checkNucleiAvailable(): Promise<DASTAvailability>;
14
+ /**
15
+ * Parse Nuclei JSON line output to DASTFinding
16
+ */
17
+ export declare function parseNucleiResult(result: NucleiResult): DASTFinding;
18
+ /**
19
+ * Run Nuclei scan
20
+ */
21
+ export declare function runNuclei(target: DASTTarget, policy?: DASTPolicy): Promise<DASTScanResult>;
22
+ /**
23
+ * Get Nuclei installation instructions
24
+ */
25
+ export declare function getNucleiInstallInstructions(): string;
26
+ //# sourceMappingURL=nuclei.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nuclei.d.ts","sourceRoot":"","sources":["../../../src/scanners/dast/nuclei.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EACV,UAAU,EACV,UAAU,EACV,cAAc,EACd,WAAW,EACX,gBAAgB,EAChB,YAAY,EACb,MAAM,YAAY,CAAC;AAGpB;;GAEG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAkDtE;AAqGD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,YAAY,GAAG,WAAW,CAmCnE;AA8BD;;GAEG;AACH,wBAAsB,SAAS,CAC7B,MAAM,EAAE,UAAU,EAClB,MAAM,GAAE,UAAe,GACtB,OAAO,CAAC,cAAc,CAAC,CAgIzB;AAED;;GAEG;AACH,wBAAgB,4BAA4B,IAAI,MAAM,CAgCrD"}
@@ -0,0 +1,354 @@
1
+ /**
2
+ * Nuclei Scanner Integration
3
+ *
4
+ * Integrates with ProjectDiscovery's Nuclei for dynamic
5
+ * application security testing using template-based scanning.
6
+ *
7
+ * @module scanners/dast/nuclei
8
+ */
9
+ import spawn from "cross-spawn";
10
+ import { logger } from "../../logger.js";
11
+ import { NUCLEI_SEVERITY_MAPPING } from "./types.js";
12
+ /**
13
+ * Check if Nuclei is available
14
+ */
15
+ export async function checkNucleiAvailable() {
16
+ return new Promise((resolve) => {
17
+ const child = spawn("nuclei", ["-version"], { timeout: 10000 });
18
+ let stdout = "";
19
+ let stderr = "";
20
+ child.stdout?.on("data", (data) => {
21
+ stdout += data.toString();
22
+ });
23
+ child.stderr?.on("data", (data) => {
24
+ stderr += data.toString();
25
+ });
26
+ child.on("close", (code) => {
27
+ if (code === 0) {
28
+ // Parse version from output (e.g., "Nuclei Engine Version: v3.1.0")
29
+ const versionMatch = (stdout + stderr).match(/v?\d+\.\d+\.\d+/);
30
+ const version = versionMatch ? versionMatch[0] : "unknown";
31
+ resolve({
32
+ scanner: "nuclei",
33
+ available: true,
34
+ version,
35
+ path: "nuclei",
36
+ features: {
37
+ passiveScan: true,
38
+ activeScan: true,
39
+ apiScan: true,
40
+ authentication: true,
41
+ },
42
+ });
43
+ }
44
+ else {
45
+ resolve({
46
+ scanner: "nuclei",
47
+ available: false,
48
+ error: "Nuclei not found. Install via: go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest",
49
+ });
50
+ }
51
+ });
52
+ child.on("error", () => {
53
+ resolve({
54
+ scanner: "nuclei",
55
+ available: false,
56
+ error: "Nuclei not found. Install via: go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest",
57
+ });
58
+ });
59
+ });
60
+ }
61
+ /**
62
+ * Build Nuclei command arguments
63
+ */
64
+ function buildNucleiArgs(target, policy) {
65
+ const args = [
66
+ "-u", target.url,
67
+ "-json", // JSON output
68
+ "-silent", // Minimal output
69
+ "-no-color", // No ANSI colors
70
+ ];
71
+ // Add severity filter based on risk threshold
72
+ if (policy.riskThreshold) {
73
+ const severityMap = {
74
+ high: "critical,high",
75
+ medium: "critical,high,medium",
76
+ low: "critical,high,medium,low",
77
+ informational: "critical,high,medium,low,info",
78
+ };
79
+ args.push("-severity", severityMap[policy.riskThreshold] || "critical,high,medium");
80
+ }
81
+ // Add specific templates if provided
82
+ if (policy.templates && policy.templates.length > 0) {
83
+ for (const template of policy.templates) {
84
+ args.push("-t", template);
85
+ }
86
+ }
87
+ // Add template tags
88
+ if (policy.templateTags && policy.templateTags.length > 0) {
89
+ args.push("-tags", policy.templateTags.join(","));
90
+ }
91
+ // Exclude tags
92
+ if (policy.excludeTags && policy.excludeTags.length > 0) {
93
+ args.push("-etags", policy.excludeTags.join(","));
94
+ }
95
+ // Passive-only mode (no active exploitation)
96
+ if (policy.passiveOnly) {
97
+ args.push("-passive");
98
+ }
99
+ // Rate limiting
100
+ if (policy.requestDelay && policy.requestDelay > 0) {
101
+ // Nuclei uses rate-limit as requests per second
102
+ const rps = Math.floor(1000 / policy.requestDelay);
103
+ args.push("-rate-limit", String(Math.max(1, rps)));
104
+ }
105
+ // Concurrency
106
+ if (policy.threads) {
107
+ args.push("-concurrency", String(policy.threads));
108
+ }
109
+ // Add custom headers
110
+ if (target.headers) {
111
+ for (const [key, value] of Object.entries(target.headers)) {
112
+ args.push("-header", `${key}: ${value}`);
113
+ }
114
+ }
115
+ // Add authentication header
116
+ if (target.authentication) {
117
+ const auth = target.authentication;
118
+ switch (auth.type) {
119
+ case "bearer":
120
+ if (auth.credentials.token) {
121
+ args.push("-header", `Authorization: Bearer ${auth.credentials.token}`);
122
+ }
123
+ break;
124
+ case "basic":
125
+ if (auth.credentials.username && auth.credentials.password) {
126
+ const encoded = Buffer.from(`${auth.credentials.username}:${auth.credentials.password}`).toString("base64");
127
+ args.push("-header", `Authorization: Basic ${encoded}`);
128
+ }
129
+ break;
130
+ case "api-key":
131
+ if (auth.credentials.apiKey && auth.credentials.apiKeyHeader) {
132
+ args.push("-header", `${auth.credentials.apiKeyHeader}: ${auth.credentials.apiKey}`);
133
+ }
134
+ break;
135
+ case "cookie":
136
+ if (auth.credentials.cookie) {
137
+ args.push("-header", `Cookie: ${auth.credentials.cookie}`);
138
+ }
139
+ break;
140
+ }
141
+ }
142
+ return args;
143
+ }
144
+ /**
145
+ * Parse Nuclei JSON line output to DASTFinding
146
+ */
147
+ export function parseNucleiResult(result) {
148
+ const severity = NUCLEI_SEVERITY_MAPPING[result.info.severity] || "info";
149
+ // Extract CWE and CVE IDs
150
+ const cweIds = result.info.classification?.["cwe-id"]?.map((id) => id.startsWith("CWE-") ? id : `CWE-${id}`);
151
+ const cveIds = result.info.classification?.["cve-id"];
152
+ // Build references array
153
+ const references = [];
154
+ if (result.info.reference) {
155
+ references.push(...result.info.reference);
156
+ }
157
+ if (result["template-url"]) {
158
+ references.push(result["template-url"]);
159
+ }
160
+ return {
161
+ scanner: "nuclei",
162
+ ruleId: `nuclei-${result["template-id"]}`,
163
+ name: result.info.name,
164
+ description: result.info.description || `${result.info.name} detected`,
165
+ severity,
166
+ confidence: getConfidenceFromSeverity(result.info.severity),
167
+ url: result.matched || result.host,
168
+ method: extractMethod(result.request),
169
+ evidence: result["extracted-results"]?.join("\n"),
170
+ cweIds,
171
+ cveIds,
172
+ references,
173
+ tags: result.info.tags,
174
+ timestamp: result.timestamp || new Date().toISOString(),
175
+ rawOutput: result,
176
+ };
177
+ }
178
+ /**
179
+ * Extract HTTP method from curl command or request
180
+ */
181
+ function extractMethod(request) {
182
+ if (!request)
183
+ return undefined;
184
+ const methodMatch = request.match(/^(GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS)\s/);
185
+ return methodMatch ? methodMatch[1] : undefined;
186
+ }
187
+ /**
188
+ * Get confidence score based on severity
189
+ */
190
+ function getConfidenceFromSeverity(severity) {
191
+ switch (severity.toLowerCase()) {
192
+ case "critical":
193
+ return 95;
194
+ case "high":
195
+ return 90;
196
+ case "medium":
197
+ return 80;
198
+ case "low":
199
+ return 70;
200
+ default:
201
+ return 60;
202
+ }
203
+ }
204
+ /**
205
+ * Run Nuclei scan
206
+ */
207
+ export async function runNuclei(target, policy = {}) {
208
+ const startTime = new Date();
209
+ const mergedPolicy = { ...{ passiveOnly: true, maxDuration: 300, riskThreshold: "medium" }, ...policy };
210
+ logger.info("nuclei.scan_start", {
211
+ target: target.url,
212
+ passiveOnly: mergedPolicy.passiveOnly,
213
+ });
214
+ // Check availability
215
+ const availability = await checkNucleiAvailable();
216
+ if (!availability.available) {
217
+ return {
218
+ scanner: "nuclei",
219
+ target,
220
+ findings: [],
221
+ duration: Date.now() - startTime.getTime(),
222
+ success: false,
223
+ error: availability.error || "Nuclei not available",
224
+ stats: {
225
+ requestCount: 0,
226
+ urlsDiscovered: 0,
227
+ uniqueFindings: 0,
228
+ bySeverity: {},
229
+ },
230
+ startTime: startTime.toISOString(),
231
+ endTime: new Date().toISOString(),
232
+ policy: mergedPolicy,
233
+ };
234
+ }
235
+ return new Promise((resolve) => {
236
+ const args = buildNucleiArgs(target, mergedPolicy);
237
+ logger.debug("nuclei.command", { args: args.join(" ") });
238
+ const child = spawn("nuclei", args, {
239
+ timeout: (mergedPolicy.maxDuration || 300) * 1000,
240
+ });
241
+ let stdout = "";
242
+ let stderr = "";
243
+ child.stdout?.on("data", (data) => {
244
+ stdout += data.toString();
245
+ });
246
+ child.stderr?.on("data", (data) => {
247
+ stderr += data.toString();
248
+ });
249
+ child.on("close", (code) => {
250
+ const endTime = new Date();
251
+ const findings = [];
252
+ // Parse JSON lines output
253
+ const lines = stdout.split("\n").filter(Boolean);
254
+ for (const line of lines) {
255
+ try {
256
+ const result = JSON.parse(line);
257
+ findings.push(parseNucleiResult(result));
258
+ }
259
+ catch {
260
+ // Skip non-JSON lines
261
+ logger.debug("nuclei.parse_skip", { line: line.slice(0, 100) });
262
+ }
263
+ }
264
+ // Calculate stats
265
+ const bySeverity = {};
266
+ for (const finding of findings) {
267
+ bySeverity[finding.severity] = (bySeverity[finding.severity] || 0) + 1;
268
+ }
269
+ const success = code === 0 || findings.length > 0;
270
+ const result = {
271
+ scanner: "nuclei",
272
+ target,
273
+ findings,
274
+ duration: endTime.getTime() - startTime.getTime(),
275
+ success,
276
+ error: !success && stderr ? stderr.slice(0, 500) : undefined,
277
+ stats: {
278
+ requestCount: 0, // Not available from Nuclei output
279
+ urlsDiscovered: new Set(findings.map((f) => f.url)).size,
280
+ uniqueFindings: findings.length,
281
+ bySeverity,
282
+ },
283
+ version: availability.version,
284
+ startTime: startTime.toISOString(),
285
+ endTime: endTime.toISOString(),
286
+ policy: mergedPolicy,
287
+ };
288
+ logger.info("nuclei.scan_complete", {
289
+ findings: findings.length,
290
+ duration: result.duration,
291
+ success,
292
+ });
293
+ resolve(result);
294
+ });
295
+ child.on("error", (error) => {
296
+ const endTime = new Date();
297
+ resolve({
298
+ scanner: "nuclei",
299
+ target,
300
+ findings: [],
301
+ duration: endTime.getTime() - startTime.getTime(),
302
+ success: false,
303
+ error: String(error),
304
+ stats: {
305
+ requestCount: 0,
306
+ urlsDiscovered: 0,
307
+ uniqueFindings: 0,
308
+ bySeverity: {},
309
+ },
310
+ version: availability.version,
311
+ startTime: startTime.toISOString(),
312
+ endTime: endTime.toISOString(),
313
+ policy: mergedPolicy,
314
+ });
315
+ });
316
+ });
317
+ }
318
+ /**
319
+ * Get Nuclei installation instructions
320
+ */
321
+ export function getNucleiInstallInstructions() {
322
+ return `
323
+ # Nuclei Installation
324
+
325
+ ## Go (Recommended)
326
+ \`\`\`bash
327
+ go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest
328
+ \`\`\`
329
+
330
+ ## Homebrew (macOS)
331
+ \`\`\`bash
332
+ brew install nuclei
333
+ \`\`\`
334
+
335
+ ## Docker
336
+ \`\`\`bash
337
+ docker pull projectdiscovery/nuclei:latest
338
+ \`\`\`
339
+
340
+ ## Binary Download
341
+ Download from https://github.com/projectdiscovery/nuclei/releases
342
+
343
+ ## Update Templates
344
+ \`\`\`bash
345
+ nuclei -update-templates
346
+ \`\`\`
347
+
348
+ ## Verify Installation
349
+ \`\`\`bash
350
+ nuclei -version
351
+ \`\`\`
352
+ `;
353
+ }
354
+ //# sourceMappingURL=nuclei.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nuclei.js","sourceRoot":"","sources":["../../../src/scanners/dast/nuclei.ts"],"names":[],"mappings":"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"}