Skip to content

Commit d3bd3e5

Browse files
authored
OSV data source (#22)
* OSV source * Added tests * Added tests * Added tests
1 parent bba88d4 commit d3bd3e5

File tree

13 files changed

+357
-15
lines changed

13 files changed

+357
-15
lines changed

README.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Introduction
22

3-
This repo is a vulnerability database and package search for sources such as NVD, GitHub and so on. It uses a built-in file based storage to allow offline access.
3+
This repo is a vulnerability database and package search for sources such as OSV, NVD, GitHub, and NPM. Vulnerability data are downloaded from the sources and stored in a custom file based storage with indexes to allow offline access and quick searches.
44

55
## Installation
66

@@ -14,10 +14,18 @@ This package is ideal as a library for managing vulnerabilities. This is used by
1414

1515
### Cache vulnerability data
1616

17+
Cache from all sources
18+
1719
```bash
1820
vdb --cache
1921
```
2022

23+
Cache from just [OSV](https://osv.dev)
24+
25+
```bash
26+
vdb --cache --only-osv
27+
```
28+
2129
It is possible to customise the cache behaviour by increasing the historic data period to cache by setting the following environment variables.
2230

2331
- NVD_START_YEAR - Default: 2016. Supports upto 2002

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ tabulate
44
msgpack
55
orjson
66
semver
7+
packageurl-python

setup.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,16 @@
55

66
setuptools.setup(
77
name="appthreat-vulnerability-db",
8-
version="1.7.2",
8+
version="2.0.0",
99
author="Team AppThreat",
1010
author_email="[email protected]",
11-
description="AppThreat's vulnerability database and package search library with a built-in file based storage. CVE, GitHub, npm are the primary sources of vulnerabilities.",
11+
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.",
1212
entry_points={"console_scripts": ["vdb=vdb.cli:main"]},
1313
long_description=long_description,
1414
long_description_content_type="text/markdown",
1515
url="https://github.com/appthreat/vulnerability-db",
1616
packages=setuptools.find_packages(),
17-
install_requires=["requests", "appdirs", "tabulate", "msgpack", "orjson", "semver"],
17+
install_requires=["requests", "appdirs", "tabulate", "msgpack", "orjson", "semver", "packageurl-python"],
1818
classifiers=[
1919
"Development Status :: 5 - Production/Stable",
2020
"Intended Audience :: Developers",

test/data/osv_mixed_data.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"affected":[{"database_specific":{"cvss":{"score":7.3,"vectorString":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L"},"cwes":[{"cweId":"CWE-843","description":"The program allocates or initializes a resource such as a pointer, object, or variable using one type, but it later accesses that resource using a type that is incompatible with the original type.","name":"Access of Resource Using Incompatible Type ('Type Confusion')"},{"cweId":"CWE-1321","description":"The software receives input from an upstream component that specifies attributes that are to be initialized or updated in an object, but it does not properly control modifications of attributes of the object prototype.","name":"Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')"}],"ghsa":"https://github.com/advisories/GHSA-4jqc-8m5r-9rpr"},"package":{"ecosystem":"npm","name":"set-value"},"ranges":[{"events":[{"introduced":"0"},{"fixed":"2.0.1"},{"introduced":"3.0.0"},{"fixed":"4.0.1"}],"id":0,"type":"SEMVER"}]},{"database_specific":{"cvss":{"score":7.3,"vectorString":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L"},"cwes":[{"cweId":"CWE-843","description":"The program allocates or initializes a resource such as a pointer, object, or variable using one type, but it later accesses that resource using a type that is incompatible with the original type.","name":"Access of Resource Using Incompatible Type ('Type Confusion')"},{"cweId":"CWE-1321","description":"The software receives input from an upstream component that specifies attributes that are to be initialized or updated in an object, but it does not properly control modifications of attributes of the object prototype.","name":"Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')"}],"ghsa":"https://github.com/advisories/GHSA-4jqc-8m5r-9rpr"},"package":{"ecosystem":"NuGet","name":"set-value-nuget"},"ranges":[{"events":[{"introduced":"0"},{"fixed":"2.0.0"}],"id":0,"type":"ECOSYSTEM"}]}],"aliases":["CVE-2021-23440"],"details":"This affects the package set-value before 4.0.1. A type confusion vulnerability can lead to a bypass of CVE-2019-10747 when the user-provided keys used in the path parameter are arrays.","id":"GHSA-4jqc-8m5r-9rpr","invalid":false,"isFixed":true,"modified":"2021-11-12T22:48:18Z","published":"2021-09-13T20:09:36Z","references":[{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2021-23440"},{"type":"WEB","url":"https://github.com/jonschlinkert/set-value/pull/33"},{"type":"WEB","url":"https://github.com/jonschlinkert/set-value/commit/7cf8073bb06bf0c15e08475f9f952823b4576452"},{"type":"WEB","url":"https://snyk.io/vuln/SNYK-JAVA-ORGWEBJARSNPM-1584212"},{"type":"WEB","url":"https://snyk.io/vuln/SNYK-JS-SETVALUE-1540541"},{"type":"WEB","url":"https://www.huntr.dev/bounties/2eae1159-01de-4f82-a177-7478a408c4a2/"},{"type":"ADVISORY","url":"https://github.com/advisories/GHSA-4jqc-8m5r-9rpr"}],"source":"https://storage.googleapis.com/ghsa-osv/GHSA-4jqc-8m5r-9rpr.json","source_link":"https://storage.googleapis.com/ghsa-osv/GHSA-4jqc-8m5r-9rpr.json","summary":"Prototype Pollution in set-value"}

test/data/osv_mvn_data.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"affected":[{"database_specific":{"cvss":{"score":7.0,"vectorString":"CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H"},"cwes":[{"cweId":"CWE-470","description":"The application uses external input with reflection to select which classes or code to use, but it does not sufficiently prevent the input from selecting improper classes or code.","name":"Use of Externally-Controlled Input to Select Classes or Code ('Unsafe Reflection')"}],"ghsa":"https://github.com/advisories/GHSA-xxgp-pcfc-3vgc"},"package":{"ecosystem":"Maven","name":"org.hibernate:hibernate-validator"},"ranges":[{"events":[{"introduced":"5.4.0"},{"fixed":"5.4.2"},{"introduced":"5.3.0"},{"fixed":"5.3.6"},{"introduced":"5.2.0"},{"fixed":"5.2.5"}],"id":0,"type":"ECOSYSTEM"}],"versions":["5.2.0.Final","5.2.1.Final","5.2.2.Final","5.2.3.Final","5.2.4.Final","5.3.0.Final","5.3.1.Final","5.3.2.Final","5.3.3.Final","5.3.4.Final","5.3.5.Final","5.4.0.Final","5.4.1.Final"]}],"aliases":["CVE-2017-7536"],"details":"In Hibernate Validator 5.2.x before 5.2.5 final, 5.3.x, and 5.4.x, it was found that when the security manager's reflective permissions, which allows it to access the private members of the class, are granted to Hibernate Validator, a potential privilege escalation can occur. By allowing the calling code to access those private members without the permission an attacker may be able to validate an invalid instance and access the private member value via ConstraintViolation#getInvalidValue().","id":"GHSA-xxgp-pcfc-3vgc","invalid":false,"isFixed":true,"modified":"2021-12-13T23:44:21.151108Z","published":"2020-06-15T19:57:48Z","references":[{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2017-7536"},{"type":"WEB","url":"https://bugzilla.redhat.com/show_bug.cgi?id=1465573"},{"type":"WEB","url":"https://lists.apache.org/thread.html/9317fd092b257a0815434b116a8af8daea6e920b6673f4fd5583d5fe@%3Ccommits.druid.apache.org%3E"},{"type":"WEB","url":"http://www.securityfocus.com/bid/101048"},{"type":"WEB","url":"http://www.securitytracker.com/id/1039744"},{"type":"WEB","url":"https://github.com/hibernate/hibernate-validator/commit/0778a5c98b817771a645c6f4ba0b28dd8b5437b"},{"type":"WEB","url":"https://github.com/hibernate/hibernate-validator/commit/0886e89900d343ea20fde5137c9a3086e6da9ac"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2017:2808"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2017:2809"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2017:2810"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2017:2811"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2017:3141"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2017:3454"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2017:3455"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2017:3456"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2017:3458"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2018:2740"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2018:2741"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2018:2742"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2018:2743"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2018:2927"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2018:3817"},{"type":"ADVISORY","url":"https://github.com/advisories/GHSA-xxgp-pcfc-3vgc"}],"source":"https://storage.googleapis.com/ghsa-osv/GHSA-xxgp-pcfc-3vgc.json","source_link":"https://storage.googleapis.com/ghsa-osv/GHSA-xxgp-pcfc-3vgc.json","summary":"Privilege Escalation in Hibernate Validator"}

test/data/osv_rust_data.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"id":"RUSTSEC-2020-0014","summary":"Various memory safety issues","details":"Several memory safety issues have been uncovered in an audit of\nrusqlite.\n\nSee https://github.com/rusqlite/rusqlite/releases/tag/0.23.0 for a complete list.","aliases":["CVE-2020-35866","CVE-2020-35867","CVE-2020-35868","CVE-2020-35869","CVE-2020-35870","CVE-2020-35871","CVE-2020-35872","CVE-2020-35873"],"modified":"2021-01-04T17:02:59Z","published":"2020-04-23T12:00:00Z","references":[{"type":"PACKAGE","url":"https://crates.io/crates/rusqlite"},{"type":"ADVISORY","url":"https://rustsec.org/advisories/RUSTSEC-2020-0014.html"},{"type":"WEB","url":"https://github.com/rusqlite/rusqlite/releases/tag/0.23.0"}],"affected":[{"package":{"name":"rusqlite","ecosystem":"crates.io","purl":"pkg:cargo/rusqlite"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0.0.0-0"},{"fixed":"0.23.0"}]}],"ecosystem_specific":{"affects":{"arch":[],"os":[],"functions":["rusqlite::Connection::get_aux","rusqlite::Connection::set_aux","rusqlite::session::Session::attach","rusqlite::session::Session::diff","rusqlite::trace::log","rusqlite::vtab::create_module"]}},"database_specific":{"categories":[],"informational":null,"source":"https://github.com/rustsec/advisory-db/blob/osv/crates/RUSTSEC-2020-0014.json","cvss":null}}]}

test/test_source.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
from vdb.lib.gha import GitHubSource
77
from vdb.lib.nvd import NvdSource
8+
from vdb.lib.osv import OSVSource
89

910

1011
@pytest.fixture
@@ -25,6 +26,33 @@ def test_cve_wconfig_json():
2526
return json.loads(fp.read())
2627

2728

29+
@pytest.fixture
30+
def test_osv_rust_json():
31+
test_cve_data = os.path.join(
32+
os.path.dirname(os.path.realpath(__file__)), "data", "osv_rust_data.json"
33+
)
34+
with open(test_cve_data, "r") as fp:
35+
return json.loads(fp.read())
36+
37+
38+
@pytest.fixture
39+
def test_osv_mvn_json():
40+
test_cve_data = os.path.join(
41+
os.path.dirname(os.path.realpath(__file__)), "data", "osv_mvn_data.json"
42+
)
43+
with open(test_cve_data, "r") as fp:
44+
return json.loads(fp.read())
45+
46+
47+
@pytest.fixture
48+
def test_osv_mixed_json():
49+
test_cve_data = os.path.join(
50+
os.path.dirname(os.path.realpath(__file__)), "data", "osv_mixed_data.json"
51+
)
52+
with open(test_cve_data, "r") as fp:
53+
return json.loads(fp.read())
54+
55+
2856
def test_convert(test_cve_json):
2957
nvdlatest = NvdSource()
3058
data = nvdlatest.convert(test_cve_json)
@@ -102,3 +130,24 @@ def test_gha_version_ranges():
102130
assert version_list == ("1.1.0", "", "", "")
103131
version_list = source.get_version_range("> 11.0, < 24.1.1")
104132
assert version_list == ("", "", "11.0", "24.1.1")
133+
134+
135+
@pytest.mark.skip(reason="This downloads and tests with live data")
136+
def test_osv_download_all():
137+
osvlatest = OSVSource()
138+
data = osvlatest.download_all()
139+
assert len(data) > 1000
140+
141+
142+
def test_osv_convert(test_osv_rust_json, test_osv_mvn_json, test_osv_mixed_json):
143+
osvlatest = OSVSource()
144+
cve_data = osvlatest.convert(test_osv_rust_json)
145+
assert cve_data
146+
147+
cve_data = osvlatest.convert(test_osv_mvn_json)
148+
assert cve_data
149+
assert len(cve_data) == 3
150+
151+
cve_data = osvlatest.convert(test_osv_mixed_json)
152+
assert cve_data
153+
assert len(cve_data) == 3

vdb/cli.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from vdb.lib.gha import GitHubSource
1414
from vdb.lib.npm import NpmSource
1515
from vdb.lib.nvd import NvdSource
16+
from vdb.lib.osv import OSVSource
1617

1718
logging.basicConfig(
1819
level=logging.INFO, format="%(levelname)s [%(asctime)s] %(message)s"
@@ -52,6 +53,13 @@ def build_args():
5253
dest="cache",
5354
help="Cache vulnerability information in platform specific user_data_dir",
5455
)
56+
parser.add_argument(
57+
"--only-osv",
58+
action="store_true",
59+
default=False,
60+
dest="only_osv",
61+
help="Use only OSV as the source.",
62+
)
5563
parser.add_argument(
5664
"--sync",
5765
action="store_true",
@@ -146,11 +154,12 @@ def main():
146154
os.rmdir(config.data_dir)
147155
except Exception:
148156
pass
149-
else:
150-
LOG.info("Vulnerability database loaded from {}".format(config.vdb_bin_file))
151-
152157
if args.cache:
153-
for s in [GitHubSource(), NvdSource()]:
158+
if args.only_osv:
159+
sources = [OSVSource()]
160+
else:
161+
sources = [OSVSource(), GitHubSource(), NvdSource()]
162+
for s in sources:
154163
LOG.info("Refreshing {}".format(s.__class__.__name__))
155164
s.refresh()
156165
elif args.sync:
@@ -174,6 +183,7 @@ def main():
174183
results = dbLib.list_all_occurrence(db)
175184
print_results(results)
176185
elif args.search:
186+
LOG.info("Vulnerability database loaded from {}".format(config.vdb_bin_file))
177187
db = dbLib.get()
178188
search_list = re.split(r"[,|;]", args.search)
179189
for pkg_info in search_list:

vdb/lib/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@
2323
"npm": ["javascript", "node.js", "nodejs"],
2424
"nuget": [".net_framework", "csharp", ".net_core"],
2525
"pypi": ["python"],
26-
"rubygems": ["ruby"],
26+
"rubygems": ["ruby", "gem"],
2727
"golang": ["go"],
28-
"crates": ["rust"],
28+
"crates": ["rust", "crates.io", "cargo"],
2929
}
3030

3131
# CPE Regex

vdb/lib/config.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@
55
# NVD CVE json feed url
66
nvd_url = "https://nvd.nist.gov/feeds/json/cve/1.1/nvdcve-1.1-%(year)s.json.gz"
77

8-
# NVD start year. 2016 is quicker. 2002 is quite detailed but slow
9-
nvd_start_year = os.getenv("NVD_START_YEAR", 2016)
8+
# NVD start year. 2018 is quicker. 2002 is quite detailed but slow
9+
nvd_start_year = os.getenv("NVD_START_YEAR", 2018)
1010

1111
# GitHub advisory feed url
1212
gha_url = os.getenv("GITHUB_GRAPHQL_URL", "https://api.github.com/graphql")
1313

1414
# No of pages to download from GitHub during a full refresh
15-
gha_pages_count = os.getenv("GITHUB_PAGE_COUNT", 10)
16-
npm_pages_count = os.getenv("NPM_PAGE_COUNT", 10)
15+
gha_pages_count = os.getenv("GITHUB_PAGE_COUNT", 2)
16+
npm_pages_count = os.getenv("NPM_PAGE_COUNT", 2)
1717

1818
# DB file dir
1919
data_dir = os.getenv("VDB_HOME", user_data_dir("vdb"))
@@ -37,6 +37,15 @@
3737
{"cve":{"data_type":"CVE","data_format":"MITRE","data_version":"4.0","CVE_data_meta":{"ID":"%(cve_id)s","ASSIGNER":"%(assigner)s"},"problemtype":{"problemtype_data":[{"description":[{"lang":"en","value":"%(cwe_id)s"}]}]},"references":{"reference_data": %(references)s},"description":{"description_data":[{"lang":"en","value":"%(description)s"}]}},"configurations":{"CVE_data_version":"4.0","nodes":[{"operator":"OR","cpe_match":[{"vulnerable":true,"cpe23Uri":"cpe:2.3:a:%(vendor)s:%(product)s:%(version)s:*:*:*:*:*:*:*","versionStartExcluding":"%(version_start_excluding)s","versionEndExcluding":"%(version_end_excluding)s","versionStartIncluding":"%(version_start_including)s","versionEndIncluding":"%(version_end_including)s"}, {"vulnerable":false,"cpe23Uri":"cpe:2.3:a:%(vendor)s:%(product)s:%(fix_version_start_including)s:*:*:*:*:*:*:*","versionStartExcluding":"%(fix_version_start_excluding)s","versionEndExcluding":"%(fix_version_end_excluding)s","versionStartIncluding":"%(fix_version_start_including)s","versionEndIncluding":"%(fix_version_end_including)s"}]}]},"impact":{"baseMetricV3":{"cvssV3":{"version":"3.1","vectorString":"%(vectorString)s","attackVector":"NETWORK","attackComplexity":"%(attackComplexity)s","privilegesRequired":"NONE","userInteraction":"REQUIRED","scope":"UNCHANGED","confidentialityImpact":"%(severity)s","integrityImpact":"%(severity)s","availabilityImpact":"%(severity)s","baseScore":%(score).1f,"baseSeverity":"%(severity)s"},"exploitabilityScore":%(exploitabilityScore).1f,"impactScore":%(score).1f},"baseMetricV2":{"cvssV2":{"version":"2.0","vectorString":"AV:N/AC:M/Au:N/C:P/I:P/A:P","accessVector":"NETWORK","accessComplexity":"MEDIUM","authentication":"NONE","confidentialityImpact":"PARTIAL","integrityImpact":"PARTIAL","availabilityImpact":"PARTIAL","baseScore":%(score).1f},"severity":"%(severity)s","exploitabilityScore":%(exploitabilityScore).1f,"impactScore":%(score).1f,"acInsufInfo":false,"obtainAllPrivilege":false,"obtainUserPrivilege":false,"obtainOtherPrivilege":false,"userInteractionRequired":false}},"publishedDate":"%(publishedDate)s","lastModifiedDate":"%(lastModifiedDate)s"}
3838
"""
3939

40+
osv_url_dict = {
41+
"javascript": "https://osv-vulnerabilities.storage.googleapis.com/npm/all.zip",
42+
"python": "https://osv-vulnerabilities.storage.googleapis.com/PyPI/all.zip",
43+
"go": "https://osv-vulnerabilities.storage.googleapis.com/Go/all.zip",
44+
"java": "https://osv-vulnerabilities.storage.googleapis.com/Maven/all.zip",
45+
"rust": "https://osv-vulnerabilities.storage.googleapis.com/crates.io/all.zip",
46+
"csharp": "https://osv-vulnerabilities.storage.googleapis.com/NuGet/all.zip",
47+
"ruby": "https://osv-vulnerabilities.storage.googleapis.com/RubyGems/all.zip",
48+
}
4049
# CVE types to exclude - hardware
4150
nvd_exclude_types = ["h"]
4251
if os.getenv("NVD_EXCLUDE_TYPES") is not None:

0 commit comments

Comments
 (0)