turingsecure / cvss.js Goto Github PK
View Code? Open in Web Editor NEWA tiny JavaScript library to work with CVSS vectors
License: MIT License
A tiny JavaScript library to work with CVSS vectors
License: MIT License
If the user wants to create his own vector using a UI it would be useful to just parse an object of the specified metrics into a vector string.
So for example if you have a vector object
const obj = { CVSS: "3.0", AV: "N", AC: "H", PR: "L", UI: "R", S: "C", C: "L", I: "L", A: "L", E: "U", RL: "T", RC: "R" }
a function getVectorString(obj)
would return CVSS:3.0/AV:N/AC:H/PR:L/UI:R/S:C/C:L/I:L/A:L/E:U/RL:T/RC:R
. The same function should work for vectors in the format of the getDetailedObject()
function.
One thing to note here is: we're using a function with a string vector as parameter to create our CVSS object. I see two options in handling this:
a) Allow the user to input objects as parameter
b) Remove the parameter from the CVSS function and create a new function, e.g. CVSS().set(VECTOR)
to set the vector.
I'm open for discussions about this topic, because I think we should be thoughtful on how to handle this.
Sometimes it's useful to get an object with a whole lot of information. E.g. for displaying the vector in the following ways:
To save the user effort, we can return a complex object with some more detailed information. An example object could look like this:
{
version: 3.0, // this is going to be implemented with #8
metrics: {
AV: {
name: "Attack Vector",
abbr: "AV",
fullName: "Attack Vector (AV)",
value: "Network",
valueAbbr: "N"
},
AC: {
name: "Attack Complexity",
abbr: "AC",
fullName: "Attack Complexity (AC)",
value: "Low",
valueAbbr: "L"
}
...
}
}
We should provide an action for running eslint automatically when new changes are pushed.
Currently it is only possible to get a qualitative rating for the base score using the getRating() function. However, it is also important to be able to retrieve this rating for the Temporal and Environmental Score. I think we should create a public function (getTemporalRating and getEnvironmentalRating) for both scores
Currently the user has to install the library with a package manager. I think it would be a good idea to build a (minified) version of the lib each time the main
branch gets updated. This way the user can just include a script tag with a CDN's url (e.g. https://unpkg.com/@turingpointde/[email protected]/production.min.js) and use the library.
I do not really know if GitHub Actions can modify commits or add this to a merge commit. But what we would need ideally is:
The cvss.js
file is getting quite big. To implement #26 we should make sure we won't run into problems with different versions.
Since CVSS version 3.0 and 3.1 are very similar in terms of metrics and differ for the most part only in the calculations, all functions for calculating the scores should be in a separate file.
This should increase our ability to run tests more specifically by a lot as well.
We're parsing the vector object the same way in both functions. We can just replace the implementation in getTemporalScore()
with a call of getVectorObject()
The usage section in the readme is getting quite bloated and I think we should provide a little bit more context on some of the functions. In addition to that, the output of the getDetailedVectorObject()
function should be in a spoiler as it is quite large.
To have everything implemented for version 3.1 only the environmental score is missing. The only thing that is different ist the modified impact calculation.
A constant and another exponent must be added to the calculateISC function.
Example (ISC_modified is equal to MISS):
We need a test environment with some initial tests and a GitHub action.
As it is not necessary to define all metrics we need one test to check if the correct environmental score is calculated. There might be a bug over here.
The environmental score of the vector CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:N/E:P/RL:O/IR:M/MAV:A/MPR:N/MI:L
should be 4.9. ref
This vector should be added to the tests to make sure this works. If it does not work, we should look into fixing this.
Once #54 is implemented, base score and temporal score can be calculated for CVSS v. 3.1. It makes little sense to rewrite the functions if only the rounding functions are different. Therefore, depending on the CVSS version, the correct rounding function should be used in the calculations.
Maybe we should find vectors for the tests that contain "rounding errors" in version 3.0 and therefore differ from version 3.1.
When trying to use the library with Vite, I noticed that it cannot be imported without major problems. So first things first: There is no entry point defined in the package.json
file. Vite throws an exception when importing:
[vite] dependency @turingpointde/cvss.js does not have default entry defined in package.json.
According to this you do not have to specify an entry point if the entry point is the index.js
file in the root folder, but we should add it regardless. I tried to create a main-entry locally and the error disappears.
This is not the end of the story though, vite requires native ESM imports/exports instead of CJS require()
and module.exports
.
Uncaught SyntaxError: The requested module '/@modules/@turingpointde/cvss.js/index.js' does not provide an export named 'default'
I'm not sure how we should proceed here. Maybe someone has more experience and can offer a solution. Should we switch from CJS to ESM? Would this cause problems with older node versions? Is there a workaround to support both?
In Version 3.1 of the CVSS the roundUp function has changed because of IEEE 754 floating point arithmetics. This function needs to be implemented.
https://www.first.org/cvss/v3.1/specification-document#Appendix-A---Floating-Point-Rounding
Currently only metrics defined in the vector string are returned in the getVectorObject function. This leads to problems as soon as the environmental score is to be calculated, for example. The function currently iterates over all metrics in the string, but it should instead iterate over all available metrics, add them to the object and take the values from the string.
Here is an example. The current behaviour is the following:
const vector = CVSS("CVSS:3.0/AV:N/AC:H/PR:L/UI:R/S:C/C:L/I:L/A:L/E:U/RL:T/RC:R");
console.log(vector.getVectorObject()); // { CVSS: "3.0", AV: "N", AC: "H", PR: "L", UI: "R", S: "C", C: "L", I: "L", A: "L", E: "U", RL: "T", RC: "R" }
The function should instead return
{ CVSS: "3.0", AV: "N", AC: "H", PR: "L", UI: "R", S: "C", C: "L", I: "L", A: "L", E: "U", RL: "T", RC: "R", CR: "X", IR: "X", AR: "X", MAV: "X", MAC: "X", MPR: "X", MUI: "X", MS: "X" , MC: "X", MI: "X", MA: "X"}
A vector with no environmental metrics specified returns the wrong environmental score.
Example vector:
CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:N/E:X/RL:X/RC:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MPR:X/MUI:X/MS:X/MC:X/MI:X/MA:X
Should be a score of 8.2. It returns NaN instead. After a little bit of investigation the calculateModifiedExploitability
calculation gets a wrong score for the modified privileges required. I'm not exactly sure how to handle the modified numbers when they are not defined.
We should test if vectors meet the standards of the specification. This should prevent the library to throw unexpected errors. For this to work we need a function that tests the following:
For refrence which metrics are required and so on you can take a look here.
It might be an idea to make this function available to the end user to quickly test if a vector is valid.
It seems like the version 1.4.7 has not been published on the npm registry.
Was it done on purpose or it is a mistake ?
When the users passes an object, whose entries are not in the correct order, the parsing of that object to a vector string returns an invalid vector.
Example:
const obj = {
A: "N",
AC: "L",
AV: "N",
C: "L",
CVSS: "3.0",
E: "X",
I: "H",
PR: "N",
RC: "X",
RL: "X",
S: "U",
UI: "N"
};
CVSS(obj) // Error: The vector format is not valid!
The constructed string is:
A:N/AC:L/AV:N/C:L/CVSS:3.0/E:X/I:H/PR:N/RC:X/RL:X/S:U/UI:N
But it should be:
CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:N/E:X/RL:X/RC:X
This happens because we use Object.entries
to iterate over the input object. If we somehow use the definitions from the json file (they are in the correct order) to iterate, it should be in the correct order.
A note on this: The specification only says that the vector must start with "CVSS:VERSION_NUMBER", the rest of the order does not matter. However, I think it is good style to construct the vector as a whole in the recommended order.
We need extensive testing for the getScore()
function. A good place to get vectors and their calculations is: https://www.first.org/cvss/calculator/3.0
Currently, it is only possible to use CVSS 3.0 vectors. In the future, I think it is a good idea to support Version 3.1 of the CVSS. The metrics of version 3.1 and 3.0 are identical, but the calculation is different.
When #8 is implemented, we can dynamically check which version the vector has and run the calculations based on that. When no version is specified we should use version 3.0, because it seems to be the most common version at the moment.
This issue could be split into multiple parts. I'm not exactly sure, yet.
Support for the new Common Vulnerability Scoring System (CVSS) v4
Reference:
https://github.com/RedHatProductSecurity/cvss-v4-calculator
https://www.first.org/cvss/v4.0/specification-document
Sometimes it is useful for the user to get a string without any metrics that are not defined (so value = "X"). We should implement a function getCleanVectorString()
that returns a string without those values.
So instead of
CVSS:3.0/AV:L/AC:L/PR:H/UI:N/S:U/C:N/I:H/A:N/E:P/RL:W/RC:X/CR:X/IR:X/AR:M/MAV:A/MAC:X/MPR:X/MUI:N/MS:X/MC:X/MI:X/MA:X
The function should return
CVSS:3.0/AV:L/AC:L/PR:H/UI:N/S:U/C:N/I:H/A:N/E:P/RL:W/AR:M/MAV:A/MUI:N
mkdir test && cd test
yarn
: yarn add @turingpointde/cvss.js
index.js
filenode index.js
5.5
4.7
Medium - Based on Qualitative Severity Rating Scale
CVSS:3.0/AV:N/AC:H/PR:L/UI:R/S:C/C:L/I:L/A:L/E:U/RL:T/RC:R
{ CVSS: "3.0", AV: "N", AC: "H", PR: "L", UI: "R", S: "C", C: "L", I: "L", A: "L", E: "U", RL: "T", RC: "R" }
5.5
/Users/tantan/workspace/hacktoberfest/test/index.js:6
console.log(vector.getTemporalScore()); // 4.7
^
TypeError: vector.getTemporalScore is not a function
at Object.<anonymous> (/Users/tantan/workspace/hacktoberfest/test/index.js:6:20)
at Module._compile (internal/modules/cjs/loader.js:1158:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1178:10)
at Module.load (internal/modules/cjs/loader.js:1002:32)
at Function.Module._load (internal/modules/cjs/loader.js:901:14)
at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:74:12)
at internal/main/run_main_module.js:18:47
The user should be able to get the vector's temporal score. This is specified here: https://www.first.org/cvss/v3.0/specification-document Section 8.3 Temporal
For this we need a function getEnvironmentalScore()
. The calculation for the function is:
If (Modified Impact Sub score =< 0) 0 else,
If Modified Scope Unchanged Round up(Round up (Minimum [
(M.Impact + M.Exploitability), 10])
× Exploit Code Maturity
× Remediation Level
× Report Confidence)
If Modified Scope Changed Round up(Round up (Minimum [1.08
× (M.Impact + M.Exploitability), 10])
× Exploit Code Maturity
× Remediation Level
× Report Confidence)
And the modified Impact sub score is defined as,
If Modified Scope Unchanged 6.42 × [ISC_Modified]
If Modified Scope Changed 7.52 × [ISC_Modified−0.029] - 3.25 × [ISC_Modified−0.02]^15
Where
ISC_Modified = Minimum[[1−(1−M.I_Conf × CR)×(1−M.I_Integ × IR)×(1−M.I_Avail × AR)],0.915]
The Modified Exploitability sub score is,
8.22 × M.AttackVector × M.AttackComplexity × M.PrivilegeRequired × M.UserInteraction
The metrics are described in section 8.4 of the specification document.
In the future it should be possible to calculate scores based on the vector's CVSS version. The vectors usually begin with CVSS:VERSION_NUMBER
. It should be possible to get the version with a function getVersion()
.
Reference for the versions:
https://www.first.org/cvss/
The user should be able to get the vector's temporal score. This is specified here: https://www.first.org/cvss/v3.0/specification-document Section 8.2 Temporal
For this we need a function getTemporalScore()
. The basic calculation for the function is:
Round up(BaseScore × ExploitCodeMaturity × RemediationLevel × ReportConfidence)
We already got the base score (it's the getScore()
function). The rest of the metrics are described in section 8.4 of the specification document.
We need extensive testing for the getScore()
function. A good place to get vectors and their calculations is: https://www.first.org/cvss/calculator/3.0
Sometimes the user does not need the exact numeric score of a vector, but instead he wants a qualitative rating.
Those ratings are specified in section 5. Qualitative Severity Rating Scale
of the following document: https://www.first.org/cvss/v3.0/specification-document
Basically, we just need a function to map the score to the qualitative rating defined in the following table:
Rating | CVSS Score |
---|---|
None | 0.0 |
Low | 0.1 - 3.9 |
Medium | 4.0 - 6.9 |
High | 7.0 - 8.9 |
Critical | 9.0 - 10.0 |
In some cases the base score calculation seems to be broken. I did not figure out the problem here yet. I suppose it has something to do with (not) rounding the intermediate results or decimals in JavaScript.
Some scores that fail:
CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:C/C:N/I:L/A:N
Expected: 4.0
Received: 4.1
https://www.first.org/cvss/calculator/3.0#CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:C/C:N/I:L/A:N
CVSS:3.0/AV:A/AC:H/PR:N/UI:N/S:U/C:H/I:L/A:H
Expected: 7.1
Received: 7.2
https://www.first.org/cvss/calculator/3.0#CVSS:3.0/AV:A/AC:H/PR:N/UI:N/S:U/C:H/I:L/A:H
CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:N
Expected: 8.2
Received: 8.4
https://www.first.org/cvss/calculator/3.0#CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:N
This calculator lets you print intermediate results which may be useful for debugging purposes: https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator
With #37 the user can install the library via CDN. This should be mentioned in the installation section of the readme.
Example CDN link: https://unpkg.com/@turingpointde/cvss.js@latest/dist/production.min.js
To keep the overview, some of our internal functions can be outsourced to a util file. Only version independent functions should be considered here. Some functions that came into my mind are parseVectorObjectToString
and isVectorValid
.
Currently we split the vector in the getScore() function and create an object with the abbreviations as key and the vector values as value:
https://github.com/turingpointde/cvss.js/blob/main/lib/cvss.js#L16-L22
We should refactor this into a separate function and make it available to the public API.
It is useful to provide this function to the user. In the future it is imaginable that even more information will be generated by this function.
Hello 👋 I noticed that some scores differ from the First calculator.
Example:
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H
X
s)const CVSS = require("@turingpointde/cvss.js");
const vector = CVSS("CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H");
console.log("base", vector.getScore());
console.log("temporal", vector.getTemporalScore());
console.log("environmental", vector.getEnvironmentalScore());
For vectors where the Scope was changed, but the Modified Scope was not defined, the wrong score is returned.
Example Vector:
CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:C/C:L/I:L/A:L/E:X/RL:X/RC:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MPR:X/MUI:X/MS:X/MC:X/MI:X/MA:X
The base score of this vector is 6.5. Because the temporal score and base score were not touched, the environmental score needs to be 6.5 as well, but it is 5.6.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.