UNPKG

@neuralegion/cvss

Version:

The Common Vulnerability Scoring System ([CVSS](https://www.first.org/cvss/)) [score](https://www.first.org/cvss/specification-document#1-2-Scoring) calculator and validator library written in [TypeScript](https://www.typescriptlang.org/).

169 lines (168 loc) 6.59 kB
import { BaseMetric, EnvironmentalMetric, TemporalMetric, environmentalMetrics, temporalMetrics } from './models'; import { parseMetricsAsMap } from '../../parser'; const baseMetricValueScores = { [BaseMetric.ACCESS_VECTOR]: { L: 0.395, A: 0.646, N: 1.0 }, [BaseMetric.ACCESS_COMPLEXITY]: { H: 0.35, M: 0.61, L: 0.71 }, [BaseMetric.AUTHENTICATION]: { M: 0.45, S: 0.56, N: 0.704 }, [BaseMetric.CONFIDENTIALITY_IMPACT]: { N: 0, P: 0.275, C: 0.66 }, [BaseMetric.INTEGRITY_IMPACT]: { N: 0, P: 0.275, C: 0.66 }, [BaseMetric.AVAILABILITY_IMPACT]: { N: 0, P: 0.275, C: 0.66 } }; const temporalMetricValueScores = { [TemporalMetric.EXPLOITABILITY]: { ND: 1.0, U: 0.85, POC: 0.9, F: 0.95, H: 1.0 }, [TemporalMetric.REMEDIATION_LEVEL]: { ND: 1.0, OF: 0.87, TF: 0.9, W: 0.95, U: 1.0 }, [TemporalMetric.REPORT_CONFIDENCE]: { ND: 1.0, UC: 0.9, UR: 0.95, C: 1.0 } }; const environmentalMetricValueScores = { [EnvironmentalMetric.COLLATERAL_DAMAGE_POTENTIAL]: { ND: 0, N: 0, L: 0.1, LM: 0.3, MH: 0.4, H: 0.5 }, [EnvironmentalMetric.TARGET_DISTRIBUTION]: { ND: 1.0, N: 0, L: 0.25, M: 0.75, H: 1.0 }, [EnvironmentalMetric.CONFIDENTIALITY_REQUIREMENT]: { ND: 1.0, L: 0.5, M: 1.0, H: 1.51 }, [EnvironmentalMetric.INTEGRITY_REQUIREMENT]: { ND: 1.0, L: 0.5, M: 1.0, H: 1.51 }, [EnvironmentalMetric.AVAILABILITY_REQUIREMENT]: { ND: 1.0, L: 0.5, M: 1.0, H: 1.51 } }; const getMetricNumericValue = (metric, metricsMap) => { if (!metricsMap.has(metric)) { throw new Error(`Missing metric: ${metric}`); } const score = { ...baseMetricValueScores, ...temporalMetricValueScores, ...environmentalMetricValueScores }[metric]; if (!score) { throw new Error(`Internal error. Missing metric score: ${metric}`); } return score[metricsMap.get(metric)]; }; const round = (input) => Math.round(input * 10) / 10; export const populateTemporalMetricDefaults = (metricsMap) => { [...temporalMetrics].forEach((metric) => { if (!metricsMap.has(metric)) { metricsMap.set(metric, 'ND'); } }); return metricsMap; }; export const populateEnvironmentalMetricDefaults = (metricsMap) => { [...environmentalMetrics].forEach((metric) => { if (!metricsMap.has(metric)) { metricsMap.set(metric, 'ND'); } }); return metricsMap; }; export class CvssV2Calculator { calculate(cvssString) { const metricsMap = parseMetricsAsMap(cvssString); const baseResult = this.calculateBaseScore(metricsMap); const temporalResult = this.calculateTemporalScore(baseResult, metricsMap); const environmentalResult = this.calculateEnvironmentalScore(baseResult, metricsMap); return { ...baseResult, ...temporalResult, ...environmentalResult, version: '2.0', metrics: metricsMap }; } calculateBaseScore(metricsMap) { const impact = this.calculateImpact(metricsMap); const exploitability = this.calculateExploitability(metricsMap); const fImpact = impact === 0 ? 0 : 1.176; const baseScore = (0.6 * impact + 0.4 * exploitability - 1.5) * fImpact; return { baseScore: round(baseScore), baseImpact: round(impact), baseExploitability: round(exploitability) }; } calculateImpact(metricsMap) { const c = getMetricNumericValue(BaseMetric.CONFIDENTIALITY_IMPACT, metricsMap); const i = getMetricNumericValue(BaseMetric.INTEGRITY_IMPACT, metricsMap); const a = getMetricNumericValue(BaseMetric.AVAILABILITY_IMPACT, metricsMap); return 10.41 * (1 - (1 - c) * (1 - i) * (1 - a)); } calculateExploitability(metricsMap) { const av = getMetricNumericValue(BaseMetric.ACCESS_VECTOR, metricsMap); const ac = getMetricNumericValue(BaseMetric.ACCESS_COMPLEXITY, metricsMap); const au = getMetricNumericValue(BaseMetric.AUTHENTICATION, metricsMap); return 20 * av * ac * au; } calculateTemporalScore(baseResult, metricsMap) { populateTemporalMetricDefaults(metricsMap); const e = getMetricNumericValue(TemporalMetric.EXPLOITABILITY, metricsMap); const rl = getMetricNumericValue(TemporalMetric.REMEDIATION_LEVEL, metricsMap); const rc = getMetricNumericValue(TemporalMetric.REPORT_CONFIDENCE, metricsMap); const temporalScore = round(baseResult.baseScore * e * rl * rc); return { temporalScore }; } calculateEnvironmentalScore(baseResult, metricsMap) { populateEnvironmentalMetricDefaults(metricsMap); const cdp = getMetricNumericValue(EnvironmentalMetric.COLLATERAL_DAMAGE_POTENTIAL, metricsMap); const td = getMetricNumericValue(EnvironmentalMetric.TARGET_DISTRIBUTION, metricsMap); // Adjusted Impact const c = getMetricNumericValue(BaseMetric.CONFIDENTIALITY_IMPACT, metricsMap); const i = getMetricNumericValue(BaseMetric.INTEGRITY_IMPACT, metricsMap); const a = getMetricNumericValue(BaseMetric.AVAILABILITY_IMPACT, metricsMap); const cr = getMetricNumericValue(EnvironmentalMetric.CONFIDENTIALITY_REQUIREMENT, metricsMap); const ir = getMetricNumericValue(EnvironmentalMetric.INTEGRITY_REQUIREMENT, metricsMap); const ar = getMetricNumericValue(EnvironmentalMetric.AVAILABILITY_REQUIREMENT, metricsMap); const adjustedImpact = Math.min(10, 10.41 * (1 - (1 - c * cr) * (1 - i * ir) * (1 - a * ar))); // Adjusted Base const fImpact = adjustedImpact === 0 ? 0 : 1.176; const adjustedBase = round((0.6 * adjustedImpact + 0.4 * baseResult.baseExploitability - 1.5) * fImpact); // Adjusted Temporal const e = getMetricNumericValue(TemporalMetric.EXPLOITABILITY, metricsMap); const rl = getMetricNumericValue(TemporalMetric.REMEDIATION_LEVEL, metricsMap); const rc = getMetricNumericValue(TemporalMetric.REPORT_CONFIDENCE, metricsMap); const adjustedTemporal = round(adjustedBase * e * rl * rc); const environmentalScore = round((adjustedTemporal + (10 - adjustedTemporal) * cdp) * td); return { environmentalScore }; } }