@voidagency/web-scanner 0.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 (59) hide show
  1. package/README.md +198 -0
  2. package/dist/aggregator.d.ts +65 -0
  3. package/dist/aggregator.d.ts.map +1 -0
  4. package/dist/aggregator.js +546 -0
  5. package/dist/aggregator.js.map +1 -0
  6. package/dist/categories.d.ts +59 -0
  7. package/dist/categories.d.ts.map +1 -0
  8. package/dist/categories.js +278 -0
  9. package/dist/categories.js.map +1 -0
  10. package/dist/cli.d.ts +12 -0
  11. package/dist/cli.d.ts.map +1 -0
  12. package/dist/cli.js +457 -0
  13. package/dist/cli.js.map +1 -0
  14. package/dist/config.d.ts +19 -0
  15. package/dist/config.d.ts.map +1 -0
  16. package/dist/config.js +121 -0
  17. package/dist/config.js.map +1 -0
  18. package/dist/coverage.d.ts +49 -0
  19. package/dist/coverage.d.ts.map +1 -0
  20. package/dist/coverage.js +165 -0
  21. package/dist/coverage.js.map +1 -0
  22. package/dist/enrichers/nvd.d.ts +55 -0
  23. package/dist/enrichers/nvd.d.ts.map +1 -0
  24. package/dist/enrichers/nvd.js +326 -0
  25. package/dist/enrichers/nvd.js.map +1 -0
  26. package/dist/report.d.ts +12 -0
  27. package/dist/report.d.ts.map +1 -0
  28. package/dist/report.js +460 -0
  29. package/dist/report.js.map +1 -0
  30. package/dist/runners/nuclei.d.ts +59 -0
  31. package/dist/runners/nuclei.d.ts.map +1 -0
  32. package/dist/runners/nuclei.js +531 -0
  33. package/dist/runners/nuclei.js.map +1 -0
  34. package/dist/runners/testssl.d.ts +16 -0
  35. package/dist/runners/testssl.d.ts.map +1 -0
  36. package/dist/runners/testssl.js +179 -0
  37. package/dist/runners/testssl.js.map +1 -0
  38. package/dist/runners/zap.d.ts +30 -0
  39. package/dist/runners/zap.d.ts.map +1 -0
  40. package/dist/runners/zap.js +389 -0
  41. package/dist/runners/zap.js.map +1 -0
  42. package/dist/types.d.ts +172 -0
  43. package/dist/types.d.ts.map +1 -0
  44. package/dist/types.js +6 -0
  45. package/dist/types.js.map +1 -0
  46. package/package.json +54 -0
  47. package/templates/drupal-api-index-exposed.yaml +81 -0
  48. package/templates/drupal-api-user-detail.yaml +76 -0
  49. package/templates/drupal-api-user-listing.yaml +59 -0
  50. package/templates/drupal-dev-files-exposed.yaml +73 -0
  51. package/templates/drupal-file-path-disclosure.yaml +59 -0
  52. package/templates/drupal-files-listing.yaml +63 -0
  53. package/templates/drupal-install-error-disclosure.yaml +62 -0
  54. package/templates/drupal-theme-lockfiles.yaml +79 -0
  55. package/templates/drupal-version-detect.yaml +89 -0
  56. package/templates/http-options-enabled.yaml +56 -0
  57. package/templates/nextjs-version-detect.yaml +35 -0
  58. package/templates/php-version-detect.yaml +37 -0
  59. package/zap.yaml +33 -0
@@ -0,0 +1,179 @@
1
+ /**
2
+ * testssl.sh Runner
3
+ * Execute SSL/TLS analysis and parse JSON output
4
+ */
5
+ import { execa } from 'execa';
6
+ import { readFile, unlink } from 'fs/promises';
7
+ import { join } from 'path';
8
+ import { tmpdir } from 'os';
9
+ // Scan options for each profile
10
+ const PROFILE_OPTIONS = {
11
+ quick: ['--protocols', '--vulnerable'],
12
+ standard: ['--protocols', '--vulnerable', '--cipher-per-proto'],
13
+ deep: [], // Full scan (no options = everything)
14
+ };
15
+ /**
16
+ * Map testssl severity to normalized severity
17
+ */
18
+ function mapSeverity(severity) {
19
+ const s = severity.toUpperCase();
20
+ if (s === 'CRITICAL')
21
+ return 'critical';
22
+ if (s === 'HIGH')
23
+ return 'high';
24
+ if (s === 'MEDIUM')
25
+ return 'medium';
26
+ if (s === 'LOW' || s === 'WARN')
27
+ return 'low';
28
+ return 'info';
29
+ }
30
+ /**
31
+ * IDs that indicate "not vulnerable" results - these have CVEs but are negative findings
32
+ */
33
+ const VULNERABILITY_TEST_IDS = [
34
+ 'heartbleed', 'CCS', 'ticketbleed', 'ROBOT', 'secure_client_renego',
35
+ 'CRIME_TLS', 'BREACH', 'POODLE_SSL', 'SWEET32', 'FREAK', 'DROWN',
36
+ 'DROWN_hint', 'LOGJAM', 'LOGJAM-common_primes', 'BEAST', 'winshock', 'RC4',
37
+ 'secure_renego', 'fallback_SCSV',
38
+ ];
39
+ /**
40
+ * IDs that are scanner errors, not target vulnerabilities
41
+ * These indicate issues with the local scanning environment
42
+ */
43
+ const SCANNER_ERROR_IDS = new Set([
44
+ 'engine_problem', // OpenSSL engine not available on scanner machine
45
+ 'scanProblem', // Generic scan issues
46
+ 'pre_128cipher', // Old cipher check issues
47
+ ]);
48
+ /**
49
+ * Vulnerability IDs to skip (too theoretical for web app pentests)
50
+ */
51
+ const SKIP_VULN_IDS = new Set([
52
+ 'BREACH', // Requires MITM + content injection, every site uses gzip
53
+ ]);
54
+ /**
55
+ * Parse testssl JSON output into findings
56
+ * Only include actual vulnerabilities, not "passed" tests
57
+ */
58
+ function parseTestsslOutput(data, startIndex) {
59
+ const findings = [];
60
+ for (const item of data) {
61
+ const severity = item.severity.toUpperCase();
62
+ // Skip OK/INFO items - these are "not vulnerable" or informational
63
+ // Even if they have CVEs, INFO means the test PASSED (not vulnerable)
64
+ if (['OK', 'INFO'].includes(severity)) {
65
+ continue;
66
+ }
67
+ // Skip LOW severity - cipher details, session tickets, etc.
68
+ // These are too granular for web app pentests and require MITM to exploit
69
+ if (['LOW', 'WARN'].includes(severity)) {
70
+ continue;
71
+ }
72
+ // Skip items without meaningful findings
73
+ if (!item.finding || item.finding === '--') {
74
+ continue;
75
+ }
76
+ // Skip scanner errors (local machine issues, not target vulnerabilities)
77
+ if (SCANNER_ERROR_IDS.has(item.id)) {
78
+ continue;
79
+ }
80
+ // Skip theoretical vulns not useful for web app pentests
81
+ if (SKIP_VULN_IDS.has(item.id)) {
82
+ continue;
83
+ }
84
+ // Skip findings that are scanner issues, not target vulnerabilities
85
+ if (item.finding.includes('No engine or GOST support')) {
86
+ continue;
87
+ }
88
+ // Skip certain verbose informational entries
89
+ if (item.id.startsWith('cert_') && severity === 'LOW') {
90
+ // Certificate info entries that aren't critical
91
+ continue;
92
+ }
93
+ findings.push({
94
+ id: String(startIndex + findings.length + 1).padStart(3, '0'),
95
+ title: formatTestsslTitle(item.id),
96
+ description: item.finding,
97
+ severity: mapSeverity(severity),
98
+ source: 'testssl',
99
+ target: `${item.ip}:${item.port}`,
100
+ cve: item.cve,
101
+ cwe: item.cwe,
102
+ tags: ['ssl', 'tls'],
103
+ });
104
+ }
105
+ return findings;
106
+ }
107
+ /**
108
+ * Format testssl ID into readable title
109
+ */
110
+ function formatTestsslTitle(id) {
111
+ // Convert snake_case to Title Case
112
+ return id
113
+ .replaceAll('_', ' ')
114
+ .replaceAll(/\b\w/g, c => c.toUpperCase())
115
+ .replaceAll('Ssl', 'SSL')
116
+ .replaceAll('Tls', 'TLS')
117
+ .replaceAll('Hsts', 'HSTS')
118
+ .replaceAll('Csp', 'CSP');
119
+ }
120
+ /**
121
+ * Run testssl.sh scan on target
122
+ */
123
+ export async function runTestssl(target, profile = 'standard', options = {}) {
124
+ // Create temp file for JSON output
125
+ const tempFile = join(tmpdir(), `testssl-${Date.now()}.json`);
126
+ // Extract host from URL if needed
127
+ let host;
128
+ try {
129
+ const url = new URL(target);
130
+ host = url.hostname;
131
+ // Add port if not default HTTPS
132
+ if (url.port && url.port !== '443') {
133
+ host = `${host}:${url.port}`;
134
+ }
135
+ }
136
+ catch {
137
+ host = target;
138
+ }
139
+ // Build command arguments
140
+ const profileOptions = PROFILE_OPTIONS[profile];
141
+ const args = [
142
+ '--jsonfile', tempFile,
143
+ '--quiet',
144
+ ...profileOptions,
145
+ host,
146
+ ];
147
+ try {
148
+ await execa('testssl.sh', args, {
149
+ reject: false, // Don't throw on non-zero exit
150
+ timeout: profile === 'deep' ? 600000 : 300000, // 10min for deep, 5min otherwise
151
+ });
152
+ // Read and parse JSON output
153
+ const jsonContent = await readFile(tempFile, 'utf-8');
154
+ const data = JSON.parse(jsonContent);
155
+ // Parse into findings
156
+ const findings = parseTestsslOutput(data, options.startIndex || 0);
157
+ // Clean up temp file
158
+ await unlink(tempFile).catch(() => { });
159
+ return findings;
160
+ }
161
+ catch (error) {
162
+ // Clean up temp file on error
163
+ await unlink(tempFile).catch(() => { });
164
+ throw new Error(`testssl scan failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
165
+ }
166
+ }
167
+ /**
168
+ * Check if testssl.sh is installed
169
+ */
170
+ export async function isTestsslInstalled() {
171
+ try {
172
+ await execa('testssl.sh', ['--version']);
173
+ return true;
174
+ }
175
+ catch {
176
+ return false;
177
+ }
178
+ }
179
+ //# sourceMappingURL=testssl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testssl.js","sourceRoot":"","sources":["../../src/runners/testssl.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * ZAP Runner - OWASP ZAP baseline scanner via Docker
3
+ * Primary scanner for:
4
+ * - JS Library CVEs (Retire.js)
5
+ * - Security Headers
6
+ * - CORS Misconfigurations
7
+ * - CSRF Detection
8
+ * - XSS Detection hints
9
+ */
10
+ import { Finding, TechDetection } from '../types.js';
11
+ /**
12
+ * Run ZAP baseline scan via Docker
13
+ */
14
+ export declare function runZap(target: string, options?: {
15
+ outputDir?: string;
16
+ timeout?: number;
17
+ onProgress?: (msg: string) => void;
18
+ }): Promise<{
19
+ findings: Finding[];
20
+ technologies: TechDetection[];
21
+ }>;
22
+ /**
23
+ * Check if Docker and ZAP image are available
24
+ */
25
+ export declare function checkZapAvailable(): Promise<boolean>;
26
+ /**
27
+ * Pull ZAP Docker image if not present
28
+ */
29
+ export declare function pullZapImage(onProgress?: (msg: string) => void): Promise<void>;
30
+ //# sourceMappingURL=zap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zap.d.ts","sourceRoot":"","sources":["../../src/runners/zap.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,EAAE,OAAO,EAAY,aAAa,EAAE,MAAM,aAAa,CAAC;AA0U/D;;GAEG;AACH,wBAAsB,MAAM,CAC1B,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;IACP,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/B,GACL,OAAO,CAAC;IAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;IAAC,YAAY,EAAE,aAAa,EAAE,CAAA;CAAE,CAAC,CA6FjE;AAED;;GAEG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,OAAO,CAAC,CAQ1D;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBpF"}
@@ -0,0 +1,389 @@
1
+ /**
2
+ * ZAP Runner - OWASP ZAP baseline scanner via Docker
3
+ * Primary scanner for:
4
+ * - JS Library CVEs (Retire.js)
5
+ * - Security Headers
6
+ * - CORS Misconfigurations
7
+ * - CSRF Detection
8
+ * - XSS Detection hints
9
+ */
10
+ import { execa } from 'execa';
11
+ import { readFile, unlink } from 'fs/promises';
12
+ import { existsSync } from 'fs';
13
+ import path from 'path';
14
+ /**
15
+ * ZAP plugin IDs to skip (noisy/not useful)
16
+ * List from https://www.zaproxy.org/docs/alerts/
17
+ *
18
+ * 10109 - Modern Web Application (just tells you it's a SPA, not a vulnerability)
19
+ * 10015 - Re-examine Cache-control Directives (usually false positive)
20
+ * 10049 - Non-Storable Content (informational, not actionable)
21
+ * 10050 - Retrieved from Cache (informational)
22
+ * 10054 - Cookie Without SameSite (often intentional)
23
+ * 10044 - Big Redirect Detected (normal for frameworks, not a real vuln)
24
+ * 10027 - Suspicious Comments (flags "username", "query" in JS - too noisy)
25
+ * 10112 - Session Management Response Identified (just says "found session token")
26
+ * 10017 - Cross-Domain JS (redundant with SRI Missing - same fix)
27
+ */
28
+ const SKIP_PLUGIN_IDS = new Set([
29
+ '10109', // Modern Web Application
30
+ '10015', // Re-examine Cache-control Directives
31
+ '10049', // Non-Storable Content
32
+ '10050', // Retrieved from Cache
33
+ '10044', // Big Redirect Detected
34
+ '10027', // Suspicious Comments
35
+ '10112', // Session Management Response Identified
36
+ '10017', // Cross-Domain JS (merged into SRI Missing)
37
+ '10096', // Timestamp Disclosure - Unix (build IDs, cache busters - not sensitive)
38
+ ]);
39
+ /**
40
+ * Alert names to skip (when plugin ID can't be used - e.g., shared IDs)
41
+ * All CSP alerts share plugin ID 10055, so filter by name
42
+ */
43
+ const SKIP_ALERT_NAMES = new Set([
44
+ 'CSP: Notices', // Informational only
45
+ 'CSP: X-Content-Security-Policy', // Deprecated header notice
46
+ 'CSP: X-WebKit-CSP', // Deprecated header notice
47
+ 'CSP: Header & Meta', // Just says you have both - not a vuln
48
+ ]);
49
+ /**
50
+ * Rename certain findings to be clearer/combined
51
+ */
52
+ const RENAME_FINDINGS = {
53
+ '90003': 'External JavaScript Without Integrity Verification',
54
+ };
55
+ /**
56
+ * Check if a CSRF finding should be filtered (Drupal uses its own form tokens)
57
+ */
58
+ function isDrupalCsrfFalsePositive(alert) {
59
+ if (alert.pluginid !== '10202')
60
+ return false; // Not CSRF alert
61
+ // Check if the form is a Drupal form (has drupal-selector or form_build_id)
62
+ const evidence = alert.instances[0]?.evidence || '';
63
+ return evidence.includes('data-drupal-selector') ||
64
+ evidence.includes('form_build_id') ||
65
+ evidence.includes('drupal');
66
+ }
67
+ /**
68
+ * Map ZAP risk code to our severity
69
+ */
70
+ function mapZapSeverity(riskcode) {
71
+ switch (riskcode) {
72
+ case '3': return 'high'; // ZAP doesn't have critical
73
+ case '2': return 'medium';
74
+ case '1': return 'low';
75
+ case '0': return 'info';
76
+ default: return 'info';
77
+ }
78
+ }
79
+ /**
80
+ * Extract CVEs from ZAP otherinfo field
81
+ * ZAP puts CVEs in the otherinfo for vulnerable JS libraries
82
+ */
83
+ function extractCves(otherinfo) {
84
+ const cvePattern = /CVE-\d{4}-\d+/g;
85
+ const matches = otherinfo.match(cvePattern);
86
+ return matches ? [...new Set(matches)] : [];
87
+ }
88
+ /**
89
+ * Extract technology/library info from ZAP findings
90
+ */
91
+ function extractTechFromZap(alerts) {
92
+ const techMap = new Map();
93
+ for (const alert of alerts) {
94
+ // Vulnerable JS Library findings contain library info
95
+ if (alert.pluginid === '10003') {
96
+ for (const instance of alert.instances) {
97
+ const host = new URL(instance.uri).hostname;
98
+ // Extract library name and version from evidence
99
+ const libMatch = alert.otherinfo.match(/library ([a-z-]+), version ([0-9.]+)/i);
100
+ if (libMatch) {
101
+ const tech = `${libMatch[1]}:${libMatch[2]}`;
102
+ if (!techMap.has(host)) {
103
+ techMap.set(host, new Set());
104
+ }
105
+ techMap.get(host).add(tech);
106
+ }
107
+ }
108
+ }
109
+ // Server version from headers
110
+ if (alert.pluginid === '10036' || alert.pluginid === '10037') {
111
+ for (const instance of alert.instances) {
112
+ const host = new URL(instance.uri).hostname;
113
+ if (instance.evidence) {
114
+ if (!techMap.has(host)) {
115
+ techMap.set(host, new Set());
116
+ }
117
+ techMap.get(host).add(instance.evidence);
118
+ }
119
+ }
120
+ }
121
+ }
122
+ return Array.from(techMap.entries()).map(([host, techs]) => ({
123
+ host,
124
+ technologies: Array.from(techs),
125
+ }));
126
+ }
127
+ /**
128
+ * Parse ZAP alert to Finding
129
+ */
130
+ function parseZapAlert(alert, index) {
131
+ const findings = [];
132
+ const severity = mapZapSeverity(alert.riskcode);
133
+ const cves = extractCves(alert.otherinfo);
134
+ // Clean HTML from descriptions
135
+ const cleanHtml = (html) => html
136
+ .replace(/<\/?p>/g, '\n')
137
+ .replace(/<[^>]+>/g, '')
138
+ .replace(/&quot;/g, '"')
139
+ .replace(/&amp;/g, '&')
140
+ .replace(/&lt;/g, '<')
141
+ .replace(/&gt;/g, '>')
142
+ .replace(/\n{3,}/g, '\n\n')
143
+ .trim();
144
+ // For JS library vulnerabilities, create one finding per CVE
145
+ if (alert.pluginid === '10003' && cves.length > 0) {
146
+ // Group by library
147
+ const libMatch = alert.otherinfo.match(/library ([a-z-]+), version ([0-9.]+)/i);
148
+ const libName = libMatch ? `${libMatch[1]} ${libMatch[2]}` : alert.name;
149
+ findings.push({
150
+ id: '', // Will be renumbered
151
+ title: `Vulnerable JS Library: ${libName}`,
152
+ description: cleanHtml(alert.desc),
153
+ severity: severity,
154
+ source: 'zap',
155
+ target: alert.instances[0]?.uri || '',
156
+ cve: cves.join(', '),
157
+ cwe: alert.cweid !== '-1' ? `CWE-${alert.cweid}` : undefined,
158
+ tags: ['js-library', 'cve', 'outdated-component'],
159
+ extracted: cves,
160
+ references: alert.reference ? [cleanHtml(alert.reference)] : [],
161
+ matcher: libName,
162
+ });
163
+ }
164
+ else {
165
+ // Standard finding - check for renamed titles
166
+ const title = RENAME_FINDINGS[alert.pluginid] || alert.name;
167
+ findings.push({
168
+ id: '',
169
+ title,
170
+ description: cleanHtml(alert.desc),
171
+ severity: severity,
172
+ source: 'zap',
173
+ target: alert.instances[0]?.uri || '',
174
+ cwe: alert.cweid !== '-1' ? `CWE-${alert.cweid}` : undefined,
175
+ tags: getZapTags(alert.pluginid, alert.name),
176
+ references: alert.reference ? [cleanHtml(alert.reference)] : [],
177
+ matcher: alert.instances[0]?.evidence || undefined,
178
+ request: alert.instances.length > 0 ?
179
+ `${alert.instances[0].method} ${alert.instances[0].uri}` : undefined,
180
+ });
181
+ }
182
+ return findings;
183
+ }
184
+ /**
185
+ * Map ZAP plugin IDs to tags for categorization
186
+ * Reference: https://www.zaproxy.org/docs/alerts/
187
+ */
188
+ function getZapTags(pluginid, name) {
189
+ const tags = ['zap'];
190
+ const tagMap = {
191
+ // Vulnerability Detection
192
+ '10003': ['js-library', 'cve', 'outdated-component'], // Vulnerable JS Library
193
+ '10202': ['csrf', 'security-misconfiguration'], // Absence of Anti-CSRF Tokens
194
+ '10031': ['xss', 'user-input'], // User Controllable HTML Attr (Potential XSS)
195
+ '10043': ['xss', 'user-input'], // User Controllable JS Event (XSS)
196
+ '40012': ['xss', 'reflected'], // Cross Site Scripting (Reflected)
197
+ '40014': ['xss', 'persistent'], // Cross Site Scripting (Persistent)
198
+ '40016': ['xss', 'dom'], // Cross Site Scripting (DOM Based)
199
+ '40018': ['sqli'], // SQL Injection
200
+ '6': ['lfi', 'path-traversal'], // Path Traversal
201
+ '7': ['rfi', 'file-inclusion'], // Remote File Inclusion
202
+ '90019': ['ssti', 'injection'], // Server Side Template Injection
203
+ '90020': ['ssrf'], // Server Side Request Forgery
204
+ '90021': ['xxe', 'injection'], // XML External Entity Attack
205
+ '90023': ['command-injection', 'rce'], // OS Command Injection
206
+ '20019': ['redirect', 'open-redirect'], // External Redirect
207
+ // Security Headers
208
+ '10038': ['csp', 'header', 'security-misconfiguration'], // CSP Header Not Set
209
+ '10020': ['clickjacking', 'header', 'security-misconfiguration'], // Anti-clickjacking Header
210
+ '10035': ['hsts', 'header', 'security-misconfiguration'], // Strict-Transport-Security
211
+ '10021': ['header', 'security-misconfiguration'], // X-Content-Type-Options Missing
212
+ '10063': ['permissions-policy', 'header'], // Permissions Policy Header
213
+ '90003': ['sri', 'integrity', 'security-misconfiguration'], // Sub Resource Integrity Missing
214
+ '90004': ['spectre', 'isolation', 'header'], // Spectre Vulnerability
215
+ // Information Disclosure
216
+ '10009': ['info-disclosure', 'version-leak'], // In Page Banner Information Leak
217
+ '10037': ['info-disclosure', 'version-leak', 'header'], // X-Powered-By Leak
218
+ '10036': ['info-disclosure', 'version-leak', 'header'], // Server Header Leak
219
+ '10039': ['info-disclosure', 'header'], // X-Backend-Server Leak
220
+ '10023': ['info-disclosure', 'debug-errors'], // Debug Error Messages
221
+ '10044': ['redirect', 'info-disclosure'], // Big Redirect
222
+ '10027': ['info-disclosure', 'comments'], // Suspicious Comments
223
+ '2': ['info-disclosure', 'private-ip'], // Private IP Disclosure
224
+ '10062': ['info-disclosure', 'pii'], // PII Disclosure
225
+ // Cookie Issues
226
+ '10010': ['cookie', 'httponly'], // Cookie No HttpOnly
227
+ '10011': ['cookie', 'secure-flag'], // Cookie Without Secure Flag
228
+ '10054': ['cookie', 'samesite'], // Cookie without SameSite
229
+ // CORS & Cross-Domain
230
+ '10098': ['cors', 'security-misconfiguration'], // Cross-Domain Misconfiguration
231
+ '10017': ['cross-domain', 'js-inclusion'], // Cross-Domain JS Source Inclusion
232
+ // Directory & File Issues
233
+ '0': ['directory-listing'], // Directory Browsing (Active)
234
+ '10033': ['directory-listing'], // Directory Browsing (Passive)
235
+ '10095': ['backup-files', 'sensitive-files'], // Backup File Disclosure
236
+ '10045': ['source-disclosure', 'sensitive-files'], // Source Code Disclosure - WEB-INF
237
+ '10099': ['source-disclosure', 'php'], // Source Code Disclosure - PHP
238
+ // TLS/SSL Issues
239
+ '10034': ['heartbleed', 'ssl', 'cve'], // Heartbleed (Indicative)
240
+ '20015': ['heartbleed', 'ssl', 'cve'], // Heartbleed (Active)
241
+ '10040': ['mixed-content', 'ssl'], // Mixed Content
242
+ '10041': ['insecure-form', 'ssl'], // HTTP to HTTPS Insecure Transition
243
+ '10042': ['insecure-form', 'ssl'], // HTTPS to HTTP Insecure Transition
244
+ // Session & Auth
245
+ '3': ['session', 'url-rewrite'], // Session ID in URL Rewrite
246
+ '10105': ['auth', 'weak-auth'], // Weak Authentication Method
247
+ '10108': ['tabnabbing', 'security-misconfiguration'], // Reverse Tabnabbing
248
+ // Informational (mostly filtered)
249
+ '10109': ['modern-app', 'spa'], // Modern Web Application
250
+ '10015': ['cache', 'header'], // Re-examine Cache-control
251
+ '10110': ['dangerous-js', 'code-quality'], // Dangerous JS Functions
252
+ '10004': ['tech-detection'], // Tech Detection
253
+ '10112': ['session', 'informational'], // Session Management Response
254
+ '10111': ['auth', 'informational'], // Authentication Request Identified
255
+ };
256
+ if (tagMap[pluginid]) {
257
+ tags.push(...tagMap[pluginid]);
258
+ }
259
+ // Add tags based on name
260
+ if (name.toLowerCase().includes('header'))
261
+ tags.push('header');
262
+ if (name.toLowerCase().includes('xss'))
263
+ tags.push('xss');
264
+ if (name.toLowerCase().includes('csrf'))
265
+ tags.push('csrf');
266
+ return [...new Set(tags)];
267
+ }
268
+ /**
269
+ * Run ZAP baseline scan via Docker
270
+ */
271
+ export async function runZap(target, options = {}) {
272
+ const outputDir = options.outputDir || process.cwd();
273
+ const jsonFile = path.join(outputDir, 'zap-report.json');
274
+ const timeout = options.timeout || 300; // 5 minutes default
275
+ // Clean up old report if exists
276
+ if (existsSync(jsonFile)) {
277
+ await unlink(jsonFile);
278
+ }
279
+ options.onProgress?.('Starting ZAP baseline scan via Docker...');
280
+ try {
281
+ // Run ZAP baseline scan
282
+ // -t target URL
283
+ // -J json output filename
284
+ // -I don't return error on warnings
285
+ // -d debug mode for more output
286
+ const args = [
287
+ 'run',
288
+ '--rm',
289
+ '-v', `${outputDir}:/zap/wrk/:rw`,
290
+ '-t',
291
+ 'ghcr.io/zaproxy/zaproxy:stable',
292
+ 'zap-baseline.py',
293
+ '-t', target,
294
+ '-J', 'zap-report.json',
295
+ '-I', // Don't fail on warnings
296
+ ];
297
+ options.onProgress?.(`Running: docker ${args.slice(0, 5).join(' ')}...`);
298
+ await execa('docker', args, {
299
+ timeout: timeout * 1000,
300
+ reject: false, // Don't throw on non-zero exit
301
+ });
302
+ // Check if report was generated
303
+ if (!existsSync(jsonFile)) {
304
+ throw new Error('ZAP did not generate report file');
305
+ }
306
+ // Parse the report
307
+ options.onProgress?.('Parsing ZAP results...');
308
+ const reportContent = await readFile(jsonFile, 'utf-8');
309
+ const report = JSON.parse(reportContent);
310
+ const allFindings = [];
311
+ const allTechnologies = [];
312
+ // Process each site
313
+ for (const site of report.site || []) {
314
+ const alerts = site.alerts || [];
315
+ // Extract technologies
316
+ const techs = extractTechFromZap(alerts);
317
+ allTechnologies.push(...techs);
318
+ // Convert alerts to findings (skip noisy ones)
319
+ for (let i = 0; i < alerts.length; i++) {
320
+ // Skip noisy/non-actionable alerts by plugin ID
321
+ if (SKIP_PLUGIN_IDS.has(alerts[i].pluginid)) {
322
+ continue;
323
+ }
324
+ // Skip noisy alerts by name (when plugin ID is shared)
325
+ if (SKIP_ALERT_NAMES.has(alerts[i].name)) {
326
+ continue;
327
+ }
328
+ // Skip Drupal CSRF false positives (Drupal uses form tokens)
329
+ if (isDrupalCsrfFalsePositive(alerts[i])) {
330
+ continue;
331
+ }
332
+ const findings = parseZapAlert(alerts[i], i);
333
+ allFindings.push(...findings);
334
+ }
335
+ }
336
+ // Clean up report file
337
+ try {
338
+ await unlink(jsonFile);
339
+ }
340
+ catch {
341
+ // Ignore cleanup errors
342
+ }
343
+ options.onProgress?.(`ZAP found ${allFindings.length} issues`);
344
+ return { findings: allFindings, technologies: allTechnologies };
345
+ }
346
+ catch (error) {
347
+ if (error instanceof Error && error.message.includes('ETIMEDOUT')) {
348
+ throw new Error(`ZAP scan timed out after ${timeout} seconds`);
349
+ }
350
+ throw new Error(`ZAP scan failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
351
+ }
352
+ }
353
+ /**
354
+ * Check if Docker and ZAP image are available
355
+ */
356
+ export async function checkZapAvailable() {
357
+ try {
358
+ // Check Docker is running
359
+ await execa('docker', ['info'], { reject: true });
360
+ return true;
361
+ }
362
+ catch {
363
+ return false;
364
+ }
365
+ }
366
+ /**
367
+ * Pull ZAP Docker image if not present
368
+ */
369
+ export async function pullZapImage(onProgress) {
370
+ onProgress?.('Checking ZAP Docker image...');
371
+ try {
372
+ // Check if image exists
373
+ const { stdout } = await execa('docker', [
374
+ 'images', '-q', 'ghcr.io/zaproxy/zaproxy:stable'
375
+ ]);
376
+ if (!stdout.trim()) {
377
+ onProgress?.('Pulling ZAP Docker image (this may take a few minutes)...');
378
+ await execa('docker', ['pull', 'ghcr.io/zaproxy/zaproxy:stable']);
379
+ onProgress?.('ZAP image downloaded successfully');
380
+ }
381
+ else {
382
+ onProgress?.('ZAP image already available');
383
+ }
384
+ }
385
+ catch (error) {
386
+ throw new Error(`Failed to pull ZAP image: ${error instanceof Error ? error.message : 'Unknown error'}`);
387
+ }
388
+ }
389
+ //# sourceMappingURL=zap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zap.js","sourceRoot":"","sources":["../../src/runners/zap.ts"],"names":[],"mappings":"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"}