Skip to content

Commit 1dcdd7b

Browse files
committed
Add a test for golang
Fix test by adding cwe to expected files Resolve merge conflict Signed-off-by: ziadhany <ziadhany2016@gmail.com>
1 parent cf7745d commit 1dcdd7b

22 files changed

Lines changed: 1665 additions & 29 deletions

vulnerabilities/importers/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from vulnerabilities.importers import fireeye
1919
from vulnerabilities.importers import gentoo
2020
from vulnerabilities.importers import github
21+
from vulnerabilities.importers import github_osv
2122
from vulnerabilities.importers import gitlab
2223
from vulnerabilities.importers import istio
2324
from vulnerabilities.importers import mozilla
@@ -67,6 +68,7 @@
6768
fireeye.FireyeImporter,
6869
apache_kafka.ApacheKafkaImporter,
6970
oss_fuzz.OSSFuzzImporter,
71+
github_osv.GithubOSVImporter,
7072
]
7173

7274
IMPORTERS_REGISTRY = {x.qualified_name: x for x in IMPORTERS_REGISTRY}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#
2+
# Copyright (c) nexB Inc. and others. All rights reserved.
3+
# VulnerableCode is a trademark of nexB Inc.
4+
# SPDX-License-Identifier: Apache-2.0
5+
# See http://www.apache.org/licenses/LICENSE-2.0 for the license text.
6+
# See https://github.com/nexB/vulnerablecode for support or download.
7+
# See https://aboutcode.org for more information about nexB OSS projects.
8+
#
9+
import json
10+
import logging
11+
from io import BytesIO
12+
from pathlib import Path
13+
from typing import Iterable
14+
from zipfile import ZipFile
15+
16+
import requests
17+
18+
from vulnerabilities.importer import AdvisoryData
19+
from vulnerabilities.importer import Importer
20+
from vulnerabilities.importers.osv import parse_advisory_data
21+
22+
logger = logging.getLogger(__name__)
23+
24+
25+
class GithubOSVImporter(Importer):
26+
license_url = "https://github.com/github/advisory-database/blob/main/LICENSE.md"
27+
spdx_license_expression = "CC-BY-4.0"
28+
repo_url = "git+https://github.com/github/advisory-database/"
29+
30+
def advisory_data(self) -> Iterable[AdvisoryData]:
31+
supported_ecosystems = [
32+
"pypi",
33+
"npm",
34+
"maven",
35+
"golang",
36+
"composer",
37+
"hex",
38+
"gem",
39+
"nuget",
40+
"cargo",
41+
]
42+
try:
43+
self.clone(repo_url=self.repo_url)
44+
path = Path(self.vcs_response.dest_dir)
45+
# filter out non-github-reviewed files and only keep the files end-with .json
46+
advisory_dirs = path / "advisories/github-reviewed"
47+
for file in advisory_dirs.glob("**/*.json"):
48+
with open(file) as f:
49+
raw_data = json.load(f)
50+
yield parse_advisory_data(raw_data, supported_ecosystems)
51+
finally:
52+
if self.vcs_response:
53+
self.vcs_response.delete()

vulnerabilities/importers/osv.py

Lines changed: 54 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@
1313
from typing import Optional
1414

1515
import dateparser
16+
from cvss.exceptions import CVSS3MalformedError
1617
from packageurl import PackageURL
1718
from univers.version_range import RANGE_CLASS_BY_SCHEMES
1819
from univers.versions import InvalidVersion
19-
from univers.versions import PypiVersion
2020
from univers.versions import SemverVersion
2121
from univers.versions import Version
2222

@@ -31,8 +31,20 @@
3131

3232
logger = logging.getLogger(__name__)
3333

34+
PURL_TYPE_BY_OSV_SCHEME = {
35+
"npm": "npm",
36+
"pypi": "pypi",
37+
"maven": "maven",
38+
"nuget": "nuget",
39+
"packagist": "composer",
40+
"rubygems": "gem",
41+
"go": "golang",
42+
"hex": "hex",
43+
"cargo": "cargo",
44+
}
3445

35-
def parse_advisory_data(raw_data: dict, supported_ecosystem) -> Optional[AdvisoryData]:
46+
47+
def parse_advisory_data(raw_data: dict, supported_ecosystems: List) -> Optional[AdvisoryData]:
3648
"""
3749
Return an AdvisoryData build from a ``raw_data`` mapping of OSV advisory and
3850
a ``supported_ecosystem`` string.
@@ -54,18 +66,24 @@ def parse_advisory_data(raw_data: dict, supported_ecosystem) -> Optional[Advisor
5466

5567
for affected_pkg in raw_data.get("affected") or []:
5668
purl = get_affected_purl(affected_pkg=affected_pkg, raw_id=raw_id)
57-
if purl.type != supported_ecosystem:
69+
if purl.type in PURL_TYPE_BY_OSV_SCHEME:
70+
new_type = PURL_TYPE_BY_OSV_SCHEME[purl.type]
71+
purl = purl._replace(type=new_type)
72+
73+
if purl.type not in supported_ecosystems:
5874
logger.error(f"Unsupported package type: {purl!r} in OSV: {raw_id!r}")
5975
continue
6076

6177
affected_version_range = get_affected_version_range(
6278
affected_pkg=affected_pkg,
6379
raw_id=raw_id,
64-
supported_ecosystem=supported_ecosystem,
80+
supported_ecosystem=purl.type,
6581
)
6682

6783
for fixed_range in affected_pkg.get("ranges") or []:
68-
fixed_version = get_fixed_versions(fixed_range=fixed_range, raw_id=raw_id)
84+
fixed_version = get_fixed_versions(
85+
fixed_range=fixed_range, raw_id=raw_id, supported_ecosystem=purl.type
86+
)
6987

7088
for version in fixed_version:
7189
affected_packages.append(
@@ -118,14 +136,21 @@ def get_severities(raw_data) -> Iterable[VulnerabilitySeverity]:
118136
"""
119137
Yield VulnerabilitySeverity extracted from a mapping of OSV ``raw_data``
120138
"""
121-
for severity in raw_data.get("severity") or []:
122-
if severity.get("type") == "CVSS_V3":
123-
vector = severity["score"]
124-
system = SCORING_SYSTEMS["cvssv3.1"]
125-
score = system.compute(vector)
126-
yield VulnerabilitySeverity(system=system, value=score, scoring_elements=vector)
127-
else:
128-
logger.error(f"Unsupported severity type: {severity!r} for OSV id: {raw_data['id']!r}")
139+
try:
140+
for severity in raw_data.get("severity") or []:
141+
if severity.get("type") == "CVSS_V3":
142+
vector = severity["score"]
143+
valid_vector = vector[::-1] if vector[-1] == "/" else vector
144+
system = SCORING_SYSTEMS["cvssv3.1"]
145+
score = system.compute(valid_vector)
146+
yield VulnerabilitySeverity(system=system, value=score, scoring_elements=vector)
147+
148+
else:
149+
logger.error(
150+
f"Unsupported severity type: {severity!r} for OSV id: {raw_data['id']!r}"
151+
)
152+
except CVSS3MalformedError as e:
153+
logger.error(f"Invalid severity {e}")
129154

130155
ecosystem_specific = raw_data.get("ecosystem_specific") or {}
131156
severity = ecosystem_specific.get("severity")
@@ -204,18 +229,17 @@ def get_affected_version_range(affected_pkg, raw_id, supported_ecosystem):
204229
)
205230

206231

207-
def get_fixed_versions(fixed_range, raw_id) -> List[Version]:
232+
def get_fixed_versions(fixed_range, raw_id, supported_ecosystem) -> List[Version]:
208233
"""
209234
Return a list of unique fixed univers Versions given a ``fixed_range``
210235
univers VersionRange and a ``raw_id``.
211-
212236
For example::
213-
214-
>>> get_fixed_versions(fixed_range={}, raw_id="GHSA-j3f7-7rmc-6wqj")
237+
>>> get_fixed_versions(fixed_range={}, raw_id="GHSA-j3f7-7rmc-6wqj", supported_ecosystem="pypi",)
215238
[]
216239
>>> get_fixed_versions(
217-
... fixed_range={"type": "ECOSYSTEM", "events": [{"fixed": "1.7.0"}]},
218-
... raw_id="GHSA-j3f7-7rmc-6wqj"
240+
... fixed_range={"type": "ECOSYSTEM", "events": [{"fixed": "1.7.0"}], },
241+
... raw_id="GHSA-j3f7-7rmc-6wqj",
242+
... supported_ecosystem="pypi",
219243
... )
220244
[PypiVersion(string='1.7.0')]
221245
"""
@@ -226,21 +250,27 @@ def get_fixed_versions(fixed_range, raw_id) -> List[Version]:
226250

227251
fixed_range_type = fixed_range["type"]
228252

229-
for version in extract_fixed_versions(fixed_range):
253+
version_range_class = RANGE_CLASS_BY_SCHEMES.get(supported_ecosystem)
254+
version_class = version_range_class.version_class if version_range_class else None
230255

231-
# FIXME: ECOSYSTEM does not imply PyPI!!!!
256+
for version in extract_fixed_versions(fixed_range):
232257
if fixed_range_type == "ECOSYSTEM":
233258
try:
234-
fixed_versions.append(PypiVersion(version))
259+
if not version_class:
260+
raise InvalidVersion(
261+
f"Unsupported version for ecosystem: {supported_ecosystem}"
262+
)
263+
fixed_versions.append(version_class(version))
235264
except InvalidVersion:
236-
logger.error(f"Invalid PypiVersion: {version!r} for OSV id: {raw_id!r}")
265+
logger.error(
266+
f"Invalid version class: {version_class} - {version!r} for OSV id: {raw_id!r}"
267+
)
237268

238269
elif fixed_range_type == "SEMVER":
239270
try:
240271
fixed_versions.append(SemverVersion(version))
241272
except InvalidVersion:
242273
logger.error(f"Invalid SemverVersion: {version!r} for OSV id: {raw_id!r}")
243-
244274
else:
245275
logger.error(f"Unsupported fixed version type: {version!r} for OSV id: {raw_id!r}")
246276

vulnerabilities/importers/pypa.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def advisory_data(self) -> Iterable[AdvisoryData]:
3131
self.clone(repo_url=self.repo_url)
3232
path = Path(self.vcs_response.dest_dir)
3333
for raw_data in fork_and_get_files(path=path):
34-
yield parse_advisory_data(raw_data=raw_data, supported_ecosystem="pypi")
34+
yield parse_advisory_data(raw_data=raw_data, supported_ecosystems=["pypi"])
3535
finally:
3636
if self.vcs_response:
3737
self.vcs_response.delete()

vulnerabilities/importers/pysec.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,4 @@ def advisory_data(self) -> Iterable[AdvisoryData]:
3838
continue
3939
with zip_file.open(file_name) as f:
4040
vul_info = json.load(f)
41-
yield parse_advisory_data(raw_data=vul_info, supported_ecosystem="pypi")
41+
yield parse_advisory_data(raw_data=vul_info, supported_ecosystems=["pypi"])

vulnerabilities/improvers/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
valid_versions.DebianOvalImprover,
2626
valid_versions.UbuntuOvalImprover,
2727
valid_versions.OSSFuzzImprover,
28+
valid_versions.GithubOSVImprover,
2829
# vulnerability_status.VulnerabilityStatusImprover,
2930
]
3031

vulnerabilities/improvers/valid_versions.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
from vulnerabilities.importers.debian_oval import DebianOvalImporter
3232
from vulnerabilities.importers.elixir_security import ElixirSecurityImporter
3333
from vulnerabilities.importers.github import GitHubAPIImporter
34+
from vulnerabilities.importers.github_osv import GithubOSVImporter
3435
from vulnerabilities.importers.gitlab import GitLabAPIImporter
3536
from vulnerabilities.importers.istio import IstioImporter
3637
from vulnerabilities.importers.nginx import NginxImporter
@@ -483,3 +484,8 @@ class UbuntuOvalImprover(ValidVersionImprover):
483484
class OSSFuzzImprover(ValidVersionImprover):
484485
importer = OSSFuzzImporter
485486
ignorable_versions = []
487+
488+
489+
class GithubOSVImprover(ValidVersionImprover):
490+
importer = GithubOSVImporter
491+
ignorable_versions = []
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
{
2+
"aliases": [
3+
"CVE-2015-8315",
4+
"GHSA-3fx5-fwvr-xrjg"
5+
],
6+
"summary": "Regular Expression Denial of Service in ms\nVersions of `ms` prior to 0.7.1 are affected by a regular expression denial of service vulnerability when extremely long version strings are parsed.\n\n## Proof of Concept\n```javascript\nvar ms = require('ms');\nvar genstr = function (len, chr) {\n var result = \"\";\n for (i=0; i<=len; i++) {\n result = result + chr;\n }\n\n return result;\n}\n\nms(genstr(process.argv[2], \"5\") + \" minutea\");\n\n```\n\n### Results\nShowing increase in execution time based on the input string.\n```\n$ time node ms.js 10000\n\nreal\t0m0.758s\nuser\t0m0.724s\nsys\t0m0.031s\n\n$ time node ms.js 20000\n\nreal\t0m2.580s\nuser\t0m2.494s\nsys\t0m0.047s\n\n$ time node ms.js 30000\n\nreal\t0m5.747s\nuser\t0m5.483s\nsys\t0m0.080s\n\n$ time node ms.js 80000\n\nreal\t0m41.022s\nuser\t0m38.894s\nsys\t0m0.529s\n```",
7+
"affected_packages": [
8+
{
9+
"package": {
10+
"type": "npm",
11+
"namespace": null,
12+
"name": "ms",
13+
"version": null,
14+
"qualifiers": null,
15+
"subpath": null
16+
},
17+
"affected_version_range": null,
18+
"fixed_version": "0.7.1"
19+
}
20+
],
21+
"references": [
22+
{
23+
"reference_id": "",
24+
"url": "https://nvd.nist.gov/vuln/detail/CVE-2015-8315",
25+
"severities": [
26+
{
27+
"system": "cvssv3.1",
28+
"value": "7.5",
29+
"scoring_elements": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"
30+
},
31+
{
32+
"system": "generic_textual",
33+
"value": "HIGH",
34+
"scoring_elements": ""
35+
}
36+
]
37+
},
38+
{
39+
"reference_id": "",
40+
"url": "https://github.com/unshiftio/millisecond/",
41+
"severities": [
42+
{
43+
"system": "cvssv3.1",
44+
"value": "7.5",
45+
"scoring_elements": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"
46+
},
47+
{
48+
"system": "generic_textual",
49+
"value": "HIGH",
50+
"scoring_elements": ""
51+
}
52+
]
53+
},
54+
{
55+
"reference_id": "",
56+
"url": "https://support.f5.com/csp/article/K46337613?utm_source=f5support&amp;utm_medium=RSS",
57+
"severities": [
58+
{
59+
"system": "cvssv3.1",
60+
"value": "7.5",
61+
"scoring_elements": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"
62+
},
63+
{
64+
"system": "generic_textual",
65+
"value": "HIGH",
66+
"scoring_elements": ""
67+
}
68+
]
69+
},
70+
{
71+
"reference_id": "",
72+
"url": "https://www.npmjs.com/advisories/46",
73+
"severities": [
74+
{
75+
"system": "cvssv3.1",
76+
"value": "7.5",
77+
"scoring_elements": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"
78+
},
79+
{
80+
"system": "generic_textual",
81+
"value": "HIGH",
82+
"scoring_elements": ""
83+
}
84+
]
85+
},
86+
{
87+
"reference_id": "",
88+
"url": "http://www.openwall.com/lists/oss-security/2016/04/20/11",
89+
"severities": [
90+
{
91+
"system": "cvssv3.1",
92+
"value": "7.5",
93+
"scoring_elements": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"
94+
},
95+
{
96+
"system": "generic_textual",
97+
"value": "HIGH",
98+
"scoring_elements": ""
99+
}
100+
]
101+
},
102+
{
103+
"reference_id": "",
104+
"url": "http://www.securityfocus.com/bid/96389",
105+
"severities": [
106+
{
107+
"system": "cvssv3.1",
108+
"value": "7.5",
109+
"scoring_elements": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"
110+
},
111+
{
112+
"system": "generic_textual",
113+
"value": "HIGH",
114+
"scoring_elements": ""
115+
}
116+
]
117+
}
118+
],
119+
"date_published": "2017-10-24T18:33:36+00:00",
120+
"weaknesses": [400]
121+
}

0 commit comments

Comments
 (0)