@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,49 @@
1
+ /**
2
+ * Test Coverage Tracker
3
+ * Tracks which test categories were run and their results
4
+ */
5
+ import { Finding } from './types.js';
6
+ import { CategoryResult } from './categories.js';
7
+ /**
8
+ * Coverage summary for reporting
9
+ */
10
+ export interface CoverageSummary {
11
+ totalCategories: number;
12
+ testedCategories: number;
13
+ categoriesWithFindings: number;
14
+ results: CategoryResult[];
15
+ }
16
+ /**
17
+ * Calculate test coverage from findings
18
+ * Each finding is counted in only ONE category (its best/first match)
19
+ * to avoid double-counting
20
+ */
21
+ export declare function calculateCoverage(findings: Finding[]): CoverageSummary;
22
+ /**
23
+ * Mark categories as tested based on scan profile
24
+ * In deep/standard profiles, we run more templates so more categories are "tested"
25
+ */
26
+ export declare function markTestedCategories(coverage: CoverageSummary, profile: 'quick' | 'standard' | 'deep', ranTemplates: string[]): CoverageSummary;
27
+ /**
28
+ * Format coverage for CLI output
29
+ */
30
+ export declare function formatCoverageForCli(coverage: CoverageSummary): string;
31
+ /**
32
+ * Get coverage data for HTML report
33
+ */
34
+ export declare function getCoverageForReport(coverage: CoverageSummary): Array<{
35
+ name: string;
36
+ description: string;
37
+ tested: boolean;
38
+ status: 'pass' | 'fail' | 'info' | 'untested';
39
+ count: number;
40
+ }>;
41
+ /**
42
+ * Get passed security checks for the report footer
43
+ * Shows all tested categories with 0 findings
44
+ */
45
+ export declare function getPassedChecksForReport(coverage: CoverageSummary): Array<{
46
+ name: string;
47
+ description: string;
48
+ }>;
49
+ //# sourceMappingURL=coverage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coverage.d.ts","sourceRoot":"","sources":["../src/coverage.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAGL,cAAc,EAGf,MAAM,iBAAiB,CAAC;AAEzB;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,OAAO,EAAE,cAAc,EAAE,CAAC;CAC3B;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,eAAe,CAgEtE;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,eAAe,EACzB,OAAO,EAAE,OAAO,GAAG,UAAU,GAAG,MAAM,EACtC,YAAY,EAAE,MAAM,EAAE,GACrB,eAAe,CAoDjB;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,CAwBtE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,eAAe,GAAG,KAAK,CAAC;IACrE,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,UAAU,CAAC;IAC9C,KAAK,EAAE,MAAM,CAAC;CACf,CAAC,CAcD;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,eAAe,GAAG,KAAK,CAAC;IACzE,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC,CAQD"}
@@ -0,0 +1,165 @@
1
+ /**
2
+ * Test Coverage Tracker
3
+ * Tracks which test categories were run and their results
4
+ */
5
+ import { TEST_CATEGORIES, matchCategories } from './categories.js';
6
+ /**
7
+ * Calculate test coverage from findings
8
+ * Each finding is counted in only ONE category (its best/first match)
9
+ * to avoid double-counting
10
+ */
11
+ export function calculateCoverage(findings) {
12
+ // Initialize results for all categories
13
+ const categoryResults = new Map();
14
+ for (const category of TEST_CATEGORIES) {
15
+ categoryResults.set(category.id, {
16
+ category,
17
+ tested: false,
18
+ findingCount: 0,
19
+ findings: [],
20
+ });
21
+ }
22
+ // Track which findings have been assigned
23
+ const assignedFindings = new Set();
24
+ // Process each finding - assign to FIRST matching category only
25
+ for (const finding of findings) {
26
+ if (assignedFindings.has(finding.id))
27
+ continue;
28
+ const categories = matchCategories(finding.templateId || '', finding.tags || []);
29
+ // Only count in the FIRST (most specific) matching category
30
+ if (categories.length > 0) {
31
+ const categoryId = categories[0];
32
+ const result = categoryResults.get(categoryId);
33
+ if (result) {
34
+ result.tested = true;
35
+ result.findingCount++;
36
+ result.findings.push(finding.id);
37
+ assignedFindings.add(finding.id);
38
+ }
39
+ }
40
+ }
41
+ // Also mark categories as "tested" if templates ran (even with 0 findings)
42
+ for (const finding of findings) {
43
+ const categories = matchCategories(finding.templateId || '', finding.tags || []);
44
+ for (const categoryId of categories) {
45
+ const result = categoryResults.get(categoryId);
46
+ if (result) {
47
+ result.tested = true;
48
+ }
49
+ }
50
+ }
51
+ // Convert to array and calculate summary
52
+ const results = Array.from(categoryResults.values());
53
+ // Mark categories as "tested" if we ran templates that would have found them
54
+ // (For now, we mark all categories as tested in standard/deep profiles)
55
+ return {
56
+ totalCategories: TEST_CATEGORIES.length,
57
+ testedCategories: results.filter(r => r.tested).length,
58
+ categoriesWithFindings: results.filter(r => r.findingCount > 0).length,
59
+ results,
60
+ };
61
+ }
62
+ /**
63
+ * Mark categories as tested based on scan profile
64
+ * In deep/standard profiles, we run more templates so more categories are "tested"
65
+ */
66
+ export function markTestedCategories(coverage, profile, ranTemplates) {
67
+ // Categories that are always tested (basic checks)
68
+ const alwaysTested = [
69
+ 'security-headers',
70
+ 'tech-detection',
71
+ 'admin-panels',
72
+ 'misconfigurations',
73
+ ];
74
+ // Additional categories for standard profile
75
+ const standardTested = [
76
+ 'sensitive-files',
77
+ 'info-disclosure',
78
+ 'directory-listing',
79
+ 'api-endpoints',
80
+ 'client-policies',
81
+ 'http-methods',
82
+ 'known-cves',
83
+ ];
84
+ // Additional categories for deep profile (fuzzing)
85
+ const deepTested = [
86
+ 'xss',
87
+ 'sqli',
88
+ 'lfi',
89
+ 'rce',
90
+ 'ssrf',
91
+ 'redirect',
92
+ ];
93
+ // Determine which categories were tested based on profile
94
+ let testedIds = [...alwaysTested];
95
+ if (profile === 'standard' || profile === 'deep') {
96
+ testedIds = [...testedIds, ...standardTested];
97
+ }
98
+ if (profile === 'deep') {
99
+ testedIds = [...testedIds, ...deepTested];
100
+ }
101
+ // Mark categories as tested
102
+ for (const result of coverage.results) {
103
+ if (testedIds.includes(result.category.id)) {
104
+ result.tested = true;
105
+ }
106
+ }
107
+ // Recalculate summary
108
+ coverage.testedCategories = coverage.results.filter(r => r.tested).length;
109
+ return coverage;
110
+ }
111
+ /**
112
+ * Format coverage for CLI output
113
+ */
114
+ export function formatCoverageForCli(coverage) {
115
+ const lines = [];
116
+ lines.push('\nTest Coverage:');
117
+ lines.push('─'.repeat(50));
118
+ for (const result of coverage.results) {
119
+ if (!result.tested)
120
+ continue; // Skip untested categories
121
+ const icon = result.findingCount > 0 ? '⚠️' : '✅';
122
+ const count = result.findingCount > 0
123
+ ? ` (${result.findingCount} issue${result.findingCount > 1 ? 's' : ''})`
124
+ : '';
125
+ const status = result.findingCount > 0
126
+ ? `${result.findingCount} found`
127
+ : 'Nothing found';
128
+ lines.push(`${icon} ${result.category.name} - ${status}`);
129
+ }
130
+ lines.push('─'.repeat(50));
131
+ lines.push(`Tested: ${coverage.testedCategories}/${coverage.totalCategories} categories`);
132
+ return lines.join('\n');
133
+ }
134
+ /**
135
+ * Get coverage data for HTML report
136
+ */
137
+ export function getCoverageForReport(coverage) {
138
+ return coverage.results.map(result => ({
139
+ name: result.category.name,
140
+ description: result.category.description,
141
+ tested: result.tested,
142
+ status: !result.tested
143
+ ? 'untested'
144
+ : result.findingCount === 0
145
+ ? 'pass'
146
+ : result.category.id === 'tech-detection'
147
+ ? 'info'
148
+ : 'fail',
149
+ count: result.findingCount,
150
+ }));
151
+ }
152
+ /**
153
+ * Get passed security checks for the report footer
154
+ * Shows all tested categories with 0 findings
155
+ */
156
+ export function getPassedChecksForReport(coverage) {
157
+ return coverage.results
158
+ .filter(result => result.tested && result.findingCount === 0)
159
+ .filter(result => result.category.id !== 'tech-detection') // Exclude tech detection (not a "security check")
160
+ .map(result => ({
161
+ name: result.category.name,
162
+ description: result.category.description,
163
+ }));
164
+ }
165
+ //# sourceMappingURL=coverage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coverage.js","sourceRoot":"","sources":["../src/coverage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * NVD API Enrichment
3
+ * Query NIST NVD for CVE details, CVSS scores, descriptions
4
+ *
5
+ * API Docs: https://nvd.nist.gov/developers/vulnerabilities
6
+ */
7
+ export interface NvdCveData {
8
+ id: string;
9
+ description: string;
10
+ cvssScore?: number;
11
+ cvssVector?: string;
12
+ cweId?: string;
13
+ cweDescription?: string;
14
+ references: string[];
15
+ published?: string;
16
+ lastModified?: string;
17
+ }
18
+ export interface NvdEnrichment {
19
+ description: string;
20
+ cvssScore?: number;
21
+ cvssVector?: string;
22
+ cweId?: string;
23
+ references: string[];
24
+ }
25
+ /**
26
+ * Query NVD API for a specific CVE
27
+ */
28
+ export declare function getCveDetails(cveId: string): Promise<NvdCveData | null>;
29
+ /**
30
+ * Query NVD for CVEs affecting a specific software version (by CPE)
31
+ */
32
+ export declare function getCvesByCpe(vendor: string, product: string, version: string, limit?: number): Promise<NvdCveData[]>;
33
+ /**
34
+ * Get CPE mapping for a technology name
35
+ */
36
+ export declare function getCpeMapping(techName: string): {
37
+ vendor: string;
38
+ product: string;
39
+ } | null;
40
+ /**
41
+ * Enrich a finding with NVD data
42
+ * Returns enrichment data to merge into finding
43
+ * Handles multiple CVEs in a single field
44
+ */
45
+ export declare function enrichWithNvd(cveString: string): Promise<NvdEnrichment | null>;
46
+ /**
47
+ * Query NVD API by keyword search
48
+ */
49
+ export declare function getCvesByKeyword(keyword: string, limit?: number): Promise<NvdCveData[]>;
50
+ /**
51
+ * Get CVEs for a specific technology and version
52
+ * Tries CPE first, falls back to keyword search
53
+ */
54
+ export declare function getCvesForTechnology(technology: string, version: string, limit?: number): Promise<NvdCveData[]>;
55
+ //# sourceMappingURL=nvd.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nvd.d.ts","sourceRoot":"","sources":["../../src/enrichers/nvd.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAUH,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAiBD;;GAEG;AACH,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CA8E7E;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,KAAK,GAAE,MAAW,GACjB,OAAO,CAAC,UAAU,EAAE,CAAC,CA+EvB;AA0BD;;GAEG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAG1F;AAWD;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAqBpF;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,MAAM,EACf,KAAK,GAAE,MAAW,GACjB,OAAO,CAAC,UAAU,EAAE,CAAC,CA4EvB;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,KAAK,GAAE,MAAW,GACjB,OAAO,CAAC,UAAU,EAAE,CAAC,CA0BvB"}
@@ -0,0 +1,326 @@
1
+ /**
2
+ * NVD API Enrichment
3
+ * Query NIST NVD for CVE details, CVSS scores, descriptions
4
+ *
5
+ * API Docs: https://nvd.nist.gov/developers/vulnerabilities
6
+ */
7
+ const NVD_API_BASE = 'https://services.nvd.nist.gov/rest/json/cves/2.0';
8
+ // Rate limit: 5 requests per 30 seconds without API key
9
+ // With API key: 50 requests per 30 seconds
10
+ const RATE_LIMIT_DELAY = 6500; // 6.5 seconds between requests (safe without key)
11
+ let lastRequestTime = 0;
12
+ /**
13
+ * Wait for rate limit
14
+ */
15
+ async function waitForRateLimit() {
16
+ const now = Date.now();
17
+ const timeSinceLastRequest = now - lastRequestTime;
18
+ if (timeSinceLastRequest < RATE_LIMIT_DELAY) {
19
+ const waitTime = RATE_LIMIT_DELAY - timeSinceLastRequest;
20
+ await new Promise(resolve => setTimeout(resolve, waitTime));
21
+ }
22
+ lastRequestTime = Date.now();
23
+ }
24
+ /**
25
+ * Query NVD API for a specific CVE
26
+ */
27
+ export async function getCveDetails(cveId) {
28
+ if (!cveId || !cveId.startsWith('CVE-')) {
29
+ return null;
30
+ }
31
+ await waitForRateLimit();
32
+ try {
33
+ const url = `${NVD_API_BASE}?cveId=${encodeURIComponent(cveId)}`;
34
+ const response = await fetch(url, {
35
+ headers: {
36
+ 'User-Agent': 'VoidSec-Scanner/0.1.0',
37
+ },
38
+ });
39
+ if (!response.ok) {
40
+ console.warn(`NVD API error for ${cveId}: ${response.status}`);
41
+ return null;
42
+ }
43
+ const data = await response.json();
44
+ if (!data.vulnerabilities || data.vulnerabilities.length === 0) {
45
+ return null;
46
+ }
47
+ const vuln = data.vulnerabilities[0].cve;
48
+ // Extract description (prefer English)
49
+ const descriptions = vuln.descriptions || [];
50
+ const engDesc = descriptions.find((d) => d.lang === 'en');
51
+ const description = engDesc?.value || descriptions[0]?.value || '';
52
+ // Extract CVSS (prefer v3.1, then v3.0, then v2)
53
+ const metrics = vuln.metrics || {};
54
+ let cvssScore;
55
+ let cvssVector;
56
+ if (metrics.cvssMetricV31?.[0]) {
57
+ cvssScore = metrics.cvssMetricV31[0].cvssData?.baseScore;
58
+ cvssVector = metrics.cvssMetricV31[0].cvssData?.vectorString;
59
+ }
60
+ else if (metrics.cvssMetricV30?.[0]) {
61
+ cvssScore = metrics.cvssMetricV30[0].cvssData?.baseScore;
62
+ cvssVector = metrics.cvssMetricV30[0].cvssData?.vectorString;
63
+ }
64
+ else if (metrics.cvssMetricV2?.[0]) {
65
+ cvssScore = metrics.cvssMetricV2[0].cvssData?.baseScore;
66
+ cvssVector = metrics.cvssMetricV2[0].cvssData?.vectorString;
67
+ }
68
+ // Extract CWE
69
+ const weaknesses = vuln.weaknesses || [];
70
+ let cweId;
71
+ for (const w of weaknesses) {
72
+ const desc = w.description?.find((d) => d.lang === 'en');
73
+ if (desc?.value && desc.value.startsWith('CWE-')) {
74
+ cweId = desc.value;
75
+ break;
76
+ }
77
+ }
78
+ // Extract references
79
+ const refs = vuln.references || [];
80
+ const references = refs.map((r) => r.url).slice(0, 5); // Limit to 5
81
+ return {
82
+ id: cveId,
83
+ description,
84
+ cvssScore,
85
+ cvssVector,
86
+ cweId,
87
+ references,
88
+ published: vuln.published,
89
+ lastModified: vuln.lastModified,
90
+ };
91
+ }
92
+ catch (error) {
93
+ console.warn(`Failed to fetch CVE ${cveId}: ${error}`);
94
+ return null;
95
+ }
96
+ }
97
+ /**
98
+ * Query NVD for CVEs affecting a specific software version (by CPE)
99
+ */
100
+ export async function getCvesByCpe(vendor, product, version, limit = 10) {
101
+ await waitForRateLimit();
102
+ // Build CPE 2.3 string
103
+ const cpe = `cpe:2.3:a:${vendor}:${product}:${version}:*:*:*:*:*:*:*`;
104
+ try {
105
+ const url = `${NVD_API_BASE}?cpeName=${encodeURIComponent(cpe)}&resultsPerPage=${limit}`;
106
+ const response = await fetch(url, {
107
+ headers: {
108
+ 'User-Agent': 'VoidSec-Scanner/0.1.0',
109
+ },
110
+ });
111
+ if (!response.ok) {
112
+ console.warn(`NVD API error for CPE ${cpe}: ${response.status}`);
113
+ return [];
114
+ }
115
+ const data = await response.json();
116
+ if (!data.vulnerabilities || data.vulnerabilities.length === 0) {
117
+ return [];
118
+ }
119
+ const results = [];
120
+ for (const item of data.vulnerabilities) {
121
+ const vuln = item.cve;
122
+ const descriptions = vuln.descriptions || [];
123
+ const engDesc = descriptions.find((d) => d.lang === 'en');
124
+ const description = engDesc?.value || descriptions[0]?.value || '';
125
+ const metrics = vuln.metrics || {};
126
+ let cvssScore;
127
+ let cvssVector;
128
+ if (metrics.cvssMetricV31?.[0]) {
129
+ cvssScore = metrics.cvssMetricV31[0].cvssData?.baseScore;
130
+ cvssVector = metrics.cvssMetricV31[0].cvssData?.vectorString;
131
+ }
132
+ else if (metrics.cvssMetricV30?.[0]) {
133
+ cvssScore = metrics.cvssMetricV30[0].cvssData?.baseScore;
134
+ cvssVector = metrics.cvssMetricV30[0].cvssData?.vectorString;
135
+ }
136
+ else if (metrics.cvssMetricV2?.[0]) {
137
+ cvssScore = metrics.cvssMetricV2[0].cvssData?.baseScore;
138
+ cvssVector = metrics.cvssMetricV2[0].cvssData?.vectorString;
139
+ }
140
+ const weaknesses = vuln.weaknesses || [];
141
+ let cweId;
142
+ for (const w of weaknesses) {
143
+ const desc = w.description?.find((d) => d.lang === 'en');
144
+ if (desc?.value && desc.value.startsWith('CWE-')) {
145
+ cweId = desc.value;
146
+ break;
147
+ }
148
+ }
149
+ const refs = vuln.references || [];
150
+ const references = refs.map((r) => r.url).slice(0, 3);
151
+ results.push({
152
+ id: vuln.id,
153
+ description,
154
+ cvssScore,
155
+ cvssVector,
156
+ cweId,
157
+ references,
158
+ published: vuln.published,
159
+ lastModified: vuln.lastModified,
160
+ });
161
+ }
162
+ return results;
163
+ }
164
+ catch (error) {
165
+ console.warn(`Failed to fetch CVEs for CPE ${cpe}: ${error}`);
166
+ return [];
167
+ }
168
+ }
169
+ // Common CPE vendor/product mappings for detected technologies
170
+ const CPE_MAPPINGS = {
171
+ 'nginx': { vendor: 'f5', product: 'nginx' },
172
+ 'apache': { vendor: 'apache', product: 'http_server' },
173
+ 'drupal': { vendor: 'drupal', product: 'drupal' },
174
+ 'wordpress': { vendor: 'wordpress', product: 'wordpress' },
175
+ 'php': { vendor: 'php', product: 'php' },
176
+ 'mysql': { vendor: 'oracle', product: 'mysql' },
177
+ 'postgresql': { vendor: 'postgresql', product: 'postgresql' },
178
+ 'nodejs': { vendor: 'nodejs', product: 'node.js' },
179
+ 'node.js': { vendor: 'nodejs', product: 'node.js' },
180
+ 'openssl': { vendor: 'openssl', product: 'openssl' },
181
+ 'jquery': { vendor: 'jquery', product: 'jquery' },
182
+ 'bootstrap': { vendor: 'getbootstrap', product: 'bootstrap' },
183
+ 'laravel': { vendor: 'laravel', product: 'laravel' },
184
+ 'nextjs': { vendor: 'vercel', product: 'next.js' },
185
+ 'next.js': { vendor: 'vercel', product: 'next.js' },
186
+ 'react': { vendor: 'facebook', product: 'react' },
187
+ 'vue': { vendor: 'vuejs', product: 'vue.js' },
188
+ 'angular': { vendor: 'google', product: 'angular' },
189
+ 'tomcat': { vendor: 'apache', product: 'tomcat' },
190
+ 'iis': { vendor: 'microsoft', product: 'internet_information_services' },
191
+ };
192
+ /**
193
+ * Get CPE mapping for a technology name
194
+ */
195
+ export function getCpeMapping(techName) {
196
+ const normalized = techName.toLowerCase().trim();
197
+ return CPE_MAPPINGS[normalized] || null;
198
+ }
199
+ /**
200
+ * Parse CVE string - may contain multiple CVEs separated by space
201
+ */
202
+ function parseCveIds(cveString) {
203
+ // Match all CVE-XXXX-XXXXX patterns
204
+ const matches = cveString.match(/CVE-\d{4}-\d+/g);
205
+ return matches || [];
206
+ }
207
+ /**
208
+ * Enrich a finding with NVD data
209
+ * Returns enrichment data to merge into finding
210
+ * Handles multiple CVEs in a single field
211
+ */
212
+ export async function enrichWithNvd(cveString) {
213
+ const cveIds = parseCveIds(cveString);
214
+ if (cveIds.length === 0) {
215
+ return null;
216
+ }
217
+ // For multiple CVEs, get data for the first one (usually the most relevant)
218
+ const cveData = await getCveDetails(cveIds[0]);
219
+ if (!cveData) {
220
+ return null;
221
+ }
222
+ return {
223
+ description: cveData.description,
224
+ cvssScore: cveData.cvssScore,
225
+ cvssVector: cveData.cvssVector,
226
+ cweId: cveData.cweId,
227
+ references: cveData.references,
228
+ };
229
+ }
230
+ /**
231
+ * Query NVD API by keyword search
232
+ */
233
+ export async function getCvesByKeyword(keyword, limit = 10) {
234
+ await waitForRateLimit();
235
+ try {
236
+ const url = `${NVD_API_BASE}?keywordSearch=${encodeURIComponent(keyword)}&resultsPerPage=${limit}`;
237
+ const response = await fetch(url, {
238
+ headers: {
239
+ 'User-Agent': 'VoidSec-Scanner/0.1.0',
240
+ },
241
+ });
242
+ if (!response.ok) {
243
+ console.warn(`NVD API error for keyword "${keyword}": ${response.status}`);
244
+ return [];
245
+ }
246
+ const data = await response.json();
247
+ if (!data.vulnerabilities || data.vulnerabilities.length === 0) {
248
+ return [];
249
+ }
250
+ const results = [];
251
+ for (const item of data.vulnerabilities) {
252
+ const vuln = item.cve;
253
+ const descriptions = vuln.descriptions || [];
254
+ const engDesc = descriptions.find((d) => d.lang === 'en');
255
+ const description = engDesc?.value || descriptions[0]?.value || '';
256
+ const metrics = vuln.metrics || {};
257
+ let cvssScore;
258
+ let cvssVector;
259
+ if (metrics.cvssMetricV31?.[0]) {
260
+ cvssScore = metrics.cvssMetricV31[0].cvssData?.baseScore;
261
+ cvssVector = metrics.cvssMetricV31[0].cvssData?.vectorString;
262
+ }
263
+ else if (metrics.cvssMetricV30?.[0]) {
264
+ cvssScore = metrics.cvssMetricV30[0].cvssData?.baseScore;
265
+ cvssVector = metrics.cvssMetricV30[0].cvssData?.vectorString;
266
+ }
267
+ else if (metrics.cvssMetricV2?.[0]) {
268
+ cvssScore = metrics.cvssMetricV2[0].cvssData?.baseScore;
269
+ cvssVector = metrics.cvssMetricV2[0].cvssData?.vectorString;
270
+ }
271
+ const weaknesses = vuln.weaknesses || [];
272
+ let cweId;
273
+ for (const w of weaknesses) {
274
+ const desc = w.description?.find((d) => d.lang === 'en');
275
+ if (desc?.value && desc.value.startsWith('CWE-')) {
276
+ cweId = desc.value;
277
+ break;
278
+ }
279
+ }
280
+ const refs = vuln.references || [];
281
+ const references = refs.map((r) => r.url).slice(0, 3);
282
+ results.push({
283
+ id: vuln.id,
284
+ description,
285
+ cvssScore,
286
+ cvssVector,
287
+ cweId,
288
+ references,
289
+ published: vuln.published,
290
+ lastModified: vuln.lastModified,
291
+ });
292
+ }
293
+ return results;
294
+ }
295
+ catch (error) {
296
+ console.warn(`Failed to fetch CVEs for keyword "${keyword}": ${error}`);
297
+ return [];
298
+ }
299
+ }
300
+ /**
301
+ * Get CVEs for a specific technology and version
302
+ * Tries CPE first, falls back to keyword search
303
+ */
304
+ export async function getCvesForTechnology(technology, version, limit = 10) {
305
+ const cpeMapping = getCpeMapping(technology);
306
+ console.log(` 🔍 Looking up CVEs for ${technology} ${version}...`);
307
+ let cves = [];
308
+ // Try CPE-based search first
309
+ if (cpeMapping) {
310
+ cves = await getCvesByCpe(cpeMapping.vendor, cpeMapping.product, version, limit);
311
+ }
312
+ // If CPE search found nothing, try keyword search
313
+ if (cves.length === 0) {
314
+ const keyword = `${technology} ${version}`;
315
+ console.log(` ⚠ No CPE results, trying keyword search: "${keyword}"...`);
316
+ cves = await getCvesByKeyword(keyword, limit);
317
+ }
318
+ if (cves.length > 0) {
319
+ console.log(` ✓ Found ${cves.length} CVEs for ${technology} ${version}`);
320
+ }
321
+ else {
322
+ console.log(` ⚠ No CVEs found for ${technology} ${version}`);
323
+ }
324
+ return cves;
325
+ }
326
+ //# sourceMappingURL=nvd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nvd.js","sourceRoot":"","sources":["../../src/enrichers/nvd.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Report Generator
3
+ * Generate HTML reports from scan results
4
+ * Uses Tailwind CSS + Alpine.js for styling and interactivity
5
+ */
6
+ import { Report } from './types.js';
7
+ export declare function generateHtmlReport(report: Report): string;
8
+ /**
9
+ * Generate JSON report from scan results
10
+ */
11
+ export declare function generateJsonReport(report: Report): string;
12
+ //# sourceMappingURL=report.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,MAAM,EAAqB,MAAM,YAAY,CAAC;AAocvD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAOzD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEzD"}