@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/).
1,168 lines (1,156 loc) • 55.5 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.cvss = {}));
})(this, (function (exports) { 'use strict';
exports.BaseMetric = void 0;
(function (BaseMetric) {
BaseMetric["ATTACK_VECTOR"] = "AV";
BaseMetric["ATTACK_COMPLEXITY"] = "AC";
BaseMetric["PRIVILEGES_REQUIRED"] = "PR";
BaseMetric["USER_INTERACTION"] = "UI";
BaseMetric["SCOPE"] = "S";
BaseMetric["CONFIDENTIALITY"] = "C";
BaseMetric["INTEGRITY"] = "I";
BaseMetric["AVAILABILITY"] = "A";
})(exports.BaseMetric || (exports.BaseMetric = {}));
exports.TemporalMetric = void 0;
(function (TemporalMetric) {
TemporalMetric["EXPLOIT_CODE_MATURITY"] = "E";
TemporalMetric["REMEDIATION_LEVEL"] = "RL";
TemporalMetric["REPORT_CONFIDENCE"] = "RC";
})(exports.TemporalMetric || (exports.TemporalMetric = {}));
exports.EnvironmentalMetric = void 0;
(function (EnvironmentalMetric) {
EnvironmentalMetric["CONFIDENTIALITY_REQUIREMENT"] = "CR";
EnvironmentalMetric["INTEGRITY_REQUIREMENT"] = "IR";
EnvironmentalMetric["AVAILABILITY_REQUIREMENT"] = "AR";
EnvironmentalMetric["MODIFIED_ATTACK_VECTOR"] = "MAV";
EnvironmentalMetric["MODIFIED_ATTACK_COMPLEXITY"] = "MAC";
EnvironmentalMetric["MODIFIED_PRIVILEGES_REQUIRED"] = "MPR";
EnvironmentalMetric["MODIFIED_USER_INTERACTION"] = "MUI";
EnvironmentalMetric["MODIFIED_SCOPE"] = "MS";
EnvironmentalMetric["MODIFIED_CONFIDENTIALITY"] = "MC";
EnvironmentalMetric["MODIFIED_INTEGRITY"] = "MI";
EnvironmentalMetric["MODIFIED_AVAILABILITY"] = "MA";
})(exports.EnvironmentalMetric || (exports.EnvironmentalMetric = {}));
const baseMetrics$1 = [
exports.BaseMetric.ATTACK_VECTOR,
exports.BaseMetric.ATTACK_COMPLEXITY,
exports.BaseMetric.PRIVILEGES_REQUIRED,
exports.BaseMetric.USER_INTERACTION,
exports.BaseMetric.SCOPE,
exports.BaseMetric.CONFIDENTIALITY,
exports.BaseMetric.INTEGRITY,
exports.BaseMetric.AVAILABILITY
];
const temporalMetrics$1 = [
exports.TemporalMetric.EXPLOIT_CODE_MATURITY,
exports.TemporalMetric.REMEDIATION_LEVEL,
exports.TemporalMetric.REPORT_CONFIDENCE
];
const environmentalMetrics$1 = [
exports.EnvironmentalMetric.AVAILABILITY_REQUIREMENT,
exports.EnvironmentalMetric.CONFIDENTIALITY_REQUIREMENT,
exports.EnvironmentalMetric.INTEGRITY_REQUIREMENT,
exports.EnvironmentalMetric.MODIFIED_ATTACK_VECTOR,
exports.EnvironmentalMetric.MODIFIED_ATTACK_COMPLEXITY,
exports.EnvironmentalMetric.MODIFIED_PRIVILEGES_REQUIRED,
exports.EnvironmentalMetric.MODIFIED_USER_INTERACTION,
exports.EnvironmentalMetric.MODIFIED_SCOPE,
exports.EnvironmentalMetric.MODIFIED_CONFIDENTIALITY,
exports.EnvironmentalMetric.MODIFIED_INTEGRITY,
exports.EnvironmentalMetric.MODIFIED_AVAILABILITY
];
const baseMetricValues$1 = {
[exports.BaseMetric.ATTACK_VECTOR]: ['N', 'A', 'L', 'P'],
[exports.BaseMetric.ATTACK_COMPLEXITY]: ['L', 'H'],
[exports.BaseMetric.PRIVILEGES_REQUIRED]: ['N', 'L', 'H'],
[exports.BaseMetric.USER_INTERACTION]: ['N', 'R'],
[exports.BaseMetric.SCOPE]: ['U', 'C'],
[exports.BaseMetric.CONFIDENTIALITY]: ['N', 'L', 'H'],
[exports.BaseMetric.INTEGRITY]: ['N', 'L', 'H'],
[exports.BaseMetric.AVAILABILITY]: ['N', 'L', 'H']
};
const temporalMetricValues$1 = {
[exports.TemporalMetric.EXPLOIT_CODE_MATURITY]: ['X', 'H', 'F', 'P', 'U'],
[exports.TemporalMetric.REMEDIATION_LEVEL]: ['X', 'U', 'W', 'T', 'O'],
[exports.TemporalMetric.REPORT_CONFIDENCE]: ['X', 'C', 'R', 'U']
};
const environmentalMetricValues$1 = {
[exports.EnvironmentalMetric.CONFIDENTIALITY_REQUIREMENT]: ['X', 'H', 'M', 'L'],
[exports.EnvironmentalMetric.INTEGRITY_REQUIREMENT]: ['X', 'H', 'M', 'L'],
[exports.EnvironmentalMetric.AVAILABILITY_REQUIREMENT]: ['X', 'H', 'M', 'L'],
[exports.EnvironmentalMetric.MODIFIED_ATTACK_VECTOR]: ['X', 'N', 'A', 'L', 'P'],
[exports.EnvironmentalMetric.MODIFIED_ATTACK_COMPLEXITY]: ['X', 'L', 'H'],
[exports.EnvironmentalMetric.MODIFIED_PRIVILEGES_REQUIRED]: ['X', 'N', 'L', 'H'],
[exports.EnvironmentalMetric.MODIFIED_USER_INTERACTION]: ['X', 'N', 'R'],
[exports.EnvironmentalMetric.MODIFIED_SCOPE]: ['X', 'U', 'C'],
[exports.EnvironmentalMetric.MODIFIED_CONFIDENTIALITY]: ['X', 'N', 'L', 'H'],
[exports.EnvironmentalMetric.MODIFIED_INTEGRITY]: ['X', 'N', 'L', 'H'],
[exports.EnvironmentalMetric.MODIFIED_AVAILABILITY]: ['X', 'N', 'L', 'H']
};
const VERSION_REGEX = /^CVSS:(\d(?:\.\d)?)(.*)?$/;
const parseVersion = (cvssStr) => {
const versionRegexRes = VERSION_REGEX.exec(cvssStr);
return versionRegexRes && versionRegexRes[1];
};
const parseVector = (cvssStr) => {
const versionRegexRes = VERSION_REGEX.exec(cvssStr);
return (versionRegexRes && versionRegexRes[2] && versionRegexRes[2].substring(1));
};
const parseMetrics = (vectorStr) => (vectorStr ? vectorStr.split('/') : []).map((metric) => {
if (!metric) {
return { key: '', value: '' };
}
const parts = metric.split(':');
return { key: parts[0], value: parts[1] };
});
const parseMetricsAsMap$1 = (cvssStr) => parseMetrics(parseVector(cvssStr) || '').reduce((res, metric) => {
if (res.has(metric.key)) {
throw new Error(`Duplicated metric: "${metric.key}:${metric.value || ''}"`);
}
return res.set(metric.key, metric.value);
}, new Map());
// https://www.first.org/cvss/v3.1/specification-document#7-4-Metric-Values
const baseMetricValueScores$1 = {
[exports.BaseMetric.ATTACK_VECTOR]: { N: 0.85, A: 0.62, L: 0.55, P: 0.2 },
[exports.BaseMetric.ATTACK_COMPLEXITY]: { L: 0.77, H: 0.44 },
[exports.BaseMetric.PRIVILEGES_REQUIRED]: null,
[exports.BaseMetric.USER_INTERACTION]: { N: 0.85, R: 0.62 },
[exports.BaseMetric.SCOPE]: { U: 0, C: 0 },
[exports.BaseMetric.CONFIDENTIALITY]: { N: 0, L: 0.22, H: 0.56 },
[exports.BaseMetric.INTEGRITY]: { N: 0, L: 0.22, H: 0.56 },
[exports.BaseMetric.AVAILABILITY]: { N: 0, L: 0.22, H: 0.56 }
};
const temporalMetricValueScores$1 = {
[exports.TemporalMetric.EXPLOIT_CODE_MATURITY]: {
X: 1,
U: 0.91,
F: 0.97,
P: 0.94,
H: 1
},
[exports.TemporalMetric.REMEDIATION_LEVEL]: { X: 1, O: 0.95, T: 0.96, W: 0.97, U: 1 },
[exports.TemporalMetric.REPORT_CONFIDENCE]: { X: 1, U: 0.92, R: 0.96, C: 1 }
};
const environmentalMetricValueScores$1 = {
[exports.EnvironmentalMetric.CONFIDENTIALITY_REQUIREMENT]: {
M: 1,
L: 0.5,
H: 1.5,
X: 1
},
[exports.EnvironmentalMetric.INTEGRITY_REQUIREMENT]: { M: 1, L: 0.5, H: 1.5, X: 1 },
[exports.EnvironmentalMetric.AVAILABILITY_REQUIREMENT]: {
M: 1,
L: 0.5,
H: 1.5,
X: 1
},
[exports.EnvironmentalMetric.MODIFIED_ATTACK_VECTOR]: baseMetricValueScores$1[exports.BaseMetric.ATTACK_VECTOR],
[exports.EnvironmentalMetric.MODIFIED_ATTACK_COMPLEXITY]: baseMetricValueScores$1[exports.BaseMetric.ATTACK_COMPLEXITY],
[exports.EnvironmentalMetric.MODIFIED_PRIVILEGES_REQUIRED]: null,
[exports.EnvironmentalMetric.MODIFIED_USER_INTERACTION]: baseMetricValueScores$1[exports.BaseMetric.USER_INTERACTION],
[exports.EnvironmentalMetric.MODIFIED_SCOPE]: baseMetricValueScores$1[exports.BaseMetric.SCOPE],
[exports.EnvironmentalMetric.MODIFIED_CONFIDENTIALITY]: baseMetricValueScores$1[exports.BaseMetric.CONFIDENTIALITY],
[exports.EnvironmentalMetric.MODIFIED_INTEGRITY]: baseMetricValueScores$1[exports.BaseMetric.INTEGRITY],
[exports.EnvironmentalMetric.MODIFIED_AVAILABILITY]: baseMetricValueScores$1[exports.BaseMetric.AVAILABILITY]
};
const getPrivilegesRequiredNumericValue = (value, scopeValue) => {
if (scopeValue !== 'U' && scopeValue !== 'C') {
throw new Error(`Unknown Scope value: ${scopeValue}`);
}
switch (value) {
case 'N':
return 0.85;
case 'L':
return scopeValue === 'U' ? 0.62 : 0.68;
case 'H':
return scopeValue === 'U' ? 0.27 : 0.5;
default:
throw new Error(`Unknown PrivilegesRequired value: ${value}`);
}
};
const getMetricValue = (metric, metricsMap) => {
if (!metricsMap.has(metric)) {
throw new Error(`Missing metric: ${metric}`);
}
return metricsMap.get(metric);
};
const getMetricNumericValue$1 = (metric, metricsMap) => {
const value = getMetricValue(metric || exports.TemporalMetric || exports.EnvironmentalMetric, metricsMap);
if (metric === exports.BaseMetric.PRIVILEGES_REQUIRED) {
return getPrivilegesRequiredNumericValue(value, getMetricValue(exports.BaseMetric.SCOPE, metricsMap));
}
if (metric === exports.EnvironmentalMetric.MODIFIED_PRIVILEGES_REQUIRED) {
return getPrivilegesRequiredNumericValue(value, getMetricValue(exports.EnvironmentalMetric.MODIFIED_SCOPE, metricsMap));
}
const score = {
...baseMetricValueScores$1,
...temporalMetricValueScores$1,
...environmentalMetricValueScores$1
}[metric];
if (!score) {
throw new Error(`Internal error. Missing metric score: ${metric}`);
}
return score[value];
};
// ISS = 1 - [ (1 - Confidentiality) × (1 - Integrity) × (1 - Availability) ]
const calculateIss = (metricsMap) => {
const confidentiality = getMetricNumericValue$1(exports.BaseMetric.CONFIDENTIALITY, metricsMap);
const integrity = getMetricNumericValue$1(exports.BaseMetric.INTEGRITY, metricsMap);
const availability = getMetricNumericValue$1(exports.BaseMetric.AVAILABILITY, metricsMap);
return 1 - (1 - confidentiality) * (1 - integrity) * (1 - availability);
};
// https://www.first.org/cvss/v3.1/specification-document#7-3-Environmental-Metrics-Equations
// MISS = Minimum ( 1 - [ (1 - ConfidentialityRequirement × ModifiedConfidentiality) × (1 - IntegrityRequirement × ModifiedIntegrity) × (1 - AvailabilityRequirement × ModifiedAvailability) ], 0.915)
const calculateMiss = (metricsMap) => {
const rConfidentiality = getMetricNumericValue$1(exports.EnvironmentalMetric.CONFIDENTIALITY_REQUIREMENT, metricsMap);
const mConfidentiality = getMetricNumericValue$1(exports.EnvironmentalMetric.MODIFIED_CONFIDENTIALITY, metricsMap);
const rIntegrity = getMetricNumericValue$1(exports.EnvironmentalMetric.INTEGRITY_REQUIREMENT, metricsMap);
const mIntegrity = getMetricNumericValue$1(exports.EnvironmentalMetric.MODIFIED_INTEGRITY, metricsMap);
const rAvailability = getMetricNumericValue$1(exports.EnvironmentalMetric.AVAILABILITY_REQUIREMENT, metricsMap);
const mAvailability = getMetricNumericValue$1(exports.EnvironmentalMetric.MODIFIED_AVAILABILITY, metricsMap);
return Math.min(1 -
(1 - rConfidentiality * mConfidentiality) *
(1 - rIntegrity * mIntegrity) *
(1 - rAvailability * mAvailability), 0.915);
};
// https://www.first.org/cvss/v3.1/specification-document#7-1-Base-Metrics-Equations
// Impact =
// If Scope is Unchanged 6.42 × ISS
// If Scope is Changed 7.52 × (ISS - 0.029) - 3.25 × (ISS - 0.02)^15
const calculateImpact = (metricsMap, iss) => metricsMap.get(exports.BaseMetric.SCOPE) === 'U'
? 6.42 * iss
: 7.52 * (iss - 0.029) - 3.25 * Math.pow(iss - 0.02, 15);
// https://www.first.org/cvss/v3-0/specification-document#8-1-Base
// ModifiedImpact =
// If ModifiedScope is Unchanged 6.42 × MISS
// If ModifiedScope is Changed 7.52 × (MISS - 0.029) - 3.25 × (MISS - 0.02)^15
// ModifiedExploitability = 8.22 × ModifiedAttackVector × ModifiedAttackComplexity × ModifiedPrivilegesRequired × ModifiedUserInteraction
const calculateModifiedImpactV3 = (metricsMap, miss) => metricsMap.get(exports.EnvironmentalMetric.MODIFIED_SCOPE) === 'U'
? 6.42 * miss
: 7.52 * (miss - 0.029) - 3.25 * Math.pow(miss * 1 - 0.02, 15);
// https://www.first.org/cvss/v3.1/specification-document#7-3-Environmental-Metrics-Equations
// ModifiedImpact =
// If ModifiedScope is Unchanged 6.42 × MISS
// If ModifiedScope is Changed 7.52 × (MISS - 0.029) - 3.25 × (MISS × 0.9731 - 0.02)^13
// ModifiedExploitability = 8.22 × ModifiedAttackVector × ModifiedAttackComplexity × ModifiedPrivilegesRequired × ModifiedUserInteraction
const calculateModifiedImpactV31 = (metricsMap, miss) => metricsMap.get(exports.EnvironmentalMetric.MODIFIED_SCOPE) === 'U'
? 6.42 * miss
: 7.52 * (miss - 0.029) - 3.25 * Math.pow(miss * 0.9731 - 0.02, 13);
const calculateModifiedImpact = (metricsMap, miss, versionStr) => versionStr === '3.0'
? calculateModifiedImpactV3(metricsMap, miss)
: calculateModifiedImpactV31(metricsMap, miss);
// https://www.first.org/cvss/v3.1/specification-document#7-1-Base-Metrics-Equations
// Exploitability = 8.22 × AttackVector × AttackComplexity × PrivilegesRequired × UserInteraction
const calculateExploitability = (metricsMap) => 8.22 *
getMetricNumericValue$1(exports.BaseMetric.ATTACK_VECTOR, metricsMap) *
getMetricNumericValue$1(exports.BaseMetric.ATTACK_COMPLEXITY, metricsMap) *
getMetricNumericValue$1(exports.BaseMetric.PRIVILEGES_REQUIRED, metricsMap) *
getMetricNumericValue$1(exports.BaseMetric.USER_INTERACTION, metricsMap);
// https://www.first.org/cvss/v3.1/specification-document#7-3-Environmental-Metrics-Equations
// Exploitability = 8.22 × ModifiedAttackVector × ModifiedAttackComplexity × ModifiedPrivilegesRequired × ModifiedUserInteraction
const calculateModifiedExploitability = (metricsMap) => 8.22 *
getMetricNumericValue$1(exports.EnvironmentalMetric.MODIFIED_ATTACK_VECTOR, metricsMap) *
getMetricNumericValue$1(exports.EnvironmentalMetric.MODIFIED_ATTACK_COMPLEXITY, metricsMap) *
getMetricNumericValue$1(exports.EnvironmentalMetric.MODIFIED_PRIVILEGES_REQUIRED, metricsMap) *
getMetricNumericValue$1(exports.EnvironmentalMetric.MODIFIED_USER_INTERACTION, metricsMap);
// https://www.first.org/cvss/v3.1/specification-document#Appendix-A---Floating-Point-Rounding
const roundUp = (input) => {
const intInput = Math.round(input * 100000);
return intInput % 10000 === 0
? intInput / 100000
: (Math.floor(intInput / 10000) + 1) / 10;
};
const round$1 = (input) => {
const intInput = Math.round(input * 100000);
return Math.round(intInput / 10000) / 10;
};
const modifiedMetricsMap = {
MAV: exports.BaseMetric.ATTACK_VECTOR,
MAC: exports.BaseMetric.ATTACK_COMPLEXITY,
MPR: exports.BaseMetric.PRIVILEGES_REQUIRED,
MUI: exports.BaseMetric.USER_INTERACTION,
MS: exports.BaseMetric.SCOPE,
MC: exports.BaseMetric.CONFIDENTIALITY,
MI: exports.BaseMetric.INTEGRITY,
MA: exports.BaseMetric.AVAILABILITY
};
// When Modified Temporal metric value is 'Not Defined' ('X'), which is the default value,
// then Base metric value should be used.
const populateTemporalMetricDefaults$1 = (metricsMap) => {
[...temporalMetrics$1].forEach((metric) => {
if (!metricsMap.has(metric)) {
metricsMap.set(metric, 'X');
}
});
return metricsMap;
};
const populateEnvironmentalMetricDefaults$1 = (metricsMap) => {
[...environmentalMetrics$1].forEach((metric) => {
if (!metricsMap.has(metric)) {
metricsMap.set(metric, 'X');
}
if (metricsMap.get(metric) === 'X') {
metricsMap.set(metric, metricsMap.has(modifiedMetricsMap[metric])
? metricsMap.get(modifiedMetricsMap[metric])
: 'X');
}
});
return metricsMap;
};
class CvssV3Calculator {
calculate(cvssString) {
const metricsMap = parseMetricsAsMap$1(cvssString);
const versionStr = parseVersion(cvssString);
const baseResult = this.calculateBaseScore(metricsMap, versionStr);
const temporalResult = this.calculateTemporalScore(baseResult);
const environmentalResult = this.calculateEnvironmentalScore(metricsMap, versionStr);
return {
...baseResult,
...temporalResult,
...environmentalResult
};
}
/**
* Calculate the base score for a CVSS v3.x string
*/
calculateBaseScore(metricsMap, versionStr) {
const iss = calculateIss(metricsMap);
const impact = calculateImpact(metricsMap, iss);
const exploitability = calculateExploitability(metricsMap);
const scopeUnchanged = metricsMap.get(exports.BaseMetric.SCOPE) === 'U';
const baseScore = impact <= 0
? 0
: scopeUnchanged
? roundUp(Math.min(impact + exploitability, 10))
: roundUp(Math.min(1.08 * (impact + exploitability), 10));
return {
version: versionStr,
baseScore,
baseImpact: impact <= 0 ? 0 : round$1(impact),
baseExploitability: exploitability <= 0 ? 0 : round$1(exploitability),
metrics: metricsMap
};
}
/**
* Calculate the temporal score for a CVSS v3.x string
*/
calculateTemporalScore(baseResult) {
// populate temp metrics
const metricsMap = populateTemporalMetricDefaults$1(baseResult.metrics);
const temporalScore = roundUp(baseResult.baseScore *
getMetricNumericValue$1(exports.TemporalMetric.REPORT_CONFIDENCE, metricsMap) *
getMetricNumericValue$1(exports.TemporalMetric.EXPLOIT_CODE_MATURITY, metricsMap) *
getMetricNumericValue$1(exports.TemporalMetric.REMEDIATION_LEVEL, metricsMap));
return {
temporalScore
};
}
/**
* Calculate the environmental score for a CVSS v3.x string
*/
calculateEnvironmentalScore(metricsMap, versionStr) {
metricsMap = populateTemporalMetricDefaults$1(metricsMap);
metricsMap = populateEnvironmentalMetricDefaults$1(metricsMap);
const miss = calculateMiss(metricsMap);
const impact = calculateModifiedImpact(metricsMap, miss, versionStr);
const exploitability = calculateModifiedExploitability(metricsMap);
const scopeUnchanged = metricsMap.get(exports.EnvironmentalMetric.MODIFIED_SCOPE) === 'U';
const environmentalScore = impact <= 0
? 0
: scopeUnchanged
? roundUp(roundUp(Math.min(impact + exploitability, 10)) *
getMetricNumericValue$1(exports.TemporalMetric.EXPLOIT_CODE_MATURITY, metricsMap) *
getMetricNumericValue$1(exports.TemporalMetric.REMEDIATION_LEVEL, metricsMap) *
getMetricNumericValue$1(exports.TemporalMetric.REPORT_CONFIDENCE, metricsMap))
: roundUp(roundUp(Math.min(1.08 * (impact + exploitability), 10)) *
getMetricNumericValue$1(exports.TemporalMetric.EXPLOIT_CODE_MATURITY, metricsMap) *
getMetricNumericValue$1(exports.TemporalMetric.REMEDIATION_LEVEL, metricsMap) *
getMetricNumericValue$1(exports.TemporalMetric.REPORT_CONFIDENCE, metricsMap));
return {
environmentalScore,
modifiedImpact: impact <= 0 ? 0 : round$1(impact),
modifiedExploitability: exploitability <= 0 ? 0 : round$1(exploitability)
};
}
}
var BaseMetric;
(function (BaseMetric) {
BaseMetric["ACCESS_VECTOR"] = "AV";
BaseMetric["ACCESS_COMPLEXITY"] = "AC";
BaseMetric["AUTHENTICATION"] = "Au";
BaseMetric["CONFIDENTIALITY_IMPACT"] = "C";
BaseMetric["INTEGRITY_IMPACT"] = "I";
BaseMetric["AVAILABILITY_IMPACT"] = "A";
})(BaseMetric || (BaseMetric = {}));
var TemporalMetric;
(function (TemporalMetric) {
TemporalMetric["EXPLOITABILITY"] = "E";
TemporalMetric["REMEDIATION_LEVEL"] = "RL";
TemporalMetric["REPORT_CONFIDENCE"] = "RC";
})(TemporalMetric || (TemporalMetric = {}));
var EnvironmentalMetric;
(function (EnvironmentalMetric) {
EnvironmentalMetric["COLLATERAL_DAMAGE_POTENTIAL"] = "CDP";
EnvironmentalMetric["TARGET_DISTRIBUTION"] = "TD";
EnvironmentalMetric["CONFIDENTIALITY_REQUIREMENT"] = "CR";
EnvironmentalMetric["INTEGRITY_REQUIREMENT"] = "IR";
EnvironmentalMetric["AVAILABILITY_REQUIREMENT"] = "AR";
})(EnvironmentalMetric || (EnvironmentalMetric = {}));
const baseMetrics = [
BaseMetric.ACCESS_VECTOR,
BaseMetric.ACCESS_COMPLEXITY,
BaseMetric.AUTHENTICATION,
BaseMetric.CONFIDENTIALITY_IMPACT,
BaseMetric.INTEGRITY_IMPACT,
BaseMetric.AVAILABILITY_IMPACT
];
const temporalMetrics = [
TemporalMetric.EXPLOITABILITY,
TemporalMetric.REMEDIATION_LEVEL,
TemporalMetric.REPORT_CONFIDENCE
];
const environmentalMetrics = [
EnvironmentalMetric.COLLATERAL_DAMAGE_POTENTIAL,
EnvironmentalMetric.TARGET_DISTRIBUTION,
EnvironmentalMetric.CONFIDENTIALITY_REQUIREMENT,
EnvironmentalMetric.INTEGRITY_REQUIREMENT,
EnvironmentalMetric.AVAILABILITY_REQUIREMENT
];
const baseMetricValues = {
[BaseMetric.ACCESS_VECTOR]: ['L', 'A', 'N'],
[BaseMetric.ACCESS_COMPLEXITY]: ['H', 'M', 'L'],
[BaseMetric.AUTHENTICATION]: ['M', 'S', 'N'],
[BaseMetric.CONFIDENTIALITY_IMPACT]: ['N', 'P', 'C'],
[BaseMetric.INTEGRITY_IMPACT]: ['N', 'P', 'C'],
[BaseMetric.AVAILABILITY_IMPACT]: ['N', 'P', 'C']
};
const temporalMetricValues = {
[TemporalMetric.EXPLOITABILITY]: ['U', 'POC', 'F', 'H', 'ND'],
[TemporalMetric.REMEDIATION_LEVEL]: ['OF', 'TF', 'W', 'U', 'ND'],
[TemporalMetric.REPORT_CONFIDENCE]: ['UC', 'UR', 'C', 'ND']
};
const environmentalMetricValues = {
[EnvironmentalMetric.COLLATERAL_DAMAGE_POTENTIAL]: [
'N',
'L',
'LM',
'MH',
'H',
'ND'
],
[EnvironmentalMetric.TARGET_DISTRIBUTION]: ['N', 'L', 'M', 'H', 'ND'],
[EnvironmentalMetric.CONFIDENTIALITY_REQUIREMENT]: ['L', 'M', 'H', 'ND'],
[EnvironmentalMetric.INTEGRITY_REQUIREMENT]: ['L', 'M', 'H', 'ND'],
[EnvironmentalMetric.AVAILABILITY_REQUIREMENT]: ['L', 'M', 'H', 'ND']
};
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;
const populateTemporalMetricDefaults = (metricsMap) => {
[...temporalMetrics].forEach((metric) => {
if (!metricsMap.has(metric)) {
metricsMap.set(metric, 'ND');
}
});
return metricsMap;
};
const populateEnvironmentalMetricDefaults = (metricsMap) => {
[...environmentalMetrics].forEach((metric) => {
if (!metricsMap.has(metric)) {
metricsMap.set(metric, 'ND');
}
});
return metricsMap;
};
class CvssV2Calculator {
calculate(cvssString) {
const metricsMap = parseMetricsAsMap$1(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 };
}
}
const createCvssCalculator = (version) => {
switch (version) {
case '2.0':
return new CvssV2Calculator();
case '3.0':
case '3.1':
return new CvssV3Calculator();
default:
throw new Error(`Unsupported CVSS version: ${version}`);
}
};
const validateVector = (vectorStr) => {
if (!vectorStr || vectorStr.includes('//')) {
throw new Error('Invalid CVSS string');
}
};
const checkUnknownMetrics = (metricsMap, knownMetrics) => {
[...metricsMap.keys()].forEach((userMetric) => {
if (!knownMetrics.includes(userMetric)) {
throw new Error(`Unknown CVSS metric "${userMetric}". Allowed metrics: ${knownMetrics.join(', ')}`);
}
});
};
const checkMandatoryMetrics = (metricsMap, metrics, humanizer) => {
metrics.forEach((metric) => {
if (!metricsMap.has(metric)) {
const metricName = humanizer ? humanizer.humanizeMetric(metric) : metric;
throw new Error(`Missing mandatory CVSS metric ${metricName}`);
}
});
};
const checkMetricsValues = (metricsMap, metrics, metricsValues, humanizer) => {
metrics.forEach((metric) => {
const userValue = metricsMap.get(metric);
if (!userValue) {
return;
}
if (!metricsValues[metric].includes(userValue)) {
let errorMsg = '';
if (humanizer) {
const allowedValuesHumanized = metricsValues[metric]
.map((value) => `${value} (${humanizer.humanizeMetricValue(value, metric)})`)
.join(', ');
errorMsg = `Invalid value for CVSS metric ${metric} (${humanizer.humanizeMetric(metric)})${userValue ? `: ${userValue}` : ''}. Allowed values: ${allowedValuesHumanized}`;
}
else {
const allowedValues = metricsValues[metric].join(', ');
errorMsg = `Invalid value for CVSS metric ${metric}: ${userValue}. Allowed values: ${allowedValues}`;
}
throw new Error(errorMsg);
}
});
};
const validateByKnownMaps = (cvssStr, validateVersion, metrics, knownMetricsValues, humanizer) => {
if (!cvssStr || !cvssStr.startsWith('CVSS:')) {
throw new Error('CVSS vector must start with "CVSS:"');
}
const versionStr = parseVersion(cvssStr);
validateVersion(versionStr);
const vectorStr = parseVector(cvssStr);
validateVector(vectorStr);
const allMetrics = [
...metrics.base,
...metrics.temporal,
...metrics.environmental
];
const metricsMap = parseMetricsAsMap$1(cvssStr);
checkMandatoryMetrics(metricsMap, metrics.base, humanizer);
checkUnknownMetrics(metricsMap, allMetrics);
checkMetricsValues(metricsMap, allMetrics, knownMetricsValues, humanizer);
const isTemporal = [...metricsMap.keys()].some((metric) => metrics.temporal.includes(metric));
const isEnvironmental = [...metricsMap.keys()].some((metric) => metrics.environmental.includes(metric));
return {
metricsMap,
isTemporal,
isEnvironmental,
versionStr
};
};
// eslint-disable-next-line complexity
const humanizeMetric$1 = (metric) => {
switch (metric) {
case BaseMetric.ACCESS_VECTOR:
return 'Access Vector';
case BaseMetric.ACCESS_COMPLEXITY:
return 'Access Complexity';
case BaseMetric.AUTHENTICATION:
return 'Authentication';
case BaseMetric.CONFIDENTIALITY_IMPACT:
return 'Confidentiality Impact';
case BaseMetric.INTEGRITY_IMPACT:
return 'Integrity Impact';
case BaseMetric.AVAILABILITY_IMPACT:
return 'Availability Impact';
case TemporalMetric.EXPLOITABILITY:
return 'Exploitability';
case TemporalMetric.REMEDIATION_LEVEL:
return 'Remediation Level';
case TemporalMetric.REPORT_CONFIDENCE:
return 'Report Confidence';
case EnvironmentalMetric.COLLATERAL_DAMAGE_POTENTIAL:
return 'Collateral Damage Potential';
case EnvironmentalMetric.TARGET_DISTRIBUTION:
return 'Target Distribution';
case EnvironmentalMetric.CONFIDENTIALITY_REQUIREMENT:
return 'Confidentiality Requirement';
case EnvironmentalMetric.INTEGRITY_REQUIREMENT:
return 'Integrity Requirement';
case EnvironmentalMetric.AVAILABILITY_REQUIREMENT:
return 'Availability Requirement';
default:
return 'Unknown';
}
};
// eslint-disable-next-line complexity
const humanizeMetricValue$1 = (value, metric) => {
switch (metric) {
case BaseMetric.ACCESS_VECTOR:
switch (value) {
case 'L':
return 'Local';
case 'A':
return 'Adjacent Network';
case 'N':
return 'Network';
}
break;
case BaseMetric.ACCESS_COMPLEXITY:
switch (value) {
case 'H':
return 'High';
case 'M':
return 'Medium';
case 'L':
return 'Low';
}
break;
case BaseMetric.AUTHENTICATION:
switch (value) {
case 'M':
return 'Multiple';
case 'S':
return 'Single';
case 'N':
return 'None';
}
break;
case BaseMetric.CONFIDENTIALITY_IMPACT:
case BaseMetric.INTEGRITY_IMPACT:
case BaseMetric.AVAILABILITY_IMPACT:
switch (value) {
case 'N':
return 'None';
case 'P':
return 'Partial';
case 'C':
return 'Complete';
}
break;
case TemporalMetric.EXPLOITABILITY:
switch (value) {
case 'U':
return 'Unproven that exploit exists';
case 'POC':
return 'Proof of concept code';
case 'F':
return 'Functional exploit exists';
case 'H':
return 'High';
case 'ND':
return 'Not Defined';
}
break;
case TemporalMetric.REMEDIATION_LEVEL:
switch (value) {
case 'OF':
return 'Official fix';
case 'TF':
return 'Temporary fix';
case 'W':
return 'Workaround';
case 'U':
return 'Unavailable';
case 'ND':
return 'Not Defined';
}
break;
case TemporalMetric.REPORT_CONFIDENCE:
switch (value) {
case 'UC':
return 'Unconfirmed';
case 'UR':
return 'Uncorroborated';
case 'C':
return 'Confirmed';
case 'ND':
return 'Not Defined';
}
break;
case EnvironmentalMetric.COLLATERAL_DAMAGE_POTENTIAL:
switch (value) {
case 'N':
return 'None';
case 'L':
return 'Low (light loss)';
case 'LM':
return 'Low-Medium';
case 'MH':
return 'Medium-High';
case 'H':
return 'High (catastrophic loss)';
case 'ND':
return 'Not Defined';
}
break;
case EnvironmentalMetric.TARGET_DISTRIBUTION:
switch (value) {
case 'N':
return 'None [0%]';
case 'L':
return 'Low [0-25%]';
case 'M':
return 'Medium [26-75%]';
case 'H':
return 'High [76-100%]';
case 'ND':
return 'Not Defined';
}
break;
case EnvironmentalMetric.CONFIDENTIALITY_REQUIREMENT:
case EnvironmentalMetric.INTEGRITY_REQUIREMENT:
case EnvironmentalMetric.AVAILABILITY_REQUIREMENT:
switch (value) {
case 'L':
return 'Low';
case 'M':
return 'Medium';
case 'H':
return 'High';
case 'ND':
return 'Not Defined';
}
break;
}
return 'Unknown';
};
const validateVersion$2 = (versionStr) => {
if (!versionStr) {
throw new Error('Invalid CVSS string. Example: CVSS:2.0/AV:N/AC:L/Au:N/C:N/I:N/A:C');
}
if (versionStr !== '2.0') {
throw new Error(`Unsupported CVSS version: ${versionStr}. Only 2.0 is supported by this validator.`);
}
};
const validate$2 = (cvssStr) => validateByKnownMaps(cvssStr, validateVersion$2, {
base: baseMetrics,
temporal: temporalMetrics,
environmental: environmentalMetrics
}, {
...baseMetricValues,
...temporalMetricValues,
...environmentalMetricValues
}, {
humanizeMetric: humanizeMetric$1,
humanizeMetricValue: humanizeMetricValue$1
});
// eslint-disable-next-line complexity
const humanizeMetric = (metric) => {
switch (metric) {
case exports.BaseMetric.ATTACK_VECTOR:
return 'Attack Vector';
case exports.BaseMetric.ATTACK_COMPLEXITY:
return 'Attack Complexity';
case exports.BaseMetric.PRIVILEGES_REQUIRED:
return 'Privileges Required';
case exports.BaseMetric.USER_INTERACTION:
return 'User Interaction';
case exports.BaseMetric.SCOPE:
return 'Scope';
case exports.BaseMetric.CONFIDENTIALITY:
return 'Confidentiality';
case exports.BaseMetric.INTEGRITY:
return 'Integrity';
case exports.BaseMetric.AVAILABILITY:
return 'Availability';
case exports.TemporalMetric.EXPLOIT_CODE_MATURITY:
return 'Exploit Code Maturity';
case exports.TemporalMetric.REMEDIATION_LEVEL:
return 'Remediation Level';
case exports.TemporalMetric.REPORT_CONFIDENCE:
return 'Report Confidence';
case exports.EnvironmentalMetric.CONFIDENTIALITY_REQUIREMENT:
return 'Confidentiality Requirement';
case exports.EnvironmentalMetric.INTEGRITY_REQUIREMENT:
return 'Integrity Requirement';
case exports.EnvironmentalMetric.AVAILABILITY_REQUIREMENT:
return 'Availability Requirement';
case exports.EnvironmentalMetric.MODIFIED_ATTACK_VECTOR:
return 'Modified Attack Vector';
case exports.EnvironmentalMetric.MODIFIED_ATTACK_COMPLEXITY:
return 'Modified Attack Complexity';
case exports.EnvironmentalMetric.MODIFIED_PRIVILEGES_REQUIRED:
return 'Modified Privileges Required';
case exports.EnvironmentalMetric.MODIFIED_USER_INTERACTION:
return 'Modified User Interaction';
case exports.EnvironmentalMetric.MODIFIED_SCOPE:
return 'Modified Scope';
case exports.EnvironmentalMetric.MODIFIED_CONFIDENTIALITY:
return 'Modified Confidentiality';
case exports.EnvironmentalMetric.MODIFIED_INTEGRITY:
return 'Modified Integrity';
case exports.EnvironmentalMetric.MODIFIED_AVAILABILITY:
return 'Modified Availability';
default:
return 'Unknown';
}
};
// eslint-disable-next-line complexity
const humanizeMetricValue = (value, metric) => {
switch (metric) {
case exports.BaseMetric.ATTACK_VECTOR:
switch (value) {
case 'N':
return 'Network';
case 'A':
return 'Adjacent';
case 'L':
return 'Local';
case 'P':
return 'Physical';
}
break;
case exports.BaseMetric.ATTACK_COMPLEXITY:
switch (value) {
case 'L':
return 'Low';
case 'H':
return 'High';
}
break;
case exports.BaseMetric.PRIVILEGES_REQUIRED:
switch (value) {
case 'N':
return 'None';
case 'L':
return 'Low';
case 'H':
return 'High';
}
break;
case exports.BaseMetric.USER_INTERACTION:
switch (value) {
case 'N':
return 'None';
case 'R':
return 'Required';
}
break;
case exports.BaseMetric.SCOPE:
switch (value) {
case 'U':
return 'Unchanged';
case 'C':
return 'Changed';
}
break;
case exports.BaseMetric.CONFIDENTIALITY:
case exports.BaseMetric.INTEGRITY:
case exports.BaseMetric.AVAILABILITY:
switch (value) {
case 'N':
return 'None';
case 'L':
return 'Low';
case 'H':
return 'High';
}
break;
case exports.TemporalMetric.EXPLOIT_CODE_MATURITY:
switch (value) {
case 'X':
return 'Not Defined';
case 'U':
return 'Unproven';
case 'P':
return 'Proof-of-Concept';
case 'F':
return 'Functional';
case 'H':
return 'High';
}
break;
case exports.TemporalMetric.REMEDIATION_LEVEL:
switch (value) {
case 'X':
return 'Not Defined';
case 'O':
return 'Official Fix';
case 'T':
return 'Temporary Fix';
case 'W':
return 'Workaround';
case 'U':
return 'Unavailable';
}
break;
case exports.TemporalMetric.REPORT_CONFIDENCE:
switch (value) {
case 'X':
return 'Not Defined';
case 'U':
return 'Unknown';
case 'R':
return 'Reasonable';
case 'C':
return 'Confirmed';
}
break;
case exports.EnvironmentalMetric.CONFIDENTIALITY_REQUIREMENT:
case exports.EnvironmentalMetric.INTEGRITY_REQUIREMENT:
case exports.EnvironmentalMetric.AVAILABILITY_REQUIREMENT:
switch (value) {
case 'X':
return 'Not Defined';
case 'L':
return 'Low';
case 'M':
return 'Medium';
case 'H':
return 'High';
}
break;
case exports.EnvironmentalMetric.MODIFIED_ATTACK_VECTOR:
switch (value) {
case 'X':
return 'Not Defined';
case 'N':
return 'Network';
case 'A':
return 'Adjacent Network';
case 'L':
return 'Local';
case 'P':
return 'Physical';
}
break;
case exports.EnvironmentalMetric.MODIFIED_ATTACK_COMPLEXITY:
switch (value) {
case 'X':
return 'Not Defined';
case 'L':
return 'Low';
case 'H':
return 'High';
}
break;
case exports.EnvironmentalMetric.MODIFIED_PRIVILEGES_REQUIRED:
switch (value) {
case 'X':
return 'Not Defined';
case 'N':
return 'None';
case 'L':
return 'Low';
case 'H':
return 'High';
}
break;
case exports.EnvironmentalMetric.MODIFIED_USER_INTERACTION:
switch (value) {
case 'X':
return 'Not Defined';
case 'N':
return 'None';
case 'R':
return 'Required';
}
break;
case exports.EnvironmentalMetric.MODIFIED_SCOPE:
switch (value) {
case 'X':
return 'Not Defined';
case 'U':
return 'Unchanged';
case 'C':
return 'Changed';
}
break;
case exports.EnvironmentalMetric.MODIFIED_CONFIDENTIALITY:
case exports.EnvironmentalMetric.MODIFIED_INTEGRITY:
case exports.EnvironmentalMetric.MODIFIED_AVAILABILITY:
switch (value) {
case 'X':
return 'Not Defined';
case 'N':
return 'None';
case 'L':
return 'Low';
case 'H':
return 'High';
}
break;
}
return 'Unknown';
};
// legacy, before introduction of Temporal and Environmental metrics support
const humanizeBaseMetric = (metric) => humanizeMetric(metric);
// legacy, before introduction of Temporal and Environmental metrics support
const humanizeBaseMetricValue = (value, metric) => humanizeMetricValue(value, metric);
const validateVersion$1 = (versionStr) => {
if (!versionStr) {
throw new Error('Invalid CVSS string. Example: CVSS:3.0/AV:A/AC:H/PR:H/UI:R/S:U/C:N/I:N/A:L');
}
if (versionStr !== '3.0' && versionStr !== '3.1') {
throw new Error(`Unsupported CVSS version: ${versionStr}. Only 3.0 and 3.1 are supported by this validator.`);
}
};
const validate$1 = (cvssStr) => validateByKnownMaps(cvssStr, validateVersion$1, {
base: baseMetrics$1,
temporal: temporalMetrics$1,
environmental: environmentalMetrics$1
}, {
...baseMetricValues$1,
...temporalMetricValues$1,
...environmentalMetricValues$1
}, {
humanizeMetric,
humanizeMetricValue
});
const validate = (cvssString) => {
if (!cvssString || !cvssString.startsWith('CVSS:')) {
throw new Error('CVSS vector must start with "CVSS:"');
}
const versionStr = parseVersion(cvssString);
const validateString = versionStr === '2.0' ? validate$2 : validate$1;
validateString(cvssString);
};
function calculateCvss(cvssString) {
const version = parseVersion(cvssString);
if (!version) {
throw new Error('Invalid CVSS string: