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.
- package/CHANGELOG.md +68 -0
- package/README.md +58 -1
- package/dist/__tests__/autofix/branch-manager.test.d.ts +2 -0
- package/dist/__tests__/autofix/branch-manager.test.d.ts.map +1 -0
- package/dist/__tests__/autofix/branch-manager.test.js +60 -0
- package/dist/__tests__/autofix/branch-manager.test.js.map +1 -0
- package/dist/__tests__/autofix/commit-generator.test.d.ts +2 -0
- package/dist/__tests__/autofix/commit-generator.test.d.ts.map +1 -0
- package/dist/__tests__/autofix/commit-generator.test.js +147 -0
- package/dist/__tests__/autofix/commit-generator.test.js.map +1 -0
- package/dist/__tests__/autofix/constitution.test.d.ts +9 -0
- package/dist/__tests__/autofix/constitution.test.d.ts.map +1 -0
- package/dist/__tests__/autofix/constitution.test.js +421 -0
- package/dist/__tests__/autofix/constitution.test.js.map +1 -0
- package/dist/__tests__/autofix/pr-generator.test.d.ts +2 -0
- package/dist/__tests__/autofix/pr-generator.test.d.ts.map +1 -0
- package/dist/__tests__/autofix/pr-generator.test.js +152 -0
- package/dist/__tests__/autofix/pr-generator.test.js.map +1 -0
- package/dist/__tests__/property-test-helpers.d.ts +87 -0
- package/dist/__tests__/property-test-helpers.d.ts.map +1 -0
- package/dist/__tests__/property-test-helpers.js +136 -0
- package/dist/__tests__/property-test-helpers.js.map +1 -0
- package/dist/__tests__/scanners/dast/index.test.d.ts +2 -0
- package/dist/__tests__/scanners/dast/index.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/dast/index.test.js +183 -0
- package/dist/__tests__/scanners/dast/index.test.js.map +1 -0
- package/dist/__tests__/scanners/dast/nuclei.test.d.ts +2 -0
- package/dist/__tests__/scanners/dast/nuclei.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/dast/nuclei.test.js +166 -0
- package/dist/__tests__/scanners/dast/nuclei.test.js.map +1 -0
- package/dist/__tests__/scanners/dast/zap.test.d.ts +2 -0
- package/dist/__tests__/scanners/dast/zap.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/dast/zap.test.js +158 -0
- package/dist/__tests__/scanners/dast/zap.test.js.map +1 -0
- package/dist/__tests__/scanners/fp-feedback.test.d.ts +2 -0
- package/dist/__tests__/scanners/fp-feedback.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/fp-feedback.test.js +202 -0
- package/dist/__tests__/scanners/fp-feedback.test.js.map +1 -0
- package/dist/__tests__/scanners/fp-filter.property.test.d.ts +9 -0
- package/dist/__tests__/scanners/fp-filter.property.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/fp-filter.property.test.js +253 -0
- package/dist/__tests__/scanners/fp-filter.property.test.js.map +1 -0
- package/dist/__tests__/scanners/fp-filter.test.d.ts +2 -0
- package/dist/__tests__/scanners/fp-filter.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/fp-filter.test.js +234 -0
- package/dist/__tests__/scanners/fp-filter.test.js.map +1 -0
- package/dist/__tests__/scanners/fp-tracker.test.d.ts +2 -0
- package/dist/__tests__/scanners/fp-tracker.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/fp-tracker.test.js +262 -0
- package/dist/__tests__/scanners/fp-tracker.test.js.map +1 -0
- package/dist/__tests__/scanners/logic/endpoint-analyzer.property.test.d.ts +10 -0
- package/dist/__tests__/scanners/logic/endpoint-analyzer.property.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/logic/endpoint-analyzer.property.test.js +238 -0
- package/dist/__tests__/scanners/logic/endpoint-analyzer.property.test.js.map +1 -0
- package/dist/__tests__/scanners/logic/endpoint-analyzer.test.d.ts +2 -0
- package/dist/__tests__/scanners/logic/endpoint-analyzer.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/logic/endpoint-analyzer.test.js +55 -0
- package/dist/__tests__/scanners/logic/endpoint-analyzer.test.js.map +1 -0
- package/dist/__tests__/scanners/logic/index.test.d.ts +2 -0
- package/dist/__tests__/scanners/logic/index.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/logic/index.test.js +165 -0
- package/dist/__tests__/scanners/logic/index.test.js.map +1 -0
- package/dist/__tests__/scanners/logic/types.test.d.ts +2 -0
- package/dist/__tests__/scanners/logic/types.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/logic/types.test.js +85 -0
- package/dist/__tests__/scanners/logic/types.test.js.map +1 -0
- package/dist/action/pr-comment.test.js +4 -0
- package/dist/action/pr-comment.test.js.map +1 -1
- package/dist/action/sarif-upload.test.js +4 -0
- package/dist/action/sarif-upload.test.js.map +1 -1
- package/dist/autofix/branch-manager.d.ts +115 -0
- package/dist/autofix/branch-manager.d.ts.map +1 -0
- package/dist/autofix/branch-manager.js +308 -0
- package/dist/autofix/branch-manager.js.map +1 -0
- package/dist/autofix/commit-generator.d.ts +55 -0
- package/dist/autofix/commit-generator.d.ts.map +1 -0
- package/dist/autofix/commit-generator.js +277 -0
- package/dist/autofix/commit-generator.js.map +1 -0
- package/dist/autofix/constitution.d.ts +77 -0
- package/dist/autofix/constitution.d.ts.map +1 -0
- package/dist/autofix/constitution.js +261 -0
- package/dist/autofix/constitution.js.map +1 -0
- package/dist/autofix/constitution.schema.d.ts +441 -0
- package/dist/autofix/constitution.schema.d.ts.map +1 -0
- package/dist/autofix/constitution.schema.js +144 -0
- package/dist/autofix/constitution.schema.js.map +1 -0
- package/dist/autofix/index.d.ts +13 -0
- package/dist/autofix/index.d.ts.map +1 -0
- package/dist/autofix/index.js +15 -0
- package/dist/autofix/index.js.map +1 -0
- package/dist/autofix/pr-generator.d.ts +57 -0
- package/dist/autofix/pr-generator.d.ts.map +1 -0
- package/dist/autofix/pr-generator.js +597 -0
- package/dist/autofix/pr-generator.js.map +1 -0
- package/dist/autofix/types.d.ts +151 -0
- package/dist/autofix/types.d.ts.map +1 -0
- package/dist/autofix/types.js +22 -0
- package/dist/autofix/types.js.map +1 -0
- package/dist/eval/fixtures.d.ts +20 -0
- package/dist/eval/fixtures.d.ts.map +1 -1
- package/dist/eval/fixtures.js +430 -0
- package/dist/eval/fixtures.js.map +1 -1
- package/dist/scanners/cache.d.ts.map +1 -1
- package/dist/scanners/cache.js +4 -0
- package/dist/scanners/cache.js.map +1 -1
- package/dist/scanners/dast/index.d.ts +39 -0
- package/dist/scanners/dast/index.d.ts.map +1 -0
- package/dist/scanners/dast/index.js +259 -0
- package/dist/scanners/dast/index.js.map +1 -0
- package/dist/scanners/dast/nuclei.d.ts +26 -0
- package/dist/scanners/dast/nuclei.d.ts.map +1 -0
- package/dist/scanners/dast/nuclei.js +354 -0
- package/dist/scanners/dast/nuclei.js.map +1 -0
- package/dist/scanners/dast/types.d.ts +306 -0
- package/dist/scanners/dast/types.d.ts.map +1 -0
- package/dist/scanners/dast/types.js +52 -0
- package/dist/scanners/dast/types.js.map +1 -0
- package/dist/scanners/dast/zap.d.ts +26 -0
- package/dist/scanners/dast/zap.d.ts.map +1 -0
- package/dist/scanners/dast/zap.js +453 -0
- package/dist/scanners/dast/zap.js.map +1 -0
- package/dist/scanners/fp-feedback.d.ts +140 -0
- package/dist/scanners/fp-feedback.d.ts.map +1 -0
- package/dist/scanners/fp-feedback.js +292 -0
- package/dist/scanners/fp-feedback.js.map +1 -0
- package/dist/scanners/fp-filter.d.ts +94 -0
- package/dist/scanners/fp-filter.d.ts.map +1 -0
- package/dist/scanners/fp-filter.js +397 -0
- package/dist/scanners/fp-filter.js.map +1 -0
- package/dist/scanners/fp-tracker.d.ts +125 -0
- package/dist/scanners/fp-tracker.d.ts.map +1 -0
- package/dist/scanners/fp-tracker.js +330 -0
- package/dist/scanners/fp-tracker.js.map +1 -0
- package/dist/scanners/index.d.ts.map +1 -1
- package/dist/scanners/index.js +56 -0
- package/dist/scanners/index.js.map +1 -1
- package/dist/scanners/index.test.js +6 -6
- package/dist/scanners/index.test.js.map +1 -1
- package/dist/scanners/logic/auth-flow-analyzer.d.ts +18 -0
- package/dist/scanners/logic/auth-flow-analyzer.d.ts.map +1 -0
- package/dist/scanners/logic/auth-flow-analyzer.js +384 -0
- package/dist/scanners/logic/auth-flow-analyzer.js.map +1 -0
- package/dist/scanners/logic/endpoint-analyzer.d.ts +29 -0
- package/dist/scanners/logic/endpoint-analyzer.d.ts.map +1 -0
- package/dist/scanners/logic/endpoint-analyzer.js +528 -0
- package/dist/scanners/logic/endpoint-analyzer.js.map +1 -0
- package/dist/scanners/logic/index.d.ts +41 -0
- package/dist/scanners/logic/index.d.ts.map +1 -0
- package/dist/scanners/logic/index.js +268 -0
- package/dist/scanners/logic/index.js.map +1 -0
- package/dist/scanners/logic/types.d.ts +254 -0
- package/dist/scanners/logic/types.d.ts.map +1 -0
- package/dist/scanners/logic/types.js +142 -0
- package/dist/scanners/logic/types.js.map +1 -0
- package/dist/scanners/types.d.ts +1 -1
- package/dist/scanners/types.d.ts.map +1 -1
- package/dist/scanners/types.js +4 -0
- package/dist/scanners/types.js.map +1 -1
- 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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"}
|