Skip to content

Add CVSS4 support #12751

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 25 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
3250e7d
cvss4: model + parsers
valentijnscholten Jul 6, 2025
e638d06
cvss4: UI + rest tests + fixes
valentijnscholten Jul 6, 2025
668275a
add cvssv4 to forms, fix test
valentijnscholten Jul 7, 2025
1aca925
add cvssv4 to forms, fix test
valentijnscholten Jul 7, 2025
93a508c
simplify test_metrics_queries
valentijnscholten Jul 7, 2025
f8585b4
add cvssv4 to forms, fix test
valentijnscholten Jul 7, 2025
6626cc8
update how to write a parser guide
valentijnscholten Jul 7, 2025
517b9e7
fix one more test
valentijnscholten Jul 7, 2025
2f17e7f
cvss4: add links to extnernal calculators
valentijnscholten Jul 7, 2025
f35985b
cvss4: add links to extnernal calculators
valentijnscholten Jul 7, 2025
3e188c1
fix one more test
valentijnscholten Jul 7, 2025
636a170
fix one more test
valentijnscholten Jul 7, 2025
1120ed3
fix one more test
valentijnscholten Jul 7, 2025
3362964
fix and add tests
valentijnscholten Jul 8, 2025
3c6de89
show CVSS vector together in tooltip
valentijnscholten Jul 8, 2025
6bee447
cleanup maxDiff
valentijnscholten Jul 8, 2025
8eb26a9
fix tests
valentijnscholten Jul 8, 2025
56eb50c
update model help_text and verbose_name
valentijnscholten Jul 8, 2025
5fd7f6d
fix tests
valentijnscholten Jul 8, 2025
e3732ef
fix migration
valentijnscholten Jul 8, 2025
f1eb700
fix tests
valentijnscholten Jul 8, 2025
4bd6934
allow toggling of CVSS fields
valentijnscholten Jul 9, 2025
7c2aad3
revert back to overriding the score field always
valentijnscholten Jul 9, 2025
4a16904
fix tests
valentijnscholten Jul 9, 2025
4392f1d
fix tests
valentijnscholten Jul 9, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 34 additions & 25 deletions docs/content/en/open_source/contributing/how-to-write-a-parser.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,43 +166,52 @@ Good example:
finding.cwe = data["mykey"]
```

### Do not parse CVSS by hand (vector, score or severity)
### Parsing of CVSS vectors

Data can have `CVSS` vectors or scores. Don't write your own CVSS score algorithm.
For parser, we rely on module `cvss`. But we also have a helper method to validate the vector and extract the base score and severity from it.
Data can have `CVSS` vectors or scores. Defect Dojo use the `cvss` module provided by RedHat Security.
There's also a helper method to validate the vector and extract the base score and severity from it.

```python
from dojo.utils import parse_cvss_data
cvss_data = parse_cvss_data("CVSS:3.0/S:C/C:H/I:H/A:N/AV:P/AC:H/PR:H/UI:R/E:H/RL:O/RC:R/CR:H/IR:X/AR:X/MAC:H/MPR:X/MUI:X/MC:L/MA:X")
if cvss_data:
finding.cvssv3 = cvss_data.get("vector")
finding.cvssv3_score = cvss_data.get("score")
finding.severity = cvss_data.get("severity") # if your tool does generate severity
from dojo.utils import parse_cvss_data

cvss_vector = <get CVSS3 or CVSS4 vector from the report>
cvss_data = parse_cvss_data(cvss_vector)
if cvss_data:
finding.severity = cvss_data["severity"]
finding.cvssv3 = cvss_data["cvssv3"]
finding.cvssv4 = cvss_data["cvssv4"]
# we don't set any score fields as those will be overwritten by Defect Dojo
```
Not all values have to be used as scan reports usuyall provide their own value for `severity`.
And sometimes also for `cvss_score`. Defect Dojo will not overwrite any `cvss3_score` or `cvss4_score`.
If no score is set, Defect Dojo will use the `cvss` library to calculate the score.
The response also has the detected major version of the CVSS vector in `cvss_data["major_version"]`.

If you need more manual processing, you can parse the `CVSS3` vector directly.

If you need more manual processing, you can parse the `CVSS` vector directly.

Example of use:

```python
import cvss.parser
from cvss import CVSS2, CVSS3

vectors = cvss.parser.parse_cvss_from_text("CVSS:3.0/S:C/C:H/I:H/A:N/AV:P/AC:H/PR:H/UI:R/E:H/RL:O/RC:R/CR:H/IR:X/AR:X/MAC:H/MPR:X/MUI:X/MC:L/MA:X")
if len(vectors) > 0 and type(vectors[0]) is CVSS3:
print(vectors[0].severities()) # this is the 3 severities

cvssv3 = vectors[0].clean_vector()
severity = vectors[0].severities()[0]
vectors[0].compute_base_score()
cvssv3_score = vectors[0].scores()[0]
finding.severity = severity
finding.cvssv3_score = cvssv3_score
import cvss.parser
from cvss import CVSS2, CVSS3, CVSS4

# TEMPORARY: Use Defect Dojo implementation of `parse_cvss_from_text` white waiting for https://github.com/RedHatProductSecurity/cvss/pull/75 to be released
vectors = dojo.utils.parse_cvss_from_text("CVSS:3.0/S:C/C:H/I:H/A:N/AV:P/AC:H/PR:H/UI:R/E:H/RL:O/RC:R/CR:H/IR:X/AR:X/MAC:H/MPR:X/MUI:X/MC:L/MA:X")
if len(vectors) > 0 and type(vectors[0]) is CVSS3:
print(vectors[0].severities()) # this is the 3 severities

cvssv3 = vectors[0].clean_vector()
severity = vectors[0].severities()[0]
vectors[0].compute_base_score()
cvssv3_score = vectors[0].scores()[0]
finding.severity = severity
finding.cvssv3_score = cvssv3_score
```

Bad example (DIY):
Do not do something like this:

```python
```
def get_severity(self, cvss, cvss_version="2.0"):
cvss = float(cvss)
cvss_version = float(cvss_version[:1])
Expand Down
45 changes: 45 additions & 0 deletions dojo/db_migrations/0234_finding_cvssv4_finding_cvssv4_score.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Generated by Django 5.1.8 on 2025-07-08 17:21

import django.core.validators
import dojo.validators
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('dojo', '0233_remove_test_actual_time_remove_test_estimated_time'),
]

operations = [
migrations.AlterField(
model_name='finding',
name='cvssv3',
field=models.TextField(help_text='Common Vulnerability Scoring System version 3 (CVSS3) score associated with this finding.', max_length=117, null=True, validators=[dojo.validators.cvss3_validator], verbose_name='CVSS3 Vector'),
),
migrations.AlterField(
model_name='finding',
name='cvssv3_score',
field=models.FloatField(blank=True, help_text='Numerical CVSSv3 score for the vulnerability. If the vector is given, the score is updated while saving the finding. The value must be between 0-10.', null=True, validators=[django.core.validators.MinValueValidator(0.0), django.core.validators.MaxValueValidator(10.0)], verbose_name='CVSS3 Score'),
),
migrations.AddField(
model_name='finding',
name='cvssv4',
field=models.TextField(help_text='Common Vulnerability Scoring System version 4 (CVSS4) score associated with this finding.', max_length=255, null=True, validators=[dojo.validators.cvss4_validator], verbose_name='CVSS4 vector'),
),
migrations.AddField(
model_name='finding',
name='cvssv4_score',
field=models.FloatField(blank=True, help_text='Numerical CVSSv4 score for the vulnerability. If the vector is given, the score is updated while saving the finding. The value must be between 0-10.', null=True, validators=[django.core.validators.MinValueValidator(0.0), django.core.validators.MaxValueValidator(10.0)], verbose_name='CVSSv4 Score'),
),
migrations.AddField(
model_name='system_settings',
name='enable_cvss3_display',
field=models.BooleanField(blank=False, default=True, help_text='With this setting turned off, CVSS3 fields will be hidden in the user interface.', verbose_name='Enable CVSS3 Display'),
),
migrations.AddField(
model_name='system_settings',
name='enable_cvss4_display',
field=models.BooleanField(blank=False, default=True, help_text='With this setting turned off, CVSS4 fields will be hidden in the user interface.', verbose_name='Enable CVSS4 Display'),
),
]
Loading