@neuralegion/cvss
Version:
The Common Vulnerability Scoring System ([CVSS](https://www.first.org/cvss/)) [base](https://www.first.org/cvss/specification-document#Base-Metrics) [score](https://www.first.org/cvss/specification-document#1-2-Scoring) calculator and validator library wr
556 lines (547 loc) • 26.7 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 = [
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 = [
exports.TemporalMetric.EXPLOIT_CODE_MATURITY,
exports.TemporalMetric.REMEDIATION_LEVEL,
exports.TemporalMetric.REPORT_CONFIDENCE
];
const environmentalMetrics = [
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 = {
[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 = {
[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 = {
[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 humanizeBaseMetric = (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';
default:
return 'Unknown';
}
};
// eslint-disable-next-line complexity
const humanizeBaseMetricValue = (value, metric) => {
switch (value) {
case 'A':
return 'Adjacent';
case 'C':
return 'Changed';
case 'H':
return 'High';
case 'L':
return metric === exports.BaseMetric.ATTACK_VECTOR ? 'Local' : 'Low';
case 'N':
return metric === exports.BaseMetric.ATTACK_VECTOR ? 'Network' : 'None';
case 'P':
return 'Physical';
case 'R':
return 'Required';
case 'U':
return 'Unchanged';
default:
return 'Unknown';
}
};
/**
* Stringify a score into a qualitative severity rating string
* @param score
*/
const humanizeScore = (score) => score <= 0
? 'None'
: score <= 3.9
? 'Low'
: score <= 6.9
? 'Medium'
: score <= 8.9
? 'High'
: 'Critical';
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].substr(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 = (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());
const validateVersion = (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`);
}
};
const validateVector = (vectorStr) => {
if (!vectorStr || vectorStr.includes('//')) {
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');
}
};
const checkUnknownMetrics = (metricsMap, knownMetrics) => {
const allKnownMetrics = knownMetrics || [
...baseMetrics,
...temporalMetrics,
...environmentalMetrics
];
[...metricsMap.keys()].forEach((userMetric) => {
if (!allKnownMetrics.includes(userMetric)) {
throw new Error(`Unknown CVSS metric "${userMetric}". Allowed metrics: ${allKnownMetrics.join(', ')}`);
}
});
};
const checkMandatoryMetrics = (metricsMap, metrics = baseMetrics) => {
metrics.forEach((metric) => {
if (!metricsMap.has(metric)) {
// eslint-disable-next-line max-len
throw new Error(`Missing mandatory CVSS metric ${metrics} (${humanizeBaseMetric(metric)})`);
}
});
};
const checkMetricsValues = (metricsMap, metrics, metricsValues) => {
metrics.forEach((metric) => {
const userValue = metricsMap.get(metric);
if (!userValue) {
return;
}
if (!metricsValues[metric].includes(userValue)) {
const allowedValuesHumanized = metricsValues[metric]
.map((value) => `${value} (${humanizeBaseMetricValue(value, metric)})`)
.join(', ');
throw new Error(`Invalid value for CVSS metric ${metric} (${humanizeBaseMetric(metric)})${userValue ? `: ${userValue}` : ''}. Allowed values: ${allowedValuesHumanized}`);
}
});
};
/**
* Validate that the given string is a valid cvss vector
* @param cvssStr
*/
const validate = (cvssStr) => {
if (!cvssStr || !cvssStr.startsWith('CVSS:')) {
throw new Error('CVSS vector must start with "CVSS:"');
}
const allKnownMetrics = [
...baseMetrics,
...temporalMetrics,
...environmentalMetrics
];
const allKnownMetricsValues = {
...baseMetricValues,
...temporalMetricValues,
...environmentalMetricValues
};
const versionStr = parseVersion(cvssStr);
validateVersion(versionStr);
const vectorStr = parseVector(cvssStr);
validateVector(vectorStr);
const metricsMap = parseMetricsAsMap(cvssStr);
checkMandatoryMetrics(metricsMap);
checkUnknownMetrics(metricsMap, allKnownMetrics);
checkMetricsValues(metricsMap, allKnownMetrics, allKnownMetricsValues);
const isTemporal = [...metricsMap.keys()].some((metric) => temporalMetrics.includes(metric));
const isEnvironmental = [...metricsMap.keys()].some((metric) => environmentalMetrics.includes(metric));
return {
metricsMap,
isTemporal,
isEnvironmental,
versionStr
};
};
// https://www.first.org/cvss/v3.1/specification-document#7-4-Metric-Values
const baseMetricValueScores = {
[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 = {
[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 = {
[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[exports.BaseMetric.ATTACK_VECTOR],
[exports.EnvironmentalMetric.MODIFIED_ATTACK_COMPLEXITY]: baseMetricValueScores[exports.BaseMetric.ATTACK_COMPLEXITY],
[exports.EnvironmentalMetric.MODIFIED_PRIVILEGES_REQUIRED]: null,
[exports.EnvironmentalMetric.MODIFIED_USER_INTERACTION]: baseMetricValueScores[exports.BaseMetric.USER_INTERACTION],
[exports.EnvironmentalMetric.MODIFIED_SCOPE]: baseMetricValueScores[exports.BaseMetric.SCOPE],
[exports.EnvironmentalMetric.MODIFIED_CONFIDENTIALITY]: baseMetricValueScores[exports.BaseMetric.CONFIDENTIALITY],
[exports.EnvironmentalMetric.MODIFIED_INTEGRITY]: baseMetricValueScores[exports.BaseMetric.INTEGRITY],
[exports.EnvironmentalMetric.MODIFIED_AVAILABILITY]: baseMetricValueScores[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 = (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,
...temporalMetricValueScores,
...environmentalMetricValueScores
}[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(exports.BaseMetric.CONFIDENTIALITY, metricsMap);
const integrity = getMetricNumericValue(exports.BaseMetric.INTEGRITY, metricsMap);
const availability = getMetricNumericValue(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(exports.EnvironmentalMetric.CONFIDENTIALITY_REQUIREMENT, metricsMap);
const mConfidentiality = getMetricNumericValue(exports.EnvironmentalMetric.MODIFIED_CONFIDENTIALITY, metricsMap);
const rIntegrity = getMetricNumericValue(exports.EnvironmentalMetric.INTEGRITY_REQUIREMENT, metricsMap);
const mIntegrity = getMetricNumericValue(exports.EnvironmentalMetric.MODIFIED_INTEGRITY, metricsMap);
const rAvailability = getMetricNumericValue(exports.EnvironmentalMetric.AVAILABILITY_REQUIREMENT, metricsMap);
const mAvailability = getMetricNumericValue(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.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
// Note : Math.pow is 15 in 3.0 but 13 in 3.1
const calculateModifiedImpact = (metricsMap, miss, versionStr) => metricsMap.get(exports.EnvironmentalMetric.MODIFIED_SCOPE) === 'U'
? 6.42 * miss
: 7.52 * (miss - 0.029) -
3.25 *
Math.pow(miss * (versionStr === '3.0' ? 1 : 0.9731) - 0.02, versionStr === '3.0' ? 15 : 13);
// 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(exports.BaseMetric.ATTACK_VECTOR, metricsMap) *
getMetricNumericValue(exports.BaseMetric.ATTACK_COMPLEXITY, metricsMap) *
getMetricNumericValue(exports.BaseMetric.PRIVILEGES_REQUIRED, metricsMap) *
getMetricNumericValue(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(exports.EnvironmentalMetric.MODIFIED_ATTACK_VECTOR, metricsMap) *
getMetricNumericValue(exports.EnvironmentalMetric.MODIFIED_ATTACK_COMPLEXITY, metricsMap) *
getMetricNumericValue(exports.EnvironmentalMetric.MODIFIED_PRIVILEGES_REQUIRED, metricsMap) *
getMetricNumericValue(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 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 = (metricsMap) => {
[...temporalMetrics].forEach((metric) => {
if (!metricsMap.has(metric)) {
metricsMap.set(metric, 'X');
}
});
return metricsMap;
};
const populateEnvironmentalMetricDefaults = (metricsMap) => {
[...environmentalMetrics].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;
};
// https://www.first.org/cvss/v3.1/specification-document#7-1-Base-Metrics-Equations
// If Impact <= 0 => 0; else
// If Scope is Unchanged => Roundup (Minimum [(Impact + Exploitability), 10])
// If Scope is Changed => Roundup (Minimum [1.08 × (Impact + Exploitability), 10])
const calculateBaseResult = (cvssString) => {
const { metricsMap } = validate(cvssString);
const iss = calculateIss(metricsMap);
const impact = calculateImpact(metricsMap, iss);
const exploitability = calculateExploitability(metricsMap);
const scopeUnchanged = metricsMap.get(exports.BaseMetric.SCOPE) === 'U';
const score = impact <= 0
? 0
: scopeUnchanged
? roundUp(Math.min(impact + exploitability, 10))
: roundUp(Math.min(1.08 * (impact + exploitability), 10));
return {
score,
metricsMap,
impact: impact <= 0 ? 0 : roundUp(impact),
exploitability: impact <= 0 ? 0 : roundUp(exploitability)
};
};
const calculateBaseScore = (cvssString) => {
const { score } = calculateBaseResult(cvssString);
return score;
};
// https://www.first.org/cvss/v3.1/specification-document#7-3-Environmental-Metrics-Equations
// If ModifiedImpact <= 0 => 0; else
// If ModifiedScope is Unchanged => Roundup (Roundup [Minimum ([ModifiedImpact + ModifiedExploitability], 10)] × ExploitCodeMaturity × RemediationLevel × ReportConfidence)
// If ModifiedScope is Changed => Roundup (Roundup [Minimum (1.08 × [ModifiedImpact + ModifiedExploitability], 10)] × ExploitCodeMaturity × RemediationLevel × ReportConfidence)
const calculateEnvironmentalResult = (cvssString) => {
const validationResult = validate(cvssString);
const { versionStr } = validationResult;
let { metricsMap } = validationResult;
metricsMap = populateTemporalMetricDefaults(metricsMap);
metricsMap = populateEnvironmentalMetricDefaults(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 score = impact <= 0
? 0
: scopeUnchanged
? roundUp(roundUp(Math.min(impact + exploitability, 10)) *
getMetricNumericValue(exports.TemporalMetric.EXPLOIT_CODE_MATURITY, metricsMap) *
getMetricNumericValue(exports.TemporalMetric.REMEDIATION_LEVEL, metricsMap) *
getMetricNumericValue(exports.TemporalMetric.REPORT_CONFIDENCE, metricsMap))
: roundUp(roundUp(Math.min(1.08 * (impact + exploitability), 10)) *
getMetricNumericValue(exports.TemporalMetric.EXPLOIT_CODE_MATURITY, metricsMap) *
getMetricNumericValue(exports.TemporalMetric.REMEDIATION_LEVEL, metricsMap) *
getMetricNumericValue(exports.TemporalMetric.REPORT_CONFIDENCE, metricsMap));
return {
score,
metricsMap,
impact: impact <= 0 ? 0 : roundUp(impact),
exploitability: impact <= 0 ? 0 : roundUp(exploitability)
};
};
const calculateEnvironmentalScore = (cvssString) => {
const { score } = calculateEnvironmentalResult(cvssString);
return score;
};
// https://www.first.org/cvss/v3.1/specification-document#7-2-Temporal-Metrics-Equations
// Roundup (BaseScore × ExploitCodeMaturity × RemediationLevel × ReportConfidence)
const calculateTemporalResult = (cvssString) => {
let { metricsMap } = validate(cvssString);
// populate temp metrics if not provided
metricsMap = populateTemporalMetricDefaults(metricsMap);
const { score, impact, exploitability } = calculateBaseResult(cvssString);
const tempScore = roundUp(score *
getMetricNumericValue(exports.TemporalMetric.REPORT_CONFIDENCE, metricsMap) *
getMetricNumericValue(exports.TemporalMetric.EXPLOIT_CODE_MATURITY, metricsMap) *
getMetricNumericValue(exports.TemporalMetric.REMEDIATION_LEVEL, metricsMap));
return {
score: tempScore,
metricsMap,
impact,
exploitability
};
};
const calculateTemporalScore = (cvssString) => {
const { score } = calculateTemporalResult(cvssString);
return score;
};
exports.baseMetricValues = baseMetricValues;
exports.baseMetrics = baseMetrics;
exports.calculateBaseResult = calculateBaseResult;
exports.calculateBaseScore = calculateBaseScore;
exports.calculateEnvironmentalResult = calculateEnvironmentalResult;
exports.calculateEnvironmentalScore = calculateEnvironmentalScore;
exports.calculateExploitability = calculateExploitability;
exports.calculateImpact = calculateImpact;
exports.calculateIss = calculateIss;
exports.calculateMiss = calculateMiss;
exports.calculateModifiedExploitability = calculateModifiedExploitability;
exports.calculateModifiedImpact = calculateModifiedImpact;
exports.calculateTemporalResult = calculateTemporalResult;
exports.calculateTemporalScore = calculateTemporalScore;
exports.environmentalMetricValues = environmentalMetricValues;
exports.environmentalMetrics = environmentalMetrics;
exports.humanizeBaseMetric = humanizeBaseMetric;
exports.humanizeBaseMetricValue = humanizeBaseMetricValue;
exports.humanizeScore = humanizeScore;
exports.modifiedMetricsMap = modifiedMetricsMap;
exports.parseMetrics = parseMetrics;
exports.parseMetricsAsMap = parseMetricsAsMap;
exports.parseVector = parseVector;
exports.parseVersion = parseVersion;
exports.populateEnvironmentalMetricDefaults = populateEnvironmentalMetricDefaults;
exports.populateTemporalMetricDefaults = populateTemporalMetricDefaults;
exports.temporalMetricValues = temporalMetricValues;
exports.temporalMetrics = temporalMetrics;
exports.validate = validate;
exports.validateVersion = validateVersion;
Object.defineProperty(exports, '__esModule', { value: true });
})));