Skip to content

Commit

Permalink
Upgrade to cve 5.1 schema. Support for cvssv4 in osv
Browse files Browse the repository at this point in the history
Signed-off-by: Prabhu Subramanian <[email protected]>
  • Loading branch information
prabhu committed Nov 10, 2024
1 parent 976855a commit 9e20bd1
Show file tree
Hide file tree
Showing 7 changed files with 209 additions and 6 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "appthreat-vulnerability-db"
version = "5.7.8"
version = "5.8.0"
description = "AppThreat's vulnerability database and package search library with a built-in file based storage. OSV, CVE, GitHub, npm are the primary sources of vulnerabilities."
authors = [
{name = "Team AppThreat", email = "[email protected]"},
Expand Down
156 changes: 156 additions & 0 deletions test/data/osv-maven-cvss4.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
{
"schema_version": "1.4.0",
"id": "GHSA-gr3c-q7xf-47vh",
"modified": "2024-11-08T18:49:15Z",
"published": "2024-11-08T18:49:15Z",
"aliases": [
"CVE-2024-52007"
],
"summary": "XXE vulnerability in XSLT parsing in `org.hl7.fhir.core`",
"details": "### Summary\nXSLT parsing performed by various components are vulnerable to XML external entity injections. A processed XML file with a malicious DTD tag ( <!DOCTYPE foo [<!ENTITY example SYSTEM \"/etc/passwd\"> ]> could produce XML containing data from the host system. This impacts use cases where org.hl7.fhir.core is being used to within a host where external clients can submit XML.\n\n### Details\nThis is related to https://github.com/hapifhir/org.hl7.fhir.core/security/advisories/GHSA-6cr6-ph3p-f5rf, in which its fix ( https://github.com/hapifhir/org.hl7.fhir.core/issues/1571, https://github.com/hapifhir/org.hl7.fhir.core/pull/1717) was incomplete. \n\n### References\nhttps://cwe.mitre.org/data/definitions/611.html\nhttps://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#jaxp-documentbuilderfactory-saxparserfactory-and-dom4j",
"severity": [
{
"type": "CVSS_V3",
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N"
},
{
"type": "CVSS_V4",
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:N/SC:H/SI:N/SA:N"
}
],
"affected": [
{
"package": {
"ecosystem": "Maven",
"name": "ca.uhn.hapi.fhir:org.hl7.fhir.dstu3"
},
"ranges": [
{
"type": "ECOSYSTEM",
"events": [
{
"introduced": "0"
},
{
"fixed": "6.4.0"
}
]
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "ca.uhn.hapi.fhir:org.hl7.fhir.r4"
},
"ranges": [
{
"type": "ECOSYSTEM",
"events": [
{
"introduced": "0"
},
{
"fixed": "6.4.0"
}
]
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "ca.uhn.hapi.fhir:org.hl7.fhir.r4b"
},
"ranges": [
{
"type": "ECOSYSTEM",
"events": [
{
"introduced": "0"
},
{
"fixed": "6.4.0"
}
]
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "ca.uhn.hapi.fhir:org.hl7.fhir.r5"
},
"ranges": [
{
"type": "ECOSYSTEM",
"events": [
{
"introduced": "0"
},
{
"fixed": "6.4.0"
}
]
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "ca.uhn.hapi.fhir:org.hl7.fhir.utilities"
},
"ranges": [
{
"type": "ECOSYSTEM",
"events": [
{
"introduced": "0"
},
{
"fixed": "6.4.0"
}
]
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "ca.uhn.hapi.fhir:org.hl7.fhir.dstu2016may"
},
"ranges": [
{
"type": "ECOSYSTEM",
"events": [
{
"introduced": "0"
},
{
"fixed": "6.4.0"
}
]
}
]
}
],
"references": [
{
"type": "WEB",
"url": "https://github.com/hapifhir/org.hl7.fhir.core/security/advisories/GHSA-gr3c-q7xf-47vh"
},
{
"type": "PACKAGE",
"url": "https://github.com/hapifhir/org.hl7.fhir.core"
}
],
"database_specific": {
"cwe_ids": [
"CWE-611"
],
"severity": "HIGH",
"github_reviewed": true,
"github_reviewed_at": "2024-11-08T18:49:15Z",
"nvd_published_at": null
}
}
16 changes: 16 additions & 0 deletions test/test_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,15 @@ def test_osv_pypi3_json():
return json.loads(fp.read())


@pytest.fixture
def test_osv_maven_cvss4_json():
test_cve_data = os.path.join(
os.path.dirname(os.path.realpath(__file__)), "data", "osv-maven-cvss4.json"
)
with open(test_cve_data, mode="r", encoding="utf-8") as fp:
return json.loads(fp.read())


@pytest.fixture
def test_osv_mal_json():
test_cve_data = os.path.join(
Expand Down Expand Up @@ -497,6 +506,13 @@ def test_osv_convert(
assert not cve_data


def test_osv_convert4(test_osv_maven_cvss4_json):
osvlatest = OSVSource()
# maven cvss4 version
cve_data = osvlatest.convert(test_osv_maven_cvss4_json)
assert len(cve_data) == 6


def test_osv_mal_convert(test_osv_mal_json, test_osv_mal2_json):
osvlatest = OSVSource()
cve_data = osvlatest.convert(test_osv_mal2_json)
Expand Down
2 changes: 1 addition & 1 deletion vdb/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ def print_results(results):
package_issue.fixed_location,
vuln_occ_dict.get("problem_type"),
vuln_occ_dict.get("severity"),
vuln_occ_dict.get("cvss_score"),
vuln_occ_dict.get("cvss4_vector_string") + "\n" + vuln_occ_dict.get("cvss_score") if vuln_occ_dict.get("cvss4_vector_string") else vuln_occ_dict.get("cvss_score"),
vuln_occ_dict.get("short_description"),
]
)
Expand Down
8 changes: 8 additions & 0 deletions vdb/lib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ def convert_time(time_str):

class Vulnerability(object):
"""Vulnerability"""
cvss4_vector_string: str = None

def __init__(
self,
Expand All @@ -175,6 +176,7 @@ def __init__(
cvss_v3,
source_update_time,
source_orig_time,
cvss4_vector_string=None
):
self.id = vid
self.problem_type = problem_type
Expand All @@ -186,6 +188,7 @@ def __init__(
self.cvss_v3 = cvss_v3
self.source_update_time: datetime = convert_time(source_update_time)
self.source_orig_time: datetime = convert_time(source_orig_time)
self.cvss4_vector_string = cvss4_vector_string

def __repr__(self):
return json.dumps(
Expand All @@ -204,6 +207,7 @@ def __repr__(self):
"source_orig_time": convert_time(self.source_orig_time).strftime(
"%Y-%m-%dT%H:%M:%S"
),
"cvss4_vector_string": self.cvss4_vector_string
}
)

Expand Down Expand Up @@ -550,6 +554,7 @@ class VulnerabilityOccurrence:
source_update_time: datetime
source_orig_time: datetime
matched_by: str
cvss4_vector_string: str = None

def __init__(
self,
Expand All @@ -567,6 +572,7 @@ def __init__(
source_update_time,
source_orig_time,
matched_by,
cvss4_vector_string=None
):
self.id = id
self.problem_type = problem_type
Expand All @@ -582,6 +588,7 @@ def __init__(
self.source_update_time = source_update_time
self.source_orig_time = source_orig_time
self.matched_by = matched_by
self.cvss4_vector_string = cvss4_vector_string

def to_dict(self):
"""Convert the object to dict"""
Expand Down Expand Up @@ -622,6 +629,7 @@ def to_dict(self):
"source_update_time": source_update_time,
"source_orig_time": source_orig_time,
"matched_by": self.matched_by,
"cvss4_vector_string": self.cvss4_vector_string
}


Expand Down
17 changes: 15 additions & 2 deletions vdb/lib/osv.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
compress_str,
convert_score_severity,
get_cvss3_from_vector,
get_cvss4_from_vector,
get_default_cve_data,
parse_purl,
)
Expand Down Expand Up @@ -141,6 +142,7 @@ def to_vuln(self, cve_data):
break
assigner = "OSV"
vectorString = ""
cvss4_vector_string = ""
if cve_id.startswith("GHSA"):
assigner = "github_m"
elif cve_id.startswith("CVE"):
Expand All @@ -154,6 +156,8 @@ def to_vuln(self, cve_data):
for sv in severity_list:
if sv["type"] == "CVSS_V3":
vectorString = sv["score"]
elif sv["type"] == "CVSS_V4":
cvss4_vector_string = sv["score"]
# Issue 58
cve_database_specific = cve_data.get("database_specific")
cve_ecosystem_specific = cve_data.get("ecosystem_specific")
Expand Down Expand Up @@ -187,7 +191,13 @@ def to_vuln(self, cve_data):
if cvss.get("score"):
score = cvss.get("score")
severity = convert_score_severity(score)
if vectorString:
if cvss4_vector_string:
cvss4_obj = get_cvss4_from_vector(cvss4_vector_string)
score = cvss4_obj.get("baseScore")
severity = cvss4_obj.get("baseSeverity")
exploitabilityScore = score
attackComplexity = cvss4_obj.get("attackComplexity")
elif vectorString:
cvss3_obj = get_cvss3_from_vector(vectorString)
score = cvss3_obj.get("baseScore")
severity = cvss3_obj.get("baseSeverity")
Expand All @@ -200,7 +210,6 @@ def to_vuln(self, cve_data):
# Override the score for malware
if cve_id.startswith("MAL"):
score = 10.0
user_interaction = "NONE"
# Set the default vector string only if unavailable
if not vectorString and dvectorString:
vectorString = dvectorString
Expand Down Expand Up @@ -304,6 +313,8 @@ def to_vuln(self, cve_data):
try:
vuln = NvdSource.convert_vuln(json_lib.loads(tdata))
vuln.description = compress_str(description)
if cvss4_vector_string:
vuln.cvss4_vector_string = cvss4_vector_string
ret_data.append(vuln)
except Exception:
pass
Expand Down Expand Up @@ -382,6 +393,8 @@ def to_vuln(self, cve_data):
try:
vuln = NvdSource.convert_vuln(json_lib.loads(tdata))
vuln.description = compress_str(description)
if cvss4_vector_string:
vuln.cvss4_vector_string = cvss4_vector_string
ret_data.append(vuln)
except Exception:
pass
Expand Down
14 changes: 12 additions & 2 deletions vdb/lib/utils.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import codecs
import importlib
import os
import re
import string
from datetime import date, datetime
from enum import Enum

from cvss import CVSS3
from cvss import CVSS3, CVSS4
from packageurl import PackageURL
from semver import VersionInfo

Expand Down Expand Up @@ -872,6 +871,16 @@ def get_cvss3_from_vector(vector):
return c.as_json()


def get_cvss4_from_vector(vector):
"""
Return CVE metadata for the given vector
:param vector: Vector
:return: CVSS4 parsed and converted to json
"""
c = CVSS4(vector)
return c.as_json()


def convert_to_occurrence(datas):
"""Method to parse raw search result and convert to Vulnerability occurence
Expand Down Expand Up @@ -934,6 +943,7 @@ def convert_to_occurrence(datas):
source_update_time=vobj.get("source_update_time"),
source_orig_time=vobj.get("source_orig_time"),
matched_by=match,
cvss4_vector_string=vobj.get("cvss4_vector_string")
)
id_list.append(unique_key)
data_list.append(occ)
Expand Down

0 comments on commit 9e20bd1

Please sign in to comment.