@nahisaho/musubix-security 1.8.0 → 1.8.5
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/README.md +27 -0
- package/dist/analyzers/ai/index.d.ts +6 -0
- package/dist/analyzers/ai/index.d.ts.map +1 -0
- package/dist/analyzers/ai/index.js +6 -0
- package/dist/analyzers/ai/index.js.map +1 -0
- package/dist/analyzers/ai/prompt-injection-detector.d.ts +152 -0
- package/dist/analyzers/ai/prompt-injection-detector.d.ts.map +1 -0
- package/dist/analyzers/ai/prompt-injection-detector.js +468 -0
- package/dist/analyzers/ai/prompt-injection-detector.js.map +1 -0
- package/dist/analyzers/api/api-security-analyzer.d.ts +263 -0
- package/dist/analyzers/api/api-security-analyzer.d.ts.map +1 -0
- package/dist/analyzers/api/api-security-analyzer.js +581 -0
- package/dist/analyzers/api/api-security-analyzer.js.map +1 -0
- package/dist/analyzers/compliance/compliance-checker.d.ts +201 -0
- package/dist/analyzers/compliance/compliance-checker.d.ts.map +1 -0
- package/dist/analyzers/compliance/compliance-checker.js +772 -0
- package/dist/analyzers/compliance/compliance-checker.js.map +1 -0
- package/dist/analyzers/container/image-scanner.d.ts +163 -0
- package/dist/analyzers/container/image-scanner.d.ts.map +1 -0
- package/dist/analyzers/container/image-scanner.js +459 -0
- package/dist/analyzers/container/image-scanner.js.map +1 -0
- package/dist/analyzers/container/index.d.ts +6 -0
- package/dist/analyzers/container/index.d.ts.map +1 -0
- package/dist/analyzers/container/index.js +6 -0
- package/dist/analyzers/container/index.js.map +1 -0
- package/dist/analyzers/dashboard/security-dashboard.d.ts +286 -0
- package/dist/analyzers/dashboard/security-dashboard.d.ts.map +1 -0
- package/dist/analyzers/dashboard/security-dashboard.js +796 -0
- package/dist/analyzers/dashboard/security-dashboard.js.map +1 -0
- package/dist/analyzers/iac/iac-checker.d.ts +124 -0
- package/dist/analyzers/iac/iac-checker.d.ts.map +1 -0
- package/dist/analyzers/iac/iac-checker.js +755 -0
- package/dist/analyzers/iac/iac-checker.js.map +1 -0
- package/dist/analyzers/iac/index.d.ts +6 -0
- package/dist/analyzers/iac/index.d.ts.map +1 -0
- package/dist/analyzers/iac/index.js +6 -0
- package/dist/analyzers/iac/index.js.map +1 -0
- package/dist/analyzers/index.d.ts +9 -0
- package/dist/analyzers/index.d.ts.map +1 -0
- package/dist/analyzers/index.js +13 -0
- package/dist/analyzers/index.js.map +1 -0
- package/dist/analyzers/monitor/realtime-monitor.d.ts +216 -0
- package/dist/analyzers/monitor/realtime-monitor.d.ts.map +1 -0
- package/dist/analyzers/monitor/realtime-monitor.js +601 -0
- package/dist/analyzers/monitor/realtime-monitor.js.map +1 -0
- package/dist/analyzers/sast/index.d.ts +7 -0
- package/dist/analyzers/sast/index.d.ts.map +1 -0
- package/dist/analyzers/sast/index.js +7 -0
- package/dist/analyzers/sast/index.js.map +1 -0
- package/dist/analyzers/sast/interprocedural-analyzer.d.ts +276 -0
- package/dist/analyzers/sast/interprocedural-analyzer.d.ts.map +1 -0
- package/dist/analyzers/sast/interprocedural-analyzer.js +635 -0
- package/dist/analyzers/sast/interprocedural-analyzer.js.map +1 -0
- package/dist/analyzers/sast/zero-day-detector.d.ts +183 -0
- package/dist/analyzers/sast/zero-day-detector.d.ts.map +1 -0
- package/dist/analyzers/sast/zero-day-detector.js +593 -0
- package/dist/analyzers/sast/zero-day-detector.js.map +1 -0
- package/dist/analyzers/sca/dependency-scanner.d.ts +275 -0
- package/dist/analyzers/sca/dependency-scanner.d.ts.map +1 -0
- package/dist/analyzers/sca/dependency-scanner.js +642 -0
- package/dist/analyzers/sca/dependency-scanner.js.map +1 -0
- package/dist/core/index.d.ts +8 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +10 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/pipeline-manager.d.ts +105 -0
- package/dist/core/pipeline-manager.d.ts.map +1 -0
- package/dist/core/pipeline-manager.js +449 -0
- package/dist/core/pipeline-manager.js.map +1 -0
- package/dist/core/result-aggregator.d.ts +96 -0
- package/dist/core/result-aggregator.d.ts.map +1 -0
- package/dist/core/result-aggregator.js +462 -0
- package/dist/core/result-aggregator.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +68 -0
- package/dist/index.js.map +1 -1
- package/dist/integrations/ci-integration.d.ts +227 -0
- package/dist/integrations/ci-integration.d.ts.map +1 -0
- package/dist/integrations/ci-integration.js +472 -0
- package/dist/integrations/ci-integration.js.map +1 -0
- package/dist/integrations/git-hooks.d.ts +155 -0
- package/dist/integrations/git-hooks.d.ts.map +1 -0
- package/dist/integrations/git-hooks.js +425 -0
- package/dist/integrations/git-hooks.js.map +1 -0
- package/dist/integrations/index.d.ts +9 -0
- package/dist/integrations/index.d.ts.map +1 -0
- package/dist/integrations/index.js +9 -0
- package/dist/integrations/index.js.map +1 -0
- package/dist/integrations/report-aggregator.d.ts +250 -0
- package/dist/integrations/report-aggregator.d.ts.map +1 -0
- package/dist/integrations/report-aggregator.js +488 -0
- package/dist/integrations/report-aggregator.js.map +1 -0
- package/dist/integrations/vscode-integration.d.ts +245 -0
- package/dist/integrations/vscode-integration.d.ts.map +1 -0
- package/dist/integrations/vscode-integration.js +449 -0
- package/dist/integrations/vscode-integration.js.map +1 -0
- package/dist/intelligence/attack-pattern-matcher.d.ts +217 -0
- package/dist/intelligence/attack-pattern-matcher.d.ts.map +1 -0
- package/dist/intelligence/attack-pattern-matcher.js +887 -0
- package/dist/intelligence/attack-pattern-matcher.js.map +1 -0
- package/dist/intelligence/index.d.ts +12 -0
- package/dist/intelligence/index.d.ts.map +1 -0
- package/dist/intelligence/index.js +18 -0
- package/dist/intelligence/index.js.map +1 -0
- package/dist/intelligence/neuro-symbolic-core.d.ts +88 -0
- package/dist/intelligence/neuro-symbolic-core.d.ts.map +1 -0
- package/dist/intelligence/neuro-symbolic-core.js +403 -0
- package/dist/intelligence/neuro-symbolic-core.js.map +1 -0
- package/dist/intelligence/predictive-analyzer.d.ts +317 -0
- package/dist/intelligence/predictive-analyzer.d.ts.map +1 -0
- package/dist/intelligence/predictive-analyzer.js +714 -0
- package/dist/intelligence/predictive-analyzer.js.map +1 -0
- package/dist/intelligence/risk-scorer.d.ts +333 -0
- package/dist/intelligence/risk-scorer.d.ts.map +1 -0
- package/dist/intelligence/risk-scorer.js +824 -0
- package/dist/intelligence/risk-scorer.js.map +1 -0
- package/dist/intelligence/security-analytics.d.ts +349 -0
- package/dist/intelligence/security-analytics.d.ts.map +1 -0
- package/dist/intelligence/security-analytics.js +813 -0
- package/dist/intelligence/security-analytics.js.map +1 -0
- package/dist/intelligence/threat-intelligence.d.ts +288 -0
- package/dist/intelligence/threat-intelligence.d.ts.map +1 -0
- package/dist/intelligence/threat-intelligence.js +639 -0
- package/dist/intelligence/threat-intelligence.js.map +1 -0
- package/dist/policy/index.d.ts +6 -0
- package/dist/policy/index.d.ts.map +1 -0
- package/dist/policy/index.js +6 -0
- package/dist/policy/index.js.map +1 -0
- package/dist/policy/policy-engine.d.ts +254 -0
- package/dist/policy/policy-engine.d.ts.map +1 -0
- package/dist/policy/policy-engine.js +651 -0
- package/dist/policy/policy-engine.js.map +1 -0
- package/dist/remediation/auto-fixer.d.ts +179 -0
- package/dist/remediation/auto-fixer.d.ts.map +1 -0
- package/dist/remediation/auto-fixer.js +540 -0
- package/dist/remediation/auto-fixer.js.map +1 -0
- package/dist/remediation/fix-validator.d.ts +195 -0
- package/dist/remediation/fix-validator.d.ts.map +1 -0
- package/dist/remediation/fix-validator.js +462 -0
- package/dist/remediation/fix-validator.js.map +1 -0
- package/dist/remediation/index.d.ts +10 -0
- package/dist/remediation/index.d.ts.map +1 -0
- package/dist/remediation/index.js +15 -0
- package/dist/remediation/index.js.map +1 -0
- package/dist/remediation/patch-generator.d.ts +203 -0
- package/dist/remediation/patch-generator.d.ts.map +1 -0
- package/dist/remediation/patch-generator.js +533 -0
- package/dist/remediation/patch-generator.js.map +1 -0
- package/dist/remediation/remediation-planner.d.ts +262 -0
- package/dist/remediation/remediation-planner.d.ts.map +1 -0
- package/dist/remediation/remediation-planner.js +531 -0
- package/dist/remediation/remediation-planner.js.map +1 -0
- package/dist/remediation/secure-code-transformer.d.ts +222 -0
- package/dist/remediation/secure-code-transformer.d.ts.map +1 -0
- package/dist/remediation/secure-code-transformer.js +625 -0
- package/dist/remediation/secure-code-transformer.js.map +1 -0
- package/dist/types/fix.d.ts +3 -1
- package/dist/types/fix.d.ts.map +1 -1
- package/dist/types/index.d.ts +6 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/interprocedural.d.ts +203 -0
- package/dist/types/interprocedural.d.ts.map +1 -0
- package/dist/types/interprocedural.js +7 -0
- package/dist/types/interprocedural.js.map +1 -0
- package/dist/types/neuro-symbolic.d.ts +179 -0
- package/dist/types/neuro-symbolic.d.ts.map +1 -0
- package/dist/types/neuro-symbolic.js +7 -0
- package/dist/types/neuro-symbolic.js.map +1 -0
- package/dist/types/pipeline.d.ts +173 -0
- package/dist/types/pipeline.d.ts.map +1 -0
- package/dist/types/pipeline.js +7 -0
- package/dist/types/pipeline.js.map +1 -0
- package/dist/types/result.d.ts +134 -0
- package/dist/types/result.d.ts.map +1 -0
- package/dist/types/result.js +25 -0
- package/dist/types/result.js.map +1 -0
- package/dist/types/vulnerability.d.ts +2 -2
- package/dist/types/vulnerability.d.ts.map +1 -1
- package/dist/types/zero-day.d.ts +146 -0
- package/dist/types/zero-day.d.ts.map +1 -0
- package/dist/types/zero-day.js +7 -0
- package/dist/types/zero-day.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,824 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Comprehensive Risk Scorer
|
|
3
|
+
* @module @nahisaho/musubix-security/intelligence/risk-scorer
|
|
4
|
+
*
|
|
5
|
+
* Provides comprehensive risk scoring, CVSS calculation,
|
|
6
|
+
* business impact assessment, and risk prioritization.
|
|
7
|
+
*/
|
|
8
|
+
// ============================================================================
|
|
9
|
+
// CVSS Constants
|
|
10
|
+
// ============================================================================
|
|
11
|
+
const CVSS_WEIGHTS = {
|
|
12
|
+
attackVector: { network: 0.85, adjacent: 0.62, local: 0.55, physical: 0.2 },
|
|
13
|
+
attackComplexity: { low: 0.77, high: 0.44 },
|
|
14
|
+
privilegesRequired: {
|
|
15
|
+
unchanged: { none: 0.85, low: 0.62, high: 0.27 },
|
|
16
|
+
changed: { none: 0.85, low: 0.68, high: 0.5 },
|
|
17
|
+
},
|
|
18
|
+
userInteraction: { none: 0.85, required: 0.62 },
|
|
19
|
+
impact: { none: 0, low: 0.22, high: 0.56 },
|
|
20
|
+
};
|
|
21
|
+
// Vulnerability type to CVSS metrics mapping
|
|
22
|
+
const VULN_TYPE_CVSS_MAP = {
|
|
23
|
+
'xss': {
|
|
24
|
+
attackVector: 'network',
|
|
25
|
+
attackComplexity: 'low',
|
|
26
|
+
privilegesRequired: 'none',
|
|
27
|
+
userInteraction: 'required',
|
|
28
|
+
scope: 'changed',
|
|
29
|
+
confidentialityImpact: 'low',
|
|
30
|
+
integrityImpact: 'low',
|
|
31
|
+
availabilityImpact: 'none',
|
|
32
|
+
},
|
|
33
|
+
'sql-injection': {
|
|
34
|
+
attackVector: 'network',
|
|
35
|
+
attackComplexity: 'low',
|
|
36
|
+
privilegesRequired: 'none',
|
|
37
|
+
userInteraction: 'none',
|
|
38
|
+
scope: 'unchanged',
|
|
39
|
+
confidentialityImpact: 'high',
|
|
40
|
+
integrityImpact: 'high',
|
|
41
|
+
availabilityImpact: 'high',
|
|
42
|
+
},
|
|
43
|
+
'command-injection': {
|
|
44
|
+
attackVector: 'network',
|
|
45
|
+
attackComplexity: 'low',
|
|
46
|
+
privilegesRequired: 'low',
|
|
47
|
+
userInteraction: 'none',
|
|
48
|
+
scope: 'changed',
|
|
49
|
+
confidentialityImpact: 'high',
|
|
50
|
+
integrityImpact: 'high',
|
|
51
|
+
availabilityImpact: 'high',
|
|
52
|
+
},
|
|
53
|
+
'path-traversal': {
|
|
54
|
+
attackVector: 'network',
|
|
55
|
+
attackComplexity: 'low',
|
|
56
|
+
privilegesRequired: 'none',
|
|
57
|
+
userInteraction: 'none',
|
|
58
|
+
scope: 'unchanged',
|
|
59
|
+
confidentialityImpact: 'high',
|
|
60
|
+
integrityImpact: 'low',
|
|
61
|
+
availabilityImpact: 'none',
|
|
62
|
+
},
|
|
63
|
+
'ssrf': {
|
|
64
|
+
attackVector: 'network',
|
|
65
|
+
attackComplexity: 'low',
|
|
66
|
+
privilegesRequired: 'none',
|
|
67
|
+
userInteraction: 'none',
|
|
68
|
+
scope: 'changed',
|
|
69
|
+
confidentialityImpact: 'low',
|
|
70
|
+
integrityImpact: 'low',
|
|
71
|
+
availabilityImpact: 'low',
|
|
72
|
+
},
|
|
73
|
+
'hardcoded-secret': {
|
|
74
|
+
attackVector: 'local',
|
|
75
|
+
attackComplexity: 'low',
|
|
76
|
+
privilegesRequired: 'none',
|
|
77
|
+
userInteraction: 'none',
|
|
78
|
+
scope: 'unchanged',
|
|
79
|
+
confidentialityImpact: 'high',
|
|
80
|
+
integrityImpact: 'high',
|
|
81
|
+
availabilityImpact: 'none',
|
|
82
|
+
},
|
|
83
|
+
'weak-crypto': {
|
|
84
|
+
attackVector: 'network',
|
|
85
|
+
attackComplexity: 'high',
|
|
86
|
+
privilegesRequired: 'none',
|
|
87
|
+
userInteraction: 'none',
|
|
88
|
+
scope: 'unchanged',
|
|
89
|
+
confidentialityImpact: 'high',
|
|
90
|
+
integrityImpact: 'none',
|
|
91
|
+
availabilityImpact: 'none',
|
|
92
|
+
},
|
|
93
|
+
'prototype-pollution': {
|
|
94
|
+
attackVector: 'network',
|
|
95
|
+
attackComplexity: 'low',
|
|
96
|
+
privilegesRequired: 'none',
|
|
97
|
+
userInteraction: 'none',
|
|
98
|
+
scope: 'unchanged',
|
|
99
|
+
confidentialityImpact: 'low',
|
|
100
|
+
integrityImpact: 'low',
|
|
101
|
+
availabilityImpact: 'low',
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
// Default business impact weights
|
|
105
|
+
const DEFAULT_BUSINESS_IMPACT_WEIGHTS = {
|
|
106
|
+
financial: 0.25,
|
|
107
|
+
reputation: 0.2,
|
|
108
|
+
operational: 0.2,
|
|
109
|
+
compliance: 0.15,
|
|
110
|
+
safety: 0.1,
|
|
111
|
+
privacy: 0.1,
|
|
112
|
+
};
|
|
113
|
+
// ============================================================================
|
|
114
|
+
// RiskScorer Class
|
|
115
|
+
// ============================================================================
|
|
116
|
+
/**
|
|
117
|
+
* Comprehensive Risk Scorer
|
|
118
|
+
*/
|
|
119
|
+
export class RiskScorer {
|
|
120
|
+
options;
|
|
121
|
+
constructor(options = {}) {
|
|
122
|
+
this.options = {
|
|
123
|
+
assetClassification: options.assetClassification ?? {
|
|
124
|
+
type: 'application',
|
|
125
|
+
criticality: 50,
|
|
126
|
+
dataClassification: 'internal',
|
|
127
|
+
complianceRequirements: [],
|
|
128
|
+
},
|
|
129
|
+
businessImpactWeights: {
|
|
130
|
+
...DEFAULT_BUSINESS_IMPACT_WEIGHTS,
|
|
131
|
+
...options.businessImpactWeights,
|
|
132
|
+
},
|
|
133
|
+
customFactors: options.customFactors ?? [],
|
|
134
|
+
enableThreatEnrichment: options.enableThreatEnrichment ?? true,
|
|
135
|
+
riskTolerance: options.riskTolerance ?? 50,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Calculate CVSS score for a vulnerability
|
|
140
|
+
*/
|
|
141
|
+
calculateCVSS(vulnerability) {
|
|
142
|
+
// Get base metrics from vulnerability type mapping
|
|
143
|
+
const baseMetrics = VULN_TYPE_CVSS_MAP[vulnerability.type] ?? {};
|
|
144
|
+
// Apply defaults
|
|
145
|
+
const metrics = {
|
|
146
|
+
attackVector: baseMetrics.attackVector ?? 'network',
|
|
147
|
+
attackComplexity: baseMetrics.attackComplexity ?? 'low',
|
|
148
|
+
privilegesRequired: baseMetrics.privilegesRequired ?? 'none',
|
|
149
|
+
userInteraction: baseMetrics.userInteraction ?? 'none',
|
|
150
|
+
scope: baseMetrics.scope ?? 'unchanged',
|
|
151
|
+
confidentialityImpact: baseMetrics.confidentialityImpact ?? 'low',
|
|
152
|
+
integrityImpact: baseMetrics.integrityImpact ?? 'low',
|
|
153
|
+
availabilityImpact: baseMetrics.availabilityImpact ?? 'low',
|
|
154
|
+
};
|
|
155
|
+
// Adjust based on vulnerability severity
|
|
156
|
+
if (vulnerability.severity === 'critical') {
|
|
157
|
+
metrics.confidentialityImpact = 'high';
|
|
158
|
+
metrics.integrityImpact = 'high';
|
|
159
|
+
metrics.availabilityImpact = 'high';
|
|
160
|
+
}
|
|
161
|
+
else if (vulnerability.severity === 'high') {
|
|
162
|
+
metrics.confidentialityImpact = 'high';
|
|
163
|
+
metrics.integrityImpact = 'high';
|
|
164
|
+
}
|
|
165
|
+
// Calculate exploitability score
|
|
166
|
+
const exploitability = this.calculateExploitability(metrics);
|
|
167
|
+
// Calculate impact score
|
|
168
|
+
const impact = this.calculateImpact(metrics);
|
|
169
|
+
// Calculate base score
|
|
170
|
+
let baseScore;
|
|
171
|
+
if (impact <= 0) {
|
|
172
|
+
baseScore = 0;
|
|
173
|
+
}
|
|
174
|
+
else if (metrics.scope === 'unchanged') {
|
|
175
|
+
baseScore = Math.min(10, 1.08 * (impact + exploitability));
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
baseScore = Math.min(10, 1.08 * (impact + exploitability));
|
|
179
|
+
}
|
|
180
|
+
// Round to one decimal
|
|
181
|
+
baseScore = Math.round(baseScore * 10) / 10;
|
|
182
|
+
// Determine severity
|
|
183
|
+
const severity = this.cvssToSeverity(baseScore);
|
|
184
|
+
// Generate vector string
|
|
185
|
+
const vectorString = this.generateVectorString(metrics);
|
|
186
|
+
return {
|
|
187
|
+
baseScore,
|
|
188
|
+
severity,
|
|
189
|
+
vectorString,
|
|
190
|
+
components: {
|
|
191
|
+
exploitability,
|
|
192
|
+
impact,
|
|
193
|
+
},
|
|
194
|
+
metrics,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Calculate exploitability component
|
|
199
|
+
*/
|
|
200
|
+
calculateExploitability(metrics) {
|
|
201
|
+
const av = CVSS_WEIGHTS.attackVector[metrics.attackVector];
|
|
202
|
+
const ac = CVSS_WEIGHTS.attackComplexity[metrics.attackComplexity];
|
|
203
|
+
const pr = CVSS_WEIGHTS.privilegesRequired[metrics.scope][metrics.privilegesRequired];
|
|
204
|
+
const ui = CVSS_WEIGHTS.userInteraction[metrics.userInteraction];
|
|
205
|
+
return 8.22 * av * ac * pr * ui;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Calculate impact component
|
|
209
|
+
*/
|
|
210
|
+
calculateImpact(metrics) {
|
|
211
|
+
const isc = this.calculateISC(metrics);
|
|
212
|
+
if (metrics.scope === 'unchanged') {
|
|
213
|
+
return 6.42 * isc;
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
return 7.52 * (isc - 0.029) - 3.25 * Math.pow(isc - 0.02, 15);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Calculate Impact Sub-Component
|
|
221
|
+
*/
|
|
222
|
+
calculateISC(metrics) {
|
|
223
|
+
const c = CVSS_WEIGHTS.impact[metrics.confidentialityImpact];
|
|
224
|
+
const i = CVSS_WEIGHTS.impact[metrics.integrityImpact];
|
|
225
|
+
const a = CVSS_WEIGHTS.impact[metrics.availabilityImpact];
|
|
226
|
+
return 1 - (1 - c) * (1 - i) * (1 - a);
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Convert CVSS score to severity rating
|
|
230
|
+
*/
|
|
231
|
+
cvssToSeverity(score) {
|
|
232
|
+
if (score === 0)
|
|
233
|
+
return 'none';
|
|
234
|
+
if (score < 4)
|
|
235
|
+
return 'low';
|
|
236
|
+
if (score < 7)
|
|
237
|
+
return 'medium';
|
|
238
|
+
if (score < 9)
|
|
239
|
+
return 'high';
|
|
240
|
+
return 'critical';
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Generate CVSS vector string
|
|
244
|
+
*/
|
|
245
|
+
generateVectorString(metrics) {
|
|
246
|
+
const avMap = { network: 'N', adjacent: 'A', local: 'L', physical: 'P' };
|
|
247
|
+
const acMap = { low: 'L', high: 'H' };
|
|
248
|
+
const prMap = { none: 'N', low: 'L', high: 'H' };
|
|
249
|
+
const uiMap = { none: 'N', required: 'R' };
|
|
250
|
+
const sMap = { unchanged: 'U', changed: 'C' };
|
|
251
|
+
const impactMap = { none: 'N', low: 'L', high: 'H' };
|
|
252
|
+
return `CVSS:3.1/AV:${avMap[metrics.attackVector]}/AC:${acMap[metrics.attackComplexity]}/PR:${prMap[metrics.privilegesRequired]}/UI:${uiMap[metrics.userInteraction]}/S:${sMap[metrics.scope]}/C:${impactMap[metrics.confidentialityImpact]}/I:${impactMap[metrics.integrityImpact]}/A:${impactMap[metrics.availabilityImpact]}`;
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Assess business impact
|
|
256
|
+
*/
|
|
257
|
+
assessBusinessImpact(vulnerability) {
|
|
258
|
+
const impacts = [];
|
|
259
|
+
const asset = this.options.assetClassification;
|
|
260
|
+
// Financial impact
|
|
261
|
+
const financialLevel = this.calculateFinancialImpact(vulnerability, asset);
|
|
262
|
+
impacts.push({
|
|
263
|
+
category: 'financial',
|
|
264
|
+
level: financialLevel,
|
|
265
|
+
description: this.getFinancialDescription(vulnerability, financialLevel),
|
|
266
|
+
potentialLoss: this.estimatePotentialLoss(vulnerability, financialLevel),
|
|
267
|
+
});
|
|
268
|
+
// Reputation impact
|
|
269
|
+
const reputationLevel = this.calculateReputationImpact(vulnerability, asset);
|
|
270
|
+
impacts.push({
|
|
271
|
+
category: 'reputation',
|
|
272
|
+
level: reputationLevel,
|
|
273
|
+
description: this.getReputationDescription(vulnerability, reputationLevel),
|
|
274
|
+
});
|
|
275
|
+
// Operational impact
|
|
276
|
+
const operationalLevel = this.calculateOperationalImpact(vulnerability, asset);
|
|
277
|
+
impacts.push({
|
|
278
|
+
category: 'operational',
|
|
279
|
+
level: operationalLevel,
|
|
280
|
+
description: this.getOperationalDescription(vulnerability, operationalLevel),
|
|
281
|
+
});
|
|
282
|
+
// Compliance impact
|
|
283
|
+
if (asset.complianceRequirements.length > 0) {
|
|
284
|
+
const complianceLevel = this.calculateComplianceImpact(vulnerability, asset);
|
|
285
|
+
impacts.push({
|
|
286
|
+
category: 'compliance',
|
|
287
|
+
level: complianceLevel,
|
|
288
|
+
description: this.getComplianceDescription(vulnerability, complianceLevel, asset),
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
// Privacy impact
|
|
292
|
+
if (vulnerability.type.includes('injection') || vulnerability.type === 'path-traversal') {
|
|
293
|
+
const privacyLevel = this.calculatePrivacyImpact(vulnerability, asset);
|
|
294
|
+
impacts.push({
|
|
295
|
+
category: 'privacy',
|
|
296
|
+
level: privacyLevel,
|
|
297
|
+
description: this.getPrivacyDescription(vulnerability, privacyLevel),
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
return impacts;
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Calculate financial impact level
|
|
304
|
+
*/
|
|
305
|
+
calculateFinancialImpact(vulnerability, asset) {
|
|
306
|
+
let base = 30;
|
|
307
|
+
// Adjust based on severity
|
|
308
|
+
const severityMultiplier = {
|
|
309
|
+
critical: 2.5,
|
|
310
|
+
high: 2.0,
|
|
311
|
+
medium: 1.5,
|
|
312
|
+
low: 1.0,
|
|
313
|
+
info: 0.5,
|
|
314
|
+
}[vulnerability.severity];
|
|
315
|
+
base *= severityMultiplier;
|
|
316
|
+
// Adjust based on asset criticality
|
|
317
|
+
base *= (asset.criticality / 50);
|
|
318
|
+
// Adjust based on data classification
|
|
319
|
+
const classificationMultiplier = {
|
|
320
|
+
public: 0.5,
|
|
321
|
+
internal: 1.0,
|
|
322
|
+
confidential: 1.5,
|
|
323
|
+
restricted: 2.0,
|
|
324
|
+
}[asset.dataClassification];
|
|
325
|
+
base *= classificationMultiplier;
|
|
326
|
+
return Math.min(100, Math.round(base));
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Get financial impact description
|
|
330
|
+
*/
|
|
331
|
+
getFinancialDescription(vulnerability, level) {
|
|
332
|
+
if (level >= 80) {
|
|
333
|
+
return `Critical financial exposure. ${vulnerability.type} could lead to significant monetary losses.`;
|
|
334
|
+
}
|
|
335
|
+
else if (level >= 60) {
|
|
336
|
+
return `High financial risk. Exploitation could result in substantial costs.`;
|
|
337
|
+
}
|
|
338
|
+
else if (level >= 40) {
|
|
339
|
+
return `Moderate financial impact expected if exploited.`;
|
|
340
|
+
}
|
|
341
|
+
else {
|
|
342
|
+
return `Limited direct financial impact expected.`;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Estimate potential loss
|
|
347
|
+
*/
|
|
348
|
+
estimatePotentialLoss(_vulnerability, level) {
|
|
349
|
+
// Base estimates (simplified)
|
|
350
|
+
const baseMin = level * 100;
|
|
351
|
+
const baseMax = level * 1000;
|
|
352
|
+
return {
|
|
353
|
+
min: baseMin,
|
|
354
|
+
max: baseMax,
|
|
355
|
+
currency: 'USD',
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Calculate reputation impact
|
|
360
|
+
*/
|
|
361
|
+
calculateReputationImpact(vulnerability, asset) {
|
|
362
|
+
let base = 25;
|
|
363
|
+
// High visibility vulnerabilities
|
|
364
|
+
if (['xss', 'sql-injection', 'hardcoded-secret'].includes(vulnerability.type)) {
|
|
365
|
+
base += 25;
|
|
366
|
+
}
|
|
367
|
+
// Data breach potential
|
|
368
|
+
if (asset.dataClassification === 'confidential' || asset.dataClassification === 'restricted') {
|
|
369
|
+
base += 20;
|
|
370
|
+
}
|
|
371
|
+
// Severity adjustment
|
|
372
|
+
if (vulnerability.severity === 'critical') {
|
|
373
|
+
base *= 1.5;
|
|
374
|
+
}
|
|
375
|
+
return Math.min(100, Math.round(base));
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Get reputation impact description
|
|
379
|
+
*/
|
|
380
|
+
getReputationDescription(_vulnerability, level) {
|
|
381
|
+
if (level >= 70) {
|
|
382
|
+
return 'Severe reputation damage likely if publicly disclosed or exploited.';
|
|
383
|
+
}
|
|
384
|
+
else if (level >= 50) {
|
|
385
|
+
return 'Moderate reputation risk. Public disclosure would be damaging.';
|
|
386
|
+
}
|
|
387
|
+
else {
|
|
388
|
+
return 'Limited reputation impact expected.';
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Calculate operational impact
|
|
393
|
+
*/
|
|
394
|
+
calculateOperationalImpact(vulnerability, asset) {
|
|
395
|
+
let base = 20;
|
|
396
|
+
// Availability impacts
|
|
397
|
+
if (['command-injection', 'sql-injection'].includes(vulnerability.type)) {
|
|
398
|
+
base += 30;
|
|
399
|
+
}
|
|
400
|
+
// System criticality
|
|
401
|
+
base *= (asset.criticality / 50);
|
|
402
|
+
return Math.min(100, Math.round(base));
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* Get operational impact description
|
|
406
|
+
*/
|
|
407
|
+
getOperationalDescription(_vulnerability, level) {
|
|
408
|
+
if (level >= 70) {
|
|
409
|
+
return 'High operational disruption likely. Could cause system outages.';
|
|
410
|
+
}
|
|
411
|
+
else if (level >= 40) {
|
|
412
|
+
return 'Moderate operational impact. May affect system availability.';
|
|
413
|
+
}
|
|
414
|
+
else {
|
|
415
|
+
return 'Limited operational impact expected.';
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Calculate compliance impact
|
|
420
|
+
*/
|
|
421
|
+
calculateComplianceImpact(vulnerability, asset) {
|
|
422
|
+
let base = 30;
|
|
423
|
+
// Compliance requirements
|
|
424
|
+
const highRiskCompliance = ['PCI-DSS', 'HIPAA', 'GDPR', 'SOX'];
|
|
425
|
+
const hasHighRisk = asset.complianceRequirements.some(req => highRiskCompliance.includes(req));
|
|
426
|
+
if (hasHighRisk) {
|
|
427
|
+
base += 40;
|
|
428
|
+
}
|
|
429
|
+
// Data vulnerabilities have higher compliance impact
|
|
430
|
+
if (['sql-injection', 'path-traversal', 'hardcoded-secret'].includes(vulnerability.type)) {
|
|
431
|
+
base += 20;
|
|
432
|
+
}
|
|
433
|
+
return Math.min(100, Math.round(base));
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* Get compliance impact description
|
|
437
|
+
*/
|
|
438
|
+
getComplianceDescription(_vulnerability, level, asset) {
|
|
439
|
+
const reqs = asset.complianceRequirements.join(', ');
|
|
440
|
+
if (level >= 70) {
|
|
441
|
+
return `Critical compliance violation risk for ${reqs}.`;
|
|
442
|
+
}
|
|
443
|
+
else if (level >= 40) {
|
|
444
|
+
return `May affect compliance with ${reqs}.`;
|
|
445
|
+
}
|
|
446
|
+
else {
|
|
447
|
+
return 'Limited compliance impact.';
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Calculate privacy impact
|
|
452
|
+
*/
|
|
453
|
+
calculatePrivacyImpact(vulnerability, asset) {
|
|
454
|
+
let base = 30;
|
|
455
|
+
if (asset.dataClassification === 'restricted') {
|
|
456
|
+
base += 40;
|
|
457
|
+
}
|
|
458
|
+
else if (asset.dataClassification === 'confidential') {
|
|
459
|
+
base += 25;
|
|
460
|
+
}
|
|
461
|
+
if (vulnerability.severity === 'critical' || vulnerability.severity === 'high') {
|
|
462
|
+
base += 20;
|
|
463
|
+
}
|
|
464
|
+
return Math.min(100, Math.round(base));
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Get privacy impact description
|
|
468
|
+
*/
|
|
469
|
+
getPrivacyDescription(_vulnerability, level) {
|
|
470
|
+
if (level >= 70) {
|
|
471
|
+
return 'High risk of personal data exposure. May trigger breach notification requirements.';
|
|
472
|
+
}
|
|
473
|
+
else if (level >= 40) {
|
|
474
|
+
return 'Moderate privacy risk. Could expose user data.';
|
|
475
|
+
}
|
|
476
|
+
else {
|
|
477
|
+
return 'Limited privacy impact expected.';
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Calculate comprehensive risk score for a vulnerability
|
|
482
|
+
*/
|
|
483
|
+
scoreVulnerability(vulnerability, threatContext) {
|
|
484
|
+
// Calculate CVSS
|
|
485
|
+
const cvssScore = this.calculateCVSS(vulnerability);
|
|
486
|
+
// Assess business impact
|
|
487
|
+
const businessImpacts = this.assessBusinessImpact(vulnerability);
|
|
488
|
+
// Calculate risk factors
|
|
489
|
+
const factors = this.calculateRiskFactors(vulnerability, cvssScore, businessImpacts, threatContext);
|
|
490
|
+
// Calculate overall score
|
|
491
|
+
let overallScore = 0;
|
|
492
|
+
for (const factor of factors) {
|
|
493
|
+
overallScore += factor.score * factor.weight;
|
|
494
|
+
}
|
|
495
|
+
// Apply threat context multiplier
|
|
496
|
+
if (threatContext?.riskMultiplier) {
|
|
497
|
+
overallScore *= threatContext.riskMultiplier;
|
|
498
|
+
}
|
|
499
|
+
// Cap at 100
|
|
500
|
+
overallScore = Math.min(100, Math.round(overallScore));
|
|
501
|
+
// Determine risk level
|
|
502
|
+
const riskLevel = this.scoreToRiskLevel(overallScore);
|
|
503
|
+
// Calculate confidence
|
|
504
|
+
const confidence = this.calculateConfidence(vulnerability, factors);
|
|
505
|
+
// Generate recommendations
|
|
506
|
+
const recommendations = this.generateRecommendations(vulnerability, cvssScore, businessImpacts, threatContext);
|
|
507
|
+
// Estimate remediation time
|
|
508
|
+
const remediationTimeEstimate = this.estimateRemediationTime(vulnerability);
|
|
509
|
+
return {
|
|
510
|
+
overallScore,
|
|
511
|
+
riskLevel,
|
|
512
|
+
cvssScore,
|
|
513
|
+
businessImpacts,
|
|
514
|
+
factors,
|
|
515
|
+
assetContext: this.options.assetClassification,
|
|
516
|
+
threatContext,
|
|
517
|
+
confidence,
|
|
518
|
+
recommendations,
|
|
519
|
+
remediationTimeEstimate,
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* Calculate risk factors
|
|
524
|
+
*/
|
|
525
|
+
calculateRiskFactors(vulnerability, cvssScore, businessImpacts, threatContext) {
|
|
526
|
+
const factors = [];
|
|
527
|
+
// Technical severity factor
|
|
528
|
+
factors.push({
|
|
529
|
+
name: 'Technical Severity',
|
|
530
|
+
weight: 0.3,
|
|
531
|
+
score: cvssScore.baseScore * 10,
|
|
532
|
+
description: `CVSS ${cvssScore.baseScore} (${cvssScore.severity})`,
|
|
533
|
+
evidence: [cvssScore.vectorString],
|
|
534
|
+
});
|
|
535
|
+
// Business impact factor
|
|
536
|
+
const avgBusinessImpact = businessImpacts.reduce((sum, bi) => sum + bi.level, 0) / businessImpacts.length;
|
|
537
|
+
factors.push({
|
|
538
|
+
name: 'Business Impact',
|
|
539
|
+
weight: 0.25,
|
|
540
|
+
score: avgBusinessImpact,
|
|
541
|
+
description: 'Aggregated business impact assessment',
|
|
542
|
+
evidence: businessImpacts.map(bi => `${bi.category}: ${bi.level}`),
|
|
543
|
+
});
|
|
544
|
+
// Exploitability factor
|
|
545
|
+
const exploitability = this.assessExploitability(vulnerability);
|
|
546
|
+
factors.push({
|
|
547
|
+
name: 'Exploitability',
|
|
548
|
+
weight: 0.2,
|
|
549
|
+
score: exploitability,
|
|
550
|
+
description: 'Likelihood and ease of exploitation',
|
|
551
|
+
});
|
|
552
|
+
// Threat landscape factor
|
|
553
|
+
if (threatContext) {
|
|
554
|
+
factors.push({
|
|
555
|
+
name: 'Threat Landscape',
|
|
556
|
+
weight: 0.15,
|
|
557
|
+
score: threatContext.activelyExploited ? 100 : 50,
|
|
558
|
+
description: threatContext.activelyExploited
|
|
559
|
+
? 'Actively exploited in the wild'
|
|
560
|
+
: 'No active exploitation known',
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
else {
|
|
564
|
+
factors.push({
|
|
565
|
+
name: 'Threat Landscape',
|
|
566
|
+
weight: 0.15,
|
|
567
|
+
score: 30,
|
|
568
|
+
description: 'Threat intelligence not available',
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
// Asset criticality factor
|
|
572
|
+
factors.push({
|
|
573
|
+
name: 'Asset Criticality',
|
|
574
|
+
weight: 0.1,
|
|
575
|
+
score: this.options.assetClassification.criticality,
|
|
576
|
+
description: `Asset type: ${this.options.assetClassification.type}`,
|
|
577
|
+
});
|
|
578
|
+
// Add custom factors
|
|
579
|
+
for (const custom of this.options.customFactors) {
|
|
580
|
+
factors.push(custom);
|
|
581
|
+
}
|
|
582
|
+
return factors;
|
|
583
|
+
}
|
|
584
|
+
/**
|
|
585
|
+
* Assess exploitability
|
|
586
|
+
*/
|
|
587
|
+
assessExploitability(vulnerability) {
|
|
588
|
+
let score = 50;
|
|
589
|
+
// Known vulnerability types are more exploitable
|
|
590
|
+
const highExploitabilityTypes = ['sql-injection', 'command-injection', 'xss'];
|
|
591
|
+
if (highExploitabilityTypes.includes(vulnerability.type)) {
|
|
592
|
+
score += 30;
|
|
593
|
+
}
|
|
594
|
+
// Severity indicates exploitability
|
|
595
|
+
if (vulnerability.severity === 'critical') {
|
|
596
|
+
score += 20;
|
|
597
|
+
}
|
|
598
|
+
else if (vulnerability.severity === 'high') {
|
|
599
|
+
score += 10;
|
|
600
|
+
}
|
|
601
|
+
// Public exploit availability would increase this
|
|
602
|
+
// (In real implementation, check exploit databases)
|
|
603
|
+
return Math.min(100, score);
|
|
604
|
+
}
|
|
605
|
+
/**
|
|
606
|
+
* Convert score to risk level
|
|
607
|
+
*/
|
|
608
|
+
scoreToRiskLevel(score) {
|
|
609
|
+
if (score >= 90)
|
|
610
|
+
return 'critical';
|
|
611
|
+
if (score >= 70)
|
|
612
|
+
return 'high';
|
|
613
|
+
if (score >= 40)
|
|
614
|
+
return 'medium';
|
|
615
|
+
if (score >= 20)
|
|
616
|
+
return 'low';
|
|
617
|
+
return 'informational';
|
|
618
|
+
}
|
|
619
|
+
/**
|
|
620
|
+
* Calculate confidence
|
|
621
|
+
*/
|
|
622
|
+
calculateConfidence(vulnerability, factors) {
|
|
623
|
+
let confidence = 0.7; // Base confidence
|
|
624
|
+
// More factors increase confidence
|
|
625
|
+
if (factors.length >= 5) {
|
|
626
|
+
confidence += 0.1;
|
|
627
|
+
}
|
|
628
|
+
// Known vulnerability types have higher confidence
|
|
629
|
+
if (VULN_TYPE_CVSS_MAP[vulnerability.type]) {
|
|
630
|
+
confidence += 0.1;
|
|
631
|
+
}
|
|
632
|
+
// Reduce for info level
|
|
633
|
+
if (vulnerability.severity === 'info') {
|
|
634
|
+
confidence -= 0.1;
|
|
635
|
+
}
|
|
636
|
+
return Math.min(1, Math.max(0, confidence));
|
|
637
|
+
}
|
|
638
|
+
/**
|
|
639
|
+
* Generate prioritized recommendations
|
|
640
|
+
*/
|
|
641
|
+
generateRecommendations(vulnerability, cvssScore, businessImpacts, threatContext) {
|
|
642
|
+
const recommendations = [];
|
|
643
|
+
// Urgency-based recommendations
|
|
644
|
+
if (threatContext?.activelyExploited) {
|
|
645
|
+
recommendations.push('URGENT: Apply patches immediately - active exploitation detected');
|
|
646
|
+
}
|
|
647
|
+
if (cvssScore.baseScore >= 9) {
|
|
648
|
+
recommendations.push('Critical vulnerability - prioritize remediation within 24 hours');
|
|
649
|
+
}
|
|
650
|
+
else if (cvssScore.baseScore >= 7) {
|
|
651
|
+
recommendations.push('High severity - remediate within 1 week');
|
|
652
|
+
}
|
|
653
|
+
// Type-specific recommendations
|
|
654
|
+
switch (vulnerability.type) {
|
|
655
|
+
case 'injection':
|
|
656
|
+
recommendations.push('Use parameterized queries or prepared statements');
|
|
657
|
+
recommendations.push('Implement input validation');
|
|
658
|
+
break;
|
|
659
|
+
case 'xss':
|
|
660
|
+
recommendations.push('Implement output encoding');
|
|
661
|
+
recommendations.push('Use Content Security Policy headers');
|
|
662
|
+
break;
|
|
663
|
+
case 'command-injection':
|
|
664
|
+
recommendations.push('Avoid shell commands with user input');
|
|
665
|
+
recommendations.push('Use safe APIs instead of exec/spawn');
|
|
666
|
+
break;
|
|
667
|
+
case 'sensitive-exposure':
|
|
668
|
+
recommendations.push('Move credentials to secure secrets management');
|
|
669
|
+
recommendations.push('Rotate exposed credentials');
|
|
670
|
+
break;
|
|
671
|
+
case 'path-traversal':
|
|
672
|
+
recommendations.push('Validate and sanitize file paths');
|
|
673
|
+
recommendations.push('Use allowlists for accessible directories');
|
|
674
|
+
break;
|
|
675
|
+
}
|
|
676
|
+
// Business impact recommendations
|
|
677
|
+
const highImpacts = businessImpacts.filter(bi => bi.level >= 70);
|
|
678
|
+
for (const impact of highImpacts) {
|
|
679
|
+
recommendations.push(`Address ${impact.category} risk: ${impact.description}`);
|
|
680
|
+
}
|
|
681
|
+
return recommendations;
|
|
682
|
+
}
|
|
683
|
+
/**
|
|
684
|
+
* Estimate remediation time
|
|
685
|
+
*/
|
|
686
|
+
estimateRemediationTime(vulnerability) {
|
|
687
|
+
// Base estimates by type
|
|
688
|
+
const estimates = {
|
|
689
|
+
'sensitive-exposure': { min: 1, max: 4, unit: 'hours' },
|
|
690
|
+
'xss': { min: 2, max: 8, unit: 'hours' },
|
|
691
|
+
'injection': { min: 4, max: 16, unit: 'hours' },
|
|
692
|
+
'command-injection': { min: 4, max: 24, unit: 'hours' },
|
|
693
|
+
'path-traversal': { min: 2, max: 8, unit: 'hours' },
|
|
694
|
+
'ssrf': { min: 4, max: 16, unit: 'hours' },
|
|
695
|
+
'broken-auth': { min: 1, max: 3, unit: 'days' },
|
|
696
|
+
'prototype-pollution': { min: 2, max: 8, unit: 'hours' },
|
|
697
|
+
};
|
|
698
|
+
return estimates[vulnerability.type] ?? { min: 4, max: 24, unit: 'hours' };
|
|
699
|
+
}
|
|
700
|
+
/**
|
|
701
|
+
* Score multiple vulnerabilities and create summary
|
|
702
|
+
*/
|
|
703
|
+
scoreBatch(vulnerabilities) {
|
|
704
|
+
const scores = vulnerabilities.map(v => ({
|
|
705
|
+
vulnerability: v,
|
|
706
|
+
riskScore: this.scoreVulnerability(v),
|
|
707
|
+
}));
|
|
708
|
+
// Calculate distribution
|
|
709
|
+
const distribution = {
|
|
710
|
+
critical: 0,
|
|
711
|
+
high: 0,
|
|
712
|
+
medium: 0,
|
|
713
|
+
low: 0,
|
|
714
|
+
informational: 0,
|
|
715
|
+
};
|
|
716
|
+
let totalScore = 0;
|
|
717
|
+
for (const { riskScore } of scores) {
|
|
718
|
+
distribution[riskScore.riskLevel]++;
|
|
719
|
+
totalScore += riskScore.overallScore;
|
|
720
|
+
}
|
|
721
|
+
// Calculate average
|
|
722
|
+
const averageRiskScore = scores.length > 0
|
|
723
|
+
? Math.round(totalScore / scores.length)
|
|
724
|
+
: 0;
|
|
725
|
+
// Get top risks
|
|
726
|
+
const topRisks = scores
|
|
727
|
+
.sort((a, b) => b.riskScore.overallScore - a.riskScore.overallScore)
|
|
728
|
+
.slice(0, 5);
|
|
729
|
+
// Aggregate business impact
|
|
730
|
+
const impactTotals = new Map();
|
|
731
|
+
for (const { riskScore } of scores) {
|
|
732
|
+
for (const impact of riskScore.businessImpacts) {
|
|
733
|
+
const current = impactTotals.get(impact.category) || 0;
|
|
734
|
+
impactTotals.set(impact.category, current + impact.level);
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
const totalBusinessImpact = Array.from(impactTotals.entries()).map(([category, totalScore]) => ({ category, totalScore }));
|
|
738
|
+
// Calculate security posture (inverse of risk)
|
|
739
|
+
const securityPosture = Math.max(0, 100 - averageRiskScore);
|
|
740
|
+
return {
|
|
741
|
+
totalVulnerabilities: vulnerabilities.length,
|
|
742
|
+
averageRiskScore,
|
|
743
|
+
distribution,
|
|
744
|
+
topRisks,
|
|
745
|
+
totalBusinessImpact,
|
|
746
|
+
securityPosture,
|
|
747
|
+
trend: 'stable', // Would be calculated from historical data
|
|
748
|
+
};
|
|
749
|
+
}
|
|
750
|
+
/**
|
|
751
|
+
* Score attack chain
|
|
752
|
+
*/
|
|
753
|
+
scoreAttackChain(chain) {
|
|
754
|
+
// Create a synthetic vulnerability for the chain
|
|
755
|
+
const syntheticVuln = {
|
|
756
|
+
id: chain.id,
|
|
757
|
+
type: 'code-injection', // Use a valid type for attack chains
|
|
758
|
+
severity: chain.riskScore >= 80 ? 'critical' : chain.riskScore >= 60 ? 'high' : 'medium',
|
|
759
|
+
description: chain.name,
|
|
760
|
+
recommendation: chain.mitigations.join('; '),
|
|
761
|
+
location: chain.patterns[0]?.location ?? {
|
|
762
|
+
file: 'unknown',
|
|
763
|
+
startLine: 0,
|
|
764
|
+
endLine: 0,
|
|
765
|
+
startColumn: 0,
|
|
766
|
+
endColumn: 0,
|
|
767
|
+
},
|
|
768
|
+
cwes: [],
|
|
769
|
+
confidence: 0.9,
|
|
770
|
+
ruleId: 'attack-chain',
|
|
771
|
+
detectedAt: new Date(),
|
|
772
|
+
};
|
|
773
|
+
const baseScore = this.scoreVulnerability(syntheticVuln);
|
|
774
|
+
// Adjust for chain complexity
|
|
775
|
+
const chainMultiplier = 1 + (chain.killChainStages.length * 0.1);
|
|
776
|
+
baseScore.overallScore = Math.min(100, Math.round(baseScore.overallScore * chainMultiplier));
|
|
777
|
+
// Add chain-specific recommendations
|
|
778
|
+
baseScore.recommendations.unshift(`Attack chain detected covering ${chain.killChainStages.length} kill chain stages`);
|
|
779
|
+
return baseScore;
|
|
780
|
+
}
|
|
781
|
+
/**
|
|
782
|
+
* Score pattern match
|
|
783
|
+
*/
|
|
784
|
+
scorePatternMatch(match) {
|
|
785
|
+
const severityScore = {
|
|
786
|
+
critical: 90,
|
|
787
|
+
high: 70,
|
|
788
|
+
medium: 50,
|
|
789
|
+
low: 25,
|
|
790
|
+
}[match.pattern.severity];
|
|
791
|
+
return Math.round(severityScore * match.confidence);
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
// ============================================================================
|
|
795
|
+
// Factory Functions
|
|
796
|
+
// ============================================================================
|
|
797
|
+
/**
|
|
798
|
+
* Create a RiskScorer instance
|
|
799
|
+
*/
|
|
800
|
+
export function createRiskScorer(options) {
|
|
801
|
+
return new RiskScorer(options);
|
|
802
|
+
}
|
|
803
|
+
/**
|
|
804
|
+
* Quick CVSS calculation
|
|
805
|
+
*/
|
|
806
|
+
export function calculateCVSS(vulnerability) {
|
|
807
|
+
const scorer = createRiskScorer();
|
|
808
|
+
return scorer.calculateCVSS(vulnerability);
|
|
809
|
+
}
|
|
810
|
+
/**
|
|
811
|
+
* Quick risk score
|
|
812
|
+
*/
|
|
813
|
+
export function quickRiskScore(vulnerability) {
|
|
814
|
+
const scorer = createRiskScorer();
|
|
815
|
+
return scorer.scoreVulnerability(vulnerability);
|
|
816
|
+
}
|
|
817
|
+
/**
|
|
818
|
+
* Score multiple vulnerabilities
|
|
819
|
+
*/
|
|
820
|
+
export function scoreVulnerabilities(vulnerabilities) {
|
|
821
|
+
const scorer = createRiskScorer();
|
|
822
|
+
return scorer.scoreBatch(vulnerabilities);
|
|
823
|
+
}
|
|
824
|
+
//# sourceMappingURL=risk-scorer.js.map
|