From d8cdaf472b753e40925ca4679c118b0fd1e8aa63 Mon Sep 17 00:00:00 2001 From: Ayan Sinha Mahapatra Date: Fri, 10 Nov 2023 16:20:30 +0530 Subject: [PATCH 1/5] Add RTD build configuration from skeleton (#1337) --- .gitignore | 20 ++++++++++++++++++-- .readthedocs.yml | 19 ++++++++++++++++--- apache-2.0.LICENSE | 25 +++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 4c8414d28..63fb1b5b0 100644 --- a/.gitignore +++ b/.gitignore @@ -46,8 +46,14 @@ coverage.xml *.log local_settings.py -# Sphinx documentation -docs/_build/ +# Sphinx +docs/_build +docs/bin +docs/build +docs/include +docs/Lib +doc/pyvenv.cfg +pyvenv.cfg # PyBuilder target/ @@ -103,3 +109,13 @@ Pipfile *.bak /.cache/ /tmp/ + +# pyenv +/.python-version +/man/ +/.pytest_cache/ +lib64 +tcl + +# Ignore Jupyter Notebook related temp files +.ipynb_checkpoints/ diff --git a/.readthedocs.yml b/.readthedocs.yml index d5dde4cfd..683f3a82a 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -5,12 +5,25 @@ # Required version: 2 +# Build in latest ubuntu/python +build: + os: ubuntu-22.04 + tools: + python: "3.11" + +# Build PDF & ePub +formats: + - epub + - pdf + # Where the Sphinx conf.py file is located sphinx: configuration: docs/source/conf.py -# Setting the doc build requirements +# Setting the python version and doc build requirements python: - version: "3.7" install: - - requirements: docs/requirements.txt + - method: pip + path: . + extra_requirements: + - dev diff --git a/apache-2.0.LICENSE b/apache-2.0.LICENSE index d9a10c0d8..261eeb9e9 100644 --- a/apache-2.0.LICENSE +++ b/apache-2.0.LICENSE @@ -174,3 +174,28 @@ of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. From 8f8190e20edc73340de50201f02945a07aff0ffa Mon Sep 17 00:00:00 2001 From: ziad hany Date: Sun, 12 Nov 2023 21:45:28 +0200 Subject: [PATCH 2/5] Import data from OSS-Fuzz (#897) Add OSSFuzzImprover to IMPROVERS_REGISTRY Fix oss-fuzz test ( add weakness in expected test file ) Add oss-fuzz tests Import data from oss_fuzz using osv format Resolve merge conflicts Signed-off-by: ziadhany --- vulnerabilities/importers/__init__.py | 2 + vulnerabilities/importers/oss_fuzz.py | 37 +++++++++++++++++ vulnerabilities/improvers/__init__.py | 1 + vulnerabilities/improvers/valid_versions.py | 6 +++ .../test_data/oss_fuzz/oss-fuzz-data1.yaml | 41 +++++++++++++++++++ .../oss-fuzz-data1.yaml-expected.json | 20 +++++++++ .../test_data/oss_fuzz/oss-fuzz-data2.yaml | 33 +++++++++++++++ .../oss-fuzz-data2.yaml-expected.json | 20 +++++++++ vulnerabilities/tests/test_oss_fuzz.py | 36 ++++++++++++++++ 9 files changed, 196 insertions(+) create mode 100644 vulnerabilities/importers/oss_fuzz.py create mode 100644 vulnerabilities/tests/test_data/oss_fuzz/oss-fuzz-data1.yaml create mode 100644 vulnerabilities/tests/test_data/oss_fuzz/oss-fuzz-data1.yaml-expected.json create mode 100644 vulnerabilities/tests/test_data/oss_fuzz/oss-fuzz-data2.yaml create mode 100644 vulnerabilities/tests/test_data/oss_fuzz/oss-fuzz-data2.yaml-expected.json create mode 100644 vulnerabilities/tests/test_oss_fuzz.py diff --git a/vulnerabilities/importers/__init__.py b/vulnerabilities/importers/__init__.py index 80809be62..add6967f8 100644 --- a/vulnerabilities/importers/__init__.py +++ b/vulnerabilities/importers/__init__.py @@ -25,6 +25,7 @@ from vulnerabilities.importers import npm from vulnerabilities.importers import nvd from vulnerabilities.importers import openssl +from vulnerabilities.importers import oss_fuzz from vulnerabilities.importers import postgresql from vulnerabilities.importers import project_kb_msr2019 from vulnerabilities.importers import pypa @@ -65,6 +66,7 @@ ubuntu_usn.UbuntuUSNImporter, fireeye.FireyeImporter, apache_kafka.ApacheKafkaImporter, + oss_fuzz.OSSFuzzImporter, ] IMPORTERS_REGISTRY = {x.qualified_name: x for x in IMPORTERS_REGISTRY} diff --git a/vulnerabilities/importers/oss_fuzz.py b/vulnerabilities/importers/oss_fuzz.py new file mode 100644 index 000000000..6e4d3fef4 --- /dev/null +++ b/vulnerabilities/importers/oss_fuzz.py @@ -0,0 +1,37 @@ +# +# Copyright (c) nexB Inc. and others. All rights reserved. +# VulnerableCode is a trademark of nexB Inc. +# SPDX-License-Identifier: Apache-2.0 +# See http://www.apache.org/licenses/LICENSE-2.0 for the license text. +# See https://github.com/nexB/vulnerablecode for support or download. +# See https://aboutcode.org for more information about nexB OSS projects. +# +import logging +from pathlib import Path +from typing import Iterable + +import saneyaml + +from vulnerabilities.importer import AdvisoryData +from vulnerabilities.importer import Importer +from vulnerabilities.importers.osv import parse_advisory_data + +logger = logging.getLogger(__name__) + + +class OSSFuzzImporter(Importer): + license_url = "https://github.com/google/oss-fuzz-vulns/blob/main/LICENSE" + spdx_license_expression = "CC-BY-4.0" + url = "git+https://github.com/google/oss-fuzz-vulns" + + def advisory_data(self) -> Iterable[AdvisoryData]: + try: + self.clone(repo_url=self.url) + path = Path(self.vcs_response.dest_dir) / "vulns" + for file in path.glob("**/*.yaml"): + with open(file) as f: + yaml_data = saneyaml.load(f.read()) + yield parse_advisory_data(yaml_data, supported_ecosystem="oss-fuzz") + finally: + if self.vcs_response: + self.vcs_response.delete() diff --git a/vulnerabilities/improvers/__init__.py b/vulnerabilities/improvers/__init__.py index efbf9d43b..b49bb931d 100644 --- a/vulnerabilities/improvers/__init__.py +++ b/vulnerabilities/improvers/__init__.py @@ -22,6 +22,7 @@ valid_versions.IstioImprover, valid_versions.DebianOvalImprover, valid_versions.UbuntuOvalImprover, + valid_versions.OSSFuzzImprover, ] IMPROVERS_REGISTRY = {x.qualified_name: x for x in IMPROVERS_REGISTRY} diff --git a/vulnerabilities/improvers/valid_versions.py b/vulnerabilities/improvers/valid_versions.py index 5b1796339..61f62d5a7 100644 --- a/vulnerabilities/improvers/valid_versions.py +++ b/vulnerabilities/improvers/valid_versions.py @@ -35,6 +35,7 @@ from vulnerabilities.importers.istio import IstioImporter from vulnerabilities.importers.nginx import NginxImporter from vulnerabilities.importers.npm import NpmImporter +from vulnerabilities.importers.oss_fuzz import OSSFuzzImporter from vulnerabilities.importers.ubuntu import UbuntuImporter from vulnerabilities.improver import MAX_CONFIDENCE from vulnerabilities.improver import Improver @@ -477,3 +478,8 @@ class DebianOvalImprover(ValidVersionImprover): class UbuntuOvalImprover(ValidVersionImprover): importer = UbuntuImporter ignorable_versions = [] + + +class OSSFuzzImprover(ValidVersionImprover): + importer = OSSFuzzImporter + ignorable_versions = [] diff --git a/vulnerabilities/tests/test_data/oss_fuzz/oss-fuzz-data1.yaml b/vulnerabilities/tests/test_data/oss_fuzz/oss-fuzz-data1.yaml new file mode 100644 index 000000000..dbe1a8a08 --- /dev/null +++ b/vulnerabilities/tests/test_data/oss_fuzz/oss-fuzz-data1.yaml @@ -0,0 +1,41 @@ +id: OSV-2021-933 +summary: Heap-buffer-overflow in print_mac +details: | + OSS-Fuzz report: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=35887 + + ``` + Crash type: Heap-buffer-overflow WRITE 4 + Crash state: + print_mac + log_packet + dhcp_reply + ``` +modified: '2022-04-13T03:04:31.143462Z' +published: '2021-07-08T00:01:26.369555Z' +references: +- type: REPORT + url: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=35887 +affected: +- package: + name: dnsmasq + ecosystem: OSS-Fuzz + ranges: + - type: GIT + repo: git://thekelleys.org.uk/dnsmasq.git + events: + - introduced: 96f6444958c29a670f4254722d787f328153605c + - fixed: d242cbffa4f20c9f7472f79b3a9e47008b6fe77c + versions: + - v2.86 + - v2.86rc1 + - v2.86rc2 + - v2.86rc3 + - v2.86test5 + - v2.86test6 + - v2.86test7 + - v2.87test1 + - v2.87test2 + - v2.87test3 + - v2.87test4 + ecosystem_specific: + severity: HIGH diff --git a/vulnerabilities/tests/test_data/oss_fuzz/oss-fuzz-data1.yaml-expected.json b/vulnerabilities/tests/test_data/oss_fuzz/oss-fuzz-data1.yaml-expected.json new file mode 100644 index 000000000..4b7914971 --- /dev/null +++ b/vulnerabilities/tests/test_data/oss_fuzz/oss-fuzz-data1.yaml-expected.json @@ -0,0 +1,20 @@ +{ + "aliases": [ + "OSV-2021-933" + ], + "summary": "Heap-buffer-overflow in print_mac\nOSS-Fuzz report: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=35887\n\n```\nCrash type: Heap-buffer-overflow WRITE 4\nCrash state:\nprint_mac\nlog_packet\ndhcp_reply\n```", + "affected_packages": [ + + ], + "references": [ + { + "reference_id": "", + "url": "https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=35887", + "severities": [ + + ] + } + ], + "date_published": "2021-07-08T00:01:26.369555+00:00", + "weaknesses": [] +} \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/oss_fuzz/oss-fuzz-data2.yaml b/vulnerabilities/tests/test_data/oss_fuzz/oss-fuzz-data2.yaml new file mode 100644 index 000000000..cff7c1fec --- /dev/null +++ b/vulnerabilities/tests/test_data/oss_fuzz/oss-fuzz-data2.yaml @@ -0,0 +1,33 @@ +id: OSV-2022-145 +summary: Heap-buffer-overflow in print_mac +details: | + OSS-Fuzz report: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=44581 + + ``` + Crash type: Heap-buffer-overflow WRITE 4 + Crash state: + print_mac + log_packet + dhcp_reply + ``` +modified: '2022-04-13T03:04:31.179893Z' +published: '2022-02-13T00:01:27.883603Z' +references: +- type: REPORT + url: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=44581 +affected: +- package: + name: dnsmasq + ecosystem: OSS-Fuzz + purl: pkg:generic/dnsmasq + ranges: + - type: GIT + repo: git://thekelleys.org.uk/dnsmasq.git + events: + - introduced: e426c2d3bc182d790f83039b77a09d55230ca71f + - fixed: 03345ecefeb0d82e3c3a4c28f27c3554f0611b39 + versions: + - v2.87test8 + ecosystem_specific: + severity: HIGH +schema_version: 1.2.0 diff --git a/vulnerabilities/tests/test_data/oss_fuzz/oss-fuzz-data2.yaml-expected.json b/vulnerabilities/tests/test_data/oss_fuzz/oss-fuzz-data2.yaml-expected.json new file mode 100644 index 000000000..a197ab4d4 --- /dev/null +++ b/vulnerabilities/tests/test_data/oss_fuzz/oss-fuzz-data2.yaml-expected.json @@ -0,0 +1,20 @@ +{ + "aliases": [ + "OSV-2022-145" + ], + "summary": "Heap-buffer-overflow in print_mac\nOSS-Fuzz report: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=44581\n\n```\nCrash type: Heap-buffer-overflow WRITE 4\nCrash state:\nprint_mac\nlog_packet\ndhcp_reply\n```", + "affected_packages": [ + + ], + "references": [ + { + "reference_id": "", + "url": "https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=44581", + "severities": [ + + ] + } + ], + "date_published": "2022-02-13T00:01:27.883603+00:00", + "weaknesses": [] +} \ No newline at end of file diff --git a/vulnerabilities/tests/test_oss_fuzz.py b/vulnerabilities/tests/test_oss_fuzz.py new file mode 100644 index 000000000..c6dcb501e --- /dev/null +++ b/vulnerabilities/tests/test_oss_fuzz.py @@ -0,0 +1,36 @@ +# +# Copyright (c) nexB Inc. and others. All rights reserved. +# VulnerableCode is a trademark of nexB Inc. +# SPDX-License-Identifier: Apache-2.0 +# See http://www.apache.org/licenses/LICENSE-2.0 for the license text. +# See https://github.com/nexB/vulnerablecode for support or download. +# See https://aboutcode.org for more information about nexB OSS projects. +# +import os +from unittest import TestCase + +import saneyaml + +from vulnerabilities.importers.osv import parse_advisory_data +from vulnerabilities.tests import util_tests + +BASE_DIR = os.path.dirname(os.path.abspath(__file__)) +TEST_DATA = os.path.join(BASE_DIR, "test_data/oss_fuzz") + + +class TestOSSFuzzImporter(TestCase): + def test_to_advisories1(self): + with open(os.path.join(TEST_DATA, "oss-fuzz-data1.yaml")) as f: + mock_response = saneyaml.load(f) + expected_file = os.path.join(TEST_DATA, "oss-fuzz-data1.yaml-expected.json") + imported_data = parse_advisory_data(mock_response, "oss-fuzz") + result = imported_data.to_dict() + util_tests.check_results_against_json(result, expected_file) + + def test_to_advisorie2(self): + with open(os.path.join(TEST_DATA, "oss-fuzz-data2.yaml")) as f: + mock_response = saneyaml.load(f) + expected_file = os.path.join(TEST_DATA, "oss-fuzz-data2.yaml-expected.json") + imported_data = parse_advisory_data(mock_response, "oss-fuzz") + result = imported_data.to_dict() + util_tests.check_results_against_json(result, expected_file) From f1675622218d08810267c79f8df30f4553af1cc6 Mon Sep 17 00:00:00 2001 From: Tushar Goel <34160672+TG1999@users.noreply.github.com> Date: Wed, 15 Nov 2023 13:17:08 +0530 Subject: [PATCH 3/5] Do not create vulnerabilities for empty aliases (#1334) * Do not create vulnerabilities for empty aliases Signed-off-by: Tushar Goel * Add test for process_inferences Signed-off-by: Tushar Goel * Refactor get_or_create_vulnerability_and_aliases function Signed-off-by: Tushar Goel * Copy changes of improver runner in import runner Signed-off-by: Tushar Goel * Add migration to remove vulnerabilities with empty aliases Signed-off-by: Tushar Goel * Add tests for migration Signed-off-by: Tushar Goel * Address review comments Signed-off-by: Tushar Goel --------- Signed-off-by: Tushar Goel --- vulnerabilities/import_runner.py | 128 ++++++++++------- vulnerabilities/improve_runner.py | 133 +++++++++++------- .../0041_remove_vulns_with_empty_aliases.py | 37 +++++ vulnerabilities/models.py | 3 + vulnerabilities/tests/test_data_migrations.py | 26 ++++ vulnerabilities/tests/test_improve_runner.py | 66 ++++++++- 6 files changed, 284 insertions(+), 109 deletions(-) create mode 100644 vulnerabilities/migrations/0041_remove_vulns_with_empty_aliases.py diff --git a/vulnerabilities/import_runner.py b/vulnerabilities/import_runner.py index 91ab75675..047710c2f 100644 --- a/vulnerabilities/import_runner.py +++ b/vulnerabilities/import_runner.py @@ -245,69 +245,97 @@ def create_valid_vulnerability_reference(url, reference_id=None): return reference -def get_or_create_vulnerability_and_aliases(alias_names, vulnerability_id=None, summary=None): +def get_or_create_vulnerability_and_aliases( + aliases: List[str], vulnerability_id=None, summary=None +): """ Get or create vulnerabilitiy and aliases such that all existing and new aliases point to the same vulnerability """ - existing_vulns = set() - alias_names = set(alias_names) - new_alias_names = set() - for alias_name in alias_names: - try: - alias = Alias.objects.get(alias=alias_name) - existing_vulns.add(alias.vulnerability) - except Alias.DoesNotExist: - new_alias_names.add(alias_name) - - # If given set of aliases point to different vulnerabilities in the - # database, request is malformed - # TODO: It is possible that all those vulnerabilities are actually - # the same at data level, figure out a way to merge them - if len(existing_vulns) > 1: - logger.warning( - f"Given aliases {alias_names} already exist and do not point " - f"to a single vulnerability. Cannot improve. Skipped." - ) - return + aliases = set(alias.strip() for alias in aliases if alias and alias.strip()) + new_alias_names, existing_vulns = get_vulns_for_aliases_and_get_new_aliases(aliases) + + # All aliases must point to the same vulnerability + vulnerability = None + if existing_vulns: + if len(existing_vulns) != 1: + vcids = ", ".join(v.vulnerability_id for v in existing_vulns) + logger.error( + f"Cannot create vulnerability. " + f"Aliases {aliases} already exist and point " + f"to multiple vulnerabilities {vcids}." + ) + return + else: + vulnerability = existing_vulns.pop() - existing_alias_vuln = existing_vulns.pop() if existing_vulns else None - - if ( - existing_alias_vuln - and vulnerability_id - and existing_alias_vuln.vulnerability_id != vulnerability_id - ): - logger.warning( - f"Given aliases {alias_names!r} already exist and point to existing" - f"vulnerability {existing_alias_vuln}. Unable to create Vulnerability " - f"with vulnerability_id {vulnerability_id}. Skipped" - ) - return + if vulnerability_id and vulnerability.vulnerability_id != vulnerability_id: + logger.error( + f"Cannot create vulnerability. " + f"Aliases {aliases} already exist and point to a different " + f"vulnerability {vulnerability} than the requested " + f"vulnerability {vulnerability_id}." + ) + return - if existing_alias_vuln: - vulnerability = existing_alias_vuln - elif vulnerability_id: + if vulnerability_id and not vulnerability: try: vulnerability = Vulnerability.objects.get(vulnerability_id=vulnerability_id) except Vulnerability.DoesNotExist: - logger.warning( - f"Given vulnerability_id: {vulnerability_id} does not exist in the database" - ) + logger.error(f"Cannot get requested vulnerability {vulnerability_id}.") return + if vulnerability: + # TODO: We should keep multiple summaries, one for each advisory + # if summary and summary != vulnerability.summary: + # logger.warning( + # f"Inconsistent summary for {vulnerability.vulnerability_id}. " + # f"Existing: {vulnerability.summary!r}, provided: {summary!r}" + # ) + associate_vulnerability_with_aliases(vulnerability=vulnerability, aliases=new_alias_names) else: - vulnerability = Vulnerability(summary=summary) - vulnerability.save() + try: + vulnerability = create_vulnerability_and_add_aliases( + aliases=new_alias_names, summary=summary + ) + except Exception as e: + logger.error( + f"Cannot create vulnerability with summary {summary!r} and {new_alias_names!r} {e!r}.\n{traceback_format_exc()}." + ) + return + + return vulnerability + + +def get_vulns_for_aliases_and_get_new_aliases(aliases): + """ + Return ``new_aliases`` that are not in the database and + ``existing_vulns`` that point to the given ``aliases``. + """ + new_aliases = set(aliases) + existing_vulns = set() + for alias in Alias.objects.filter(alias__in=aliases): + existing_vulns.add(alias.vulnerability) + new_aliases.remove(alias.alias) + return new_aliases, existing_vulns - if summary and summary != vulnerability.summary: - logger.warning( - f"Inconsistent summary for {vulnerability!r}. " - f"Existing: {vulnerability.summary}, provided: {summary}" - ) - for alias_name in new_alias_names: +@transaction.atomic +def create_vulnerability_and_add_aliases(aliases, summary): + """ + Return a new ``vulnerability`` created with ``summary`` + and associate the ``vulnerability`` with ``aliases``. + Raise exception if no alias is associated with the ``vulnerability``. + """ + vulnerability = Vulnerability(summary=summary) + vulnerability.save() + associate_vulnerability_with_aliases(aliases, vulnerability) + if not vulnerability.aliases.count(): + raise Exception(f"Vulnerability {vulnerability.vcid} must have one or more aliases") + return vulnerability + + +def associate_vulnerability_with_aliases(aliases, vulnerability): + for alias_name in aliases: alias = Alias(alias=alias_name, vulnerability=vulnerability) alias.save() logger.info(f"New alias for {vulnerability!r}: {alias_name}") - - return vulnerability diff --git a/vulnerabilities/improve_runner.py b/vulnerabilities/improve_runner.py index da46105d6..37c0b6c35 100644 --- a/vulnerabilities/improve_runner.py +++ b/vulnerabilities/improve_runner.py @@ -10,6 +10,7 @@ import logging from datetime import datetime from datetime import timezone +from traceback import format_exc as traceback_format_exc from typing import List from django.core.exceptions import ValidationError @@ -79,7 +80,7 @@ def process_inferences(inferences: List[Inference], advisory: Advisory, improver for inference in inferences: vulnerability = get_or_create_vulnerability_and_aliases( vulnerability_id=inference.vulnerability_id, - alias_names=inference.aliases, + aliases=inference.aliases, summary=inference.summary, ) @@ -173,69 +174,97 @@ def create_valid_vulnerability_reference(url, reference_id=None): return reference -def get_or_create_vulnerability_and_aliases(alias_names, vulnerability_id=None, summary=None): +def get_or_create_vulnerability_and_aliases( + aliases: List[str], vulnerability_id=None, summary=None +): """ Get or create vulnerabilitiy and aliases such that all existing and new aliases point to the same vulnerability """ - existing_vulns = set() - alias_names = set(alias_names) - new_alias_names = set() - for alias_name in alias_names: - try: - alias = Alias.objects.get(alias=alias_name) - existing_vulns.add(alias.vulnerability) - except Alias.DoesNotExist: - new_alias_names.add(alias_name) - - # If given set of aliases point to different vulnerabilities in the - # database, request is malformed - # TODO: It is possible that all those vulnerabilities are actually - # the same at data level, figure out a way to merge them - if len(existing_vulns) > 1: - logger.warning( - f"Given aliases {alias_names} already exist and do not point " - f"to a single vulnerability. Cannot improve. Skipped." - ) - return - - existing_alias_vuln = existing_vulns.pop() if existing_vulns else None - - if ( - existing_alias_vuln - and vulnerability_id - and existing_alias_vuln.vulnerability_id != vulnerability_id - ): - logger.warning( - f"Given aliases {alias_names!r} already exist and point to existing" - f"vulnerability {existing_alias_vuln}. Unable to create Vulnerability " - f"with vulnerability_id {vulnerability_id}. Skipped" - ) - return + aliases = set(alias.strip() for alias in aliases if alias and alias.strip()) + new_alias_names, existing_vulns = get_vulns_for_aliases_and_get_new_aliases(aliases) + + # All aliases must point to the same vulnerability + vulnerability = None + if existing_vulns: + if len(existing_vulns) != 1: + vcids = ", ".join(v.vulnerability_id for v in existing_vulns) + logger.error( + f"Cannot create vulnerability. " + f"Aliases {aliases} already exist and point " + f"to multiple vulnerabilities {vcids}." + ) + return + else: + vulnerability = existing_vulns.pop() + + if vulnerability_id and vulnerability.vulnerability_id != vulnerability_id: + logger.error( + f"Cannot create vulnerability. " + f"Aliases {aliases} already exist and point to a different " + f"vulnerability {vulnerability} than the requested " + f"vulnerability {vulnerability_id}." + ) + return - if existing_alias_vuln: - vulnerability = existing_alias_vuln - elif vulnerability_id: + if vulnerability_id and not vulnerability: try: vulnerability = Vulnerability.objects.get(vulnerability_id=vulnerability_id) except Vulnerability.DoesNotExist: - logger.warning( - f"Given vulnerability_id: {vulnerability_id} does not exist in the database" - ) + logger.error(f"Cannot get requested vulnerability {vulnerability_id}.") return + if vulnerability: + # TODO: We should keep multiple summaries, one for each advisory + # if summary and summary != vulnerability.summary: + # logger.warning( + # f"Inconsistent summary for {vulnerability.vulnerability_id}. " + # f"Existing: {vulnerability.summary!r}, provided: {summary!r}" + # ) + associate_vulnerability_with_aliases(vulnerability=vulnerability, aliases=new_alias_names) else: - vulnerability = Vulnerability(summary=summary) - vulnerability.save() + try: + vulnerability = create_vulnerability_and_add_aliases( + aliases=new_alias_names, summary=summary + ) + except Exception as e: + logger.error( + f"Cannot create vulnerability with summary {summary!r} and {new_alias_names!r} {e!r}.\n{traceback_format_exc()}." + ) + return - if summary and summary != vulnerability.summary: - logger.warning( - f"Inconsistent summary for {vulnerability!r}. " - f"Existing: {vulnerability.summary}, provided: {summary}" - ) + return vulnerability + + +def get_vulns_for_aliases_and_get_new_aliases(aliases): + """ + Return ``new_aliases`` that are not in the database and + ``existing_vulns`` that point to the given ``aliases``. + """ + new_aliases = set(aliases) + existing_vulns = set() + for alias in Alias.objects.filter(alias__in=aliases): + existing_vulns.add(alias.vulnerability) + new_aliases.remove(alias.alias) + return new_aliases, existing_vulns - for alias_name in new_alias_names: + +@transaction.atomic +def create_vulnerability_and_add_aliases(aliases, summary): + """ + Return a new ``vulnerability`` created with ``summary`` + and associate the ``vulnerability`` with ``aliases``. + Raise exception if no alias is associated with the ``vulnerability``. + """ + vulnerability = Vulnerability(summary=summary) + vulnerability.save() + associate_vulnerability_with_aliases(aliases, vulnerability) + if not vulnerability.aliases.count(): + raise Exception(f"Vulnerability {vulnerability.vcid} must have one or more aliases") + return vulnerability + + +def associate_vulnerability_with_aliases(aliases, vulnerability): + for alias_name in aliases: alias = Alias(alias=alias_name, vulnerability=vulnerability) alias.save() logger.info(f"New alias for {vulnerability!r}: {alias_name}") - - return vulnerability diff --git a/vulnerabilities/migrations/0041_remove_vulns_with_empty_aliases.py b/vulnerabilities/migrations/0041_remove_vulns_with_empty_aliases.py new file mode 100644 index 000000000..d2c44c280 --- /dev/null +++ b/vulnerabilities/migrations/0041_remove_vulns_with_empty_aliases.py @@ -0,0 +1,37 @@ +# +# Copyright (c) nexB Inc. and others. All rights reserved. +# VulnerableCode is a trademark of nexB Inc. +# SPDX-License-Identifier: Apache-2.0 +# See http://www.apache.org/licenses/LICENSE-2.0 for the license text. +# See https://github.com/nexB/vulnerablecode for support or download. +# See https://aboutcode.org for more information about nexB OSS projects. +# + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("vulnerabilities", "0040_remove_advisory_date_improved_advisory_date_imported"), + ] + + def remove_vulns_with_empty_aliases(apps, _): + Vulnerability = apps.get_model("vulnerabilities", "Vulnerability") + Package = apps.get_model("vulnerabilities", "Package") + packages = [] + vulnerabilities = [] + for vuln in Vulnerability.objects.filter(aliases=None).prefetch_related( + "packages" + ): + # Delete packages associated with that vulnerability + for package in vuln.packages.all(): + packages.append(package.id) + vulnerabilities.append(vuln.id) + + Vulnerability.objects.filter(id__in=vulnerabilities).delete() + Package.objects.filter(id__in=packages).delete() + + operations = [ + migrations.RunPython(remove_vulns_with_empty_aliases, reverse_code=migrations.RunPython.noop), + ] diff --git a/vulnerabilities/models.py b/vulnerabilities/models.py index 02259bba8..768661943 100644 --- a/vulnerabilities/models.py +++ b/vulnerabilities/models.py @@ -11,6 +11,7 @@ import json import logging from contextlib import suppress +from typing import Any from cwe2.database import Database from django.contrib.auth import get_user_model @@ -759,6 +760,8 @@ class Alias(models.Model): alias = models.CharField( max_length=50, unique=True, + blank=False, + null=False, help_text="An alias is a unique vulnerability identifier in some database, " "such as CVE-2020-2233", ) diff --git a/vulnerabilities/tests/test_data_migrations.py b/vulnerabilities/tests/test_data_migrations.py index 72796ac0f..76e7b4bf8 100644 --- a/vulnerabilities/tests/test_data_migrations.py +++ b/vulnerabilities/tests/test_data_migrations.py @@ -568,3 +568,29 @@ def test_removal_of_corrupted_advisory(self): # using get_model to avoid circular import Advisory = self.apps.get_model("vulnerabilities", "Advisory") Advisory.objects.all().count() == 0 + + +class RemoveVulnerabilitiesWithEmptyAliases(TestMigrations): + app_name = "vulnerabilities" + migrate_from = "0040_remove_advisory_date_improved_advisory_date_imported" + migrate_to = "0041_remove_vulns_with_empty_aliases" + + def setUpBeforeMigration(self, apps): + # using get_model to avoid circular import + Vulnerability = apps.get_model("vulnerabilities", "Vulnerability") + Alias = apps.get_model("vulnerabilities", "Alias") + + vuln = Vulnerability.objects.create( + summary="Corrupted vuln", + ) + vuln.save() + vuln = Vulnerability.objects.create( + summary="vuln", + ) + vuln.save() + Alias.objects.create(alias="CVE-123", vulnerability=vuln) + + def test_removal_of_corrupted_vulns(self): + # using get_model to avoid circular import + Vulnerability = self.apps.get_model("vulnerabilities", "Vulnerability") + Vulnerability.objects.all().count() == 1 diff --git a/vulnerabilities/tests/test_improve_runner.py b/vulnerabilities/tests/test_improve_runner.py index 9354b4688..632b6dab6 100644 --- a/vulnerabilities/tests/test_improve_runner.py +++ b/vulnerabilities/tests/test_improve_runner.py @@ -16,8 +16,11 @@ from vulnerabilities.importer import Reference from vulnerabilities.improve_runner import create_valid_vulnerability_reference +from vulnerabilities.improve_runner import create_vulnerability_and_add_aliases from vulnerabilities.improve_runner import get_or_create_vulnerability_and_aliases +from vulnerabilities.improve_runner import get_vulns_for_aliases_and_get_new_aliases from vulnerabilities.improve_runner import process_inferences +from vulnerabilities.improver import MAX_CONFIDENCE from vulnerabilities.improver import Improver from vulnerabilities.improver import Inference from vulnerabilities.models import Advisory @@ -61,9 +64,7 @@ def test_create_valid_vulnerability_reference_accepts_long_references(): def test_get_or_create_vulnerability_and_aliases_with_new_vulnerability_and_new_aliases(): alias_names = ["TAYLOR-1337", "SWIFT-1337"] summary = "Melodious vulnerability" - vulnerability = get_or_create_vulnerability_and_aliases( - alias_names=alias_names, summary=summary - ) + vulnerability = get_or_create_vulnerability_and_aliases(aliases=alias_names, summary=summary) assert vulnerability alias_names_in_db = vulnerability.get_aliases.values_list("alias", flat=True) assert Counter(alias_names_in_db) == Counter(alias_names) @@ -82,7 +83,7 @@ def test_get_or_create_vulnerability_and_aliases_with_different_vulnerability_an different_vulnerability = Vulnerability(vulnerability_id="VCID-New") different_vulnerability.save() assert not get_or_create_vulnerability_and_aliases( - alias_names=existing_alias_names, vulnerability_id=different_vulnerability.vulnerability_id + aliases=existing_alias_names, vulnerability_id=different_vulnerability.vulnerability_id ) @@ -93,7 +94,7 @@ def test_get_or_create_vulnerability_and_aliases_with_existing_vulnerability_and existing_alias_names = ["ALIAS-1", "ALIAS-2"] vulnerability = get_or_create_vulnerability_and_aliases( - vulnerability_id="VCID-Existing", alias_names=existing_alias_names + vulnerability_id="VCID-Existing", aliases=existing_alias_names ) assert existing_vulnerability == vulnerability @@ -113,7 +114,7 @@ def test_get_or_create_vulnerability_and_aliases_with_existing_vulnerability_and Alias.objects.bulk_create(existing_aliases) vulnerability = get_or_create_vulnerability_and_aliases( - vulnerability_id="VCID-Existing", alias_names=existing_alias_names + vulnerability_id="VCID-Existing", aliases=existing_alias_names ) assert existing_vulnerability == vulnerability @@ -135,7 +136,7 @@ def test_get_or_create_vulnerability_and_aliases_with_existing_vulnerability_and new_alias_names = ["ALIAS-3", "ALIAS-4"] alias_names = existing_alias_names + new_alias_names vulnerability = get_or_create_vulnerability_and_aliases( - vulnerability_id="VCID-Existing", alias_names=alias_names + vulnerability_id="VCID-Existing", aliases=alias_names ) assert existing_vulnerability == vulnerability @@ -204,3 +205,54 @@ def test_process_inference_idempotency_with_different_improver_names(): process_inferences(INFERENCES, DUMMY_ADVISORY, improver_name="test_improver_two") process_inferences(INFERENCES, DUMMY_ADVISORY, improver_name="test_improver_three") assert all_objects == get_objects_in_all_tables_used_by_process_inferences() + + +@pytest.mark.django_db +def test_get_or_created_vulnerability_and_aliases_with_empty_aliases(): + assert get_or_create_vulnerability_and_aliases(aliases=[], summary="EMPTY ALIASES") == None + + +@pytest.mark.django_db +def test_process_inferences_with_empty_aliases(): + with pytest.raises(AssertionError): + process_inferences( + inferences=[ + Inference( + aliases=[], + vulnerability_id=None, + confidence=MAX_CONFIDENCE, + summary="", + ) + ], + advisory=Advisory.objects.create(summary="", date_collected=timezone.now()), + improver_name="NO_ALIASES_IMPROVER", + ) + + +@pytest.mark.django_db +def test_get_vulns_for_aliases_and_get_new_aliases(): + v = Vulnerability.objects.create(summary="TEST") + Alias.objects.create(alias="CVE-1", vulnerability=v) + new_aliases, existing_vulns = get_vulns_for_aliases_and_get_new_aliases( + aliases=["CVE-1", "CVE-2"] + ) + assert new_aliases == set(["CVE-2"]) + assert existing_vulns == set([v]) + new_aliases, existing_vulns = get_vulns_for_aliases_and_get_new_aliases(aliases=["CVE-3"]) + assert new_aliases == set(["CVE-3"]) + assert existing_vulns == set() + + +@pytest.mark.django_db +def test_create_vulnerability_and_add_aliases(): + vuln = create_vulnerability_and_add_aliases(aliases=["CVE-1", "GHSA-1"], summary="NEW-VULN") + assert vuln is not None + assert vuln.aliases.all().count() == 2 + assert [alias["alias"] for alias in vuln.alias.all().values("alias")] == ["CVE-1", "GHSA-1"] + assert vuln.summary == "NEW-VULN" + + +@pytest.mark.django_db +def test_create_vulnerability_and_add_aliases_with_no_aliases(): + with pytest.raises(Exception): + create_vulnerability_and_add_aliases(aliases=[], summary="NEW-VULN") From dc94005e96bfa44de4c12284d7f09900fbb1bbc9 Mon Sep 17 00:00:00 2001 From: Tushar Goel <34160672+TG1999@users.noreply.github.com> Date: Wed, 15 Nov 2023 14:01:28 +0530 Subject: [PATCH 4/5] Mark advisories status according to NVD advisory (#1232) * Mark advisories as rejected according to NVD advisory Signed-off-by: Tushar Goel * Add improver for marking vulnerabilities as rejected as per NVD Signed-off-by: Tushar Goel * Fix Signed-off-by: Tushar Goel * Fix vulnerability status improver Signed-off-by: Tushar Goel * Fix failing tests Signed-off-by: Tushar Goel * Change status rejected to invalid Signed-off-by: Tushar Goel * fix tests Signed-off-by: Tushar Goel * Address review comments Signed-off-by: Tushar Goel * Fix failing tests Signed-off-by: Tushar Goel --------- Signed-off-by: Tushar Goel --- vulnerabilities/improvers/__init__.py | 2 + .../improvers/vulnerability_status.py | 87 + ...42_advisory_status_vulnerability_status.py | 21 + vulnerabilities/models.py | 28 +- .../templates/vulnerability_details.html | 4 + ...e_tomcat-selected-advisories-expected.json | 1740 ++++++++--------- .../tests/test_data/nvd/nvd-expected.json | 8 +- .../test_data/nvd/nvd-rejected-expected.json | 18 + .../tests/test_data/nvd/rejected_nvd.json | 40 + .../parse-advisory-npm-expected.json | 2 +- .../CVE-2023-35866.json | 71 + vulnerabilities/tests/test_nvd.py | 26 +- .../test_vulnerability_status_improver.py | 65 + vulnerabilities/views.py | 4 +- 14 files changed, 1234 insertions(+), 882 deletions(-) create mode 100644 vulnerabilities/improvers/vulnerability_status.py create mode 100644 vulnerabilities/migrations/0042_advisory_status_vulnerability_status.py create mode 100644 vulnerabilities/tests/test_data/nvd/nvd-rejected-expected.json create mode 100644 vulnerabilities/tests/test_data/nvd/rejected_nvd.json create mode 100644 vulnerabilities/tests/test_data/vulnerability_status_improver/CVE-2023-35866.json create mode 100644 vulnerabilities/tests/test_vulnerability_status_improver.py diff --git a/vulnerabilities/improvers/__init__.py b/vulnerabilities/improvers/__init__.py index b49bb931d..9880bf9ee 100644 --- a/vulnerabilities/improvers/__init__.py +++ b/vulnerabilities/improvers/__init__.py @@ -8,6 +8,7 @@ # from vulnerabilities.improvers import valid_versions +from vulnerabilities.improvers import vulnerability_status IMPROVERS_REGISTRY = [ valid_versions.GitHubBasicImprover, @@ -23,6 +24,7 @@ valid_versions.DebianOvalImprover, valid_versions.UbuntuOvalImprover, valid_versions.OSSFuzzImprover, + vulnerability_status.VulnerabilityStatusImprover, ] IMPROVERS_REGISTRY = {x.qualified_name: x for x in IMPROVERS_REGISTRY} diff --git a/vulnerabilities/improvers/vulnerability_status.py b/vulnerabilities/improvers/vulnerability_status.py new file mode 100644 index 000000000..b6db7d0d2 --- /dev/null +++ b/vulnerabilities/improvers/vulnerability_status.py @@ -0,0 +1,87 @@ +# +# Copyright (c) nexB Inc. and others. All rights reserved. +# VulnerableCode is a trademark of nexB Inc. +# SPDX-License-Identifier: Apache-2.0 +# See http://www.apache.org/licenses/LICENSE-2.0 for the license text. +# See https://github.com/nexB/vulnerablecode for support or download. +# See https://aboutcode.org for more information about nexB OSS projects. +# + + +from typing import Iterable +from urllib.parse import urljoin + +from django.db.models import Q +from django.db.models.query import QuerySet + +from vulnerabilities.importer import AdvisoryData +from vulnerabilities.importers.nvd import NVDImporter +from vulnerabilities.improver import Improver +from vulnerabilities.improver import Inference +from vulnerabilities.models import Advisory +from vulnerabilities.models import Alias +from vulnerabilities.models import Vulnerability +from vulnerabilities.models import VulnerabilityStatusType +from vulnerabilities.utils import fetch_response +from vulnerabilities.utils import get_item + +MITRE_API_URL = "https://cveawg.mitre.org/api/cve/" + + +class VulnerabilityStatusImprover(Improver): + """ + Update vulnerability with NVD statues + """ + + @property + def interesting_advisories(self) -> QuerySet: + return ( + Advisory.objects.filter(Q(created_by=NVDImporter.qualified_name)) + .distinct("aliases") + .paginated() + ) + + def get_inferences(self, advisory_data: AdvisoryData) -> Iterable[Inference]: + """ + This is a work-around until we have new style importer and improver + and this get_inferences function updates the vulnerability status directly + # TODO: Replace this with new style improvers + """ + if not advisory_data: + return [] + aliases = advisory_data.aliases + # NVD Importer only has one alias in it and this a CVE + assert len(aliases) == 1 + cve_id = aliases[0] + if not cve_id.startswith("CVE"): + return [] + + alias = Alias.objects.get(alias=cve_id) + vulnerabilities = Vulnerability.objects.filter(aliases__alias=alias).distinct() + + for vuln in vulnerabilities: + status = get_status_from_api(cve_id=cve_id) + if not status: + status = VulnerabilityStatusType.PUBLISHED + vuln.status = status + vuln.save() + return [] + + +def get_status_from_api(cve_id): + """ + Return the CVE status from the MITRE API + """ + url = urljoin(MITRE_API_URL, cve_id) + try: + response = fetch_response(url=url) + except Exception as e: + return + response = response.json() + cve_state = get_item(response, "cveMetadata", "state") or None + tags = get_item(response, "containers", "cna", "tags") or [] + if "disputed" in tags: + return VulnerabilityStatusType.DISPUTED + if cve_state and cve_state == "REJECTED": + return VulnerabilityStatusType.INVALID + return VulnerabilityStatusType.PUBLISHED diff --git a/vulnerabilities/migrations/0042_advisory_status_vulnerability_status.py b/vulnerabilities/migrations/0042_advisory_status_vulnerability_status.py new file mode 100644 index 000000000..6fbae367e --- /dev/null +++ b/vulnerabilities/migrations/0042_advisory_status_vulnerability_status.py @@ -0,0 +1,21 @@ +# Generated by Django 4.1.7 on 2023-09-29 05:26 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("vulnerabilities", "0041_remove_vulns_with_empty_aliases"), + ] + + operations = [ + migrations.AddField( + model_name="vulnerability", + name="status", + field=models.IntegerField( + choices=[(1, "published"), (2, "disputed"), (3, "invalid")], + default=1, + ), + ), + ] diff --git a/vulnerabilities/models.py b/vulnerabilities/models.py index 768661943..1078a4677 100644 --- a/vulnerabilities/models.py +++ b/vulnerabilities/models.py @@ -33,10 +33,6 @@ from packageurl.contrib.django.models import without_empty_values from rest_framework.authtoken.models import Token -from vulnerabilities.importer import AdvisoryData -from vulnerabilities.importer import AffectedPackage -from vulnerabilities.importer import Reference -from vulnerabilities.improver import MAX_CONFIDENCE from vulnerabilities.severity_systems import SCORING_SYSTEMS from vulnerabilities.utils import build_vcid from vulnerabilities.utils import remove_qualifiers_and_subpath @@ -153,6 +149,14 @@ def with_package_counts(self): ) +class VulnerabilityStatusType(models.IntegerChoices): + """List of vulnerability statuses.""" + + PUBLISHED = 1, "Published" + DISPUTED = 2, "Disputed" + INVALID = 3, "Invalid" + + class Vulnerability(models.Model): """ A software vulnerability with a unique identifier and alternate ``aliases``. @@ -181,6 +185,10 @@ class Vulnerability(models.Model): through="PackageRelatedVulnerability", ) + status = models.IntegerField( + choices=VulnerabilityStatusType.choices, default=VulnerabilityStatusType.PUBLISHED + ) + objects = VulnerabilityQuerySet.as_manager() class Meta: @@ -230,6 +238,11 @@ def get_aliases(self): alias = get_aliases + @property + def get_status_label(self): + label_by_status = {choice[0]: choice[1] for choice in VulnerabilityStatusType.choices} + return label_by_status.get(self.status) or VulnerabilityStatusType.PUBLISHED.label + def get_absolute_url(self): """ Return this Vulnerability details absolute URL. @@ -653,6 +666,7 @@ class PackageRelatedVulnerability(models.Model): "module name responsible for creating this relation. Eg:" "vulnerabilities.importers.nginx.NginxBasicImprover", ) + from vulnerabilities.improver import MAX_CONFIDENCE confidence = models.PositiveIntegerField( default=MAX_CONFIDENCE, @@ -852,7 +866,11 @@ def save(self, *args, **kwargs): self.unique_content_id = checksum.hexdigest() super().save(*args, **kwargs) - def to_advisory_data(self) -> AdvisoryData: + def to_advisory_data(self) -> "AdvisoryData": + from vulnerabilities.importer import AdvisoryData + from vulnerabilities.importer import AffectedPackage + from vulnerabilities.importer import Reference + return AdvisoryData( aliases=self.aliases, summary=self.summary, diff --git a/vulnerabilities/templates/vulnerability_details.html b/vulnerabilities/templates/vulnerability_details.html index 23eb455e8..4d1af2e5c 100644 --- a/vulnerabilities/templates/vulnerability_details.html +++ b/vulnerabilities/templates/vulnerability_details.html @@ -88,6 +88,10 @@ {% endif %} + + Status + {{ status }} + diff --git a/vulnerabilities/tests/test_data/apache_tomcat/parse-apache_tomcat-selected-advisories-expected.json b/vulnerabilities/tests/test_data/apache_tomcat/parse-apache_tomcat-selected-advisories-expected.json index a8da59963..ba023ef4e 100644 --- a/vulnerabilities/tests/test_data/apache_tomcat/parse-apache_tomcat-selected-advisories-expected.json +++ b/vulnerabilities/tests/test_data/apache_tomcat/parse-apache_tomcat-selected-advisories-expected.json @@ -1,871 +1,871 @@ [ - { - "aliases": [ - "CVE-2020-9484" - ], - "summary": "", - "affected_packages": [ - { - "package": { - "type": "apache", - "namespace": null, - "name": "tomcat", - "version": null, - "qualifiers": null, - "subpath": null - }, - "affected_version_range": "vers:apache/>=9.0.0+M1|<=9.0.41|!=9.0.43", - "fixed_version": null - }, - { - "package": { - "type": "maven", - "namespace": "org.apache.tomcat", - "name": "tomcat", - "version": null, - "qualifiers": null, - "subpath": null - }, - "affected_version_range": "vers:maven/>=9.0.0.M1|<=9.0.41|!=9.0.43", - "fixed_version": null - } - ], - "references": [ - { - "reference_id": "CVE-2020-9484", - "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-9484", - "severities": [ - { - "system": "apache_tomcat", - "value": "Low", - "scoring_elements": "" - } - ] - }, - { - "reference_id": "", - "url": "https://github.com/apache/tomcat/commit/4785433a226a20df6acbea49296e1ce7e23de453", - "severities": [] - } - ], - "date_published": null, - "weaknesses": [] - }, - { - "aliases": [ - "CVE-2021-25329" - ], - "summary": "", - "affected_packages": [ - { - "package": { - "type": "apache", - "namespace": null, - "name": "tomcat", - "version": null, - "qualifiers": null, - "subpath": null - }, - "affected_version_range": "vers:apache/>=9.0.0+M1|<=9.0.41|!=9.0.43", - "fixed_version": null - }, - { - "package": { - "type": "maven", - "namespace": "org.apache.tomcat", - "name": "tomcat", - "version": null, - "qualifiers": null, - "subpath": null - }, - "affected_version_range": "vers:maven/>=9.0.0.M1|<=9.0.41|!=9.0.43", - "fixed_version": null - } - ], - "references": [ - { - "reference_id": "CVE-2021-25329", - "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-25329", - "severities": [ - { - "system": "apache_tomcat", - "value": "Low", - "scoring_elements": "" - } - ] - }, - { - "reference_id": "", - "url": "https://github.com/apache/tomcat/commit/4785433a226a20df6acbea49296e1ce7e23de453", - "severities": [] - } - ], - "date_published": null, - "weaknesses": [] - }, - { - "aliases": [ - "CVE-2021-25122" - ], - "summary": "", - "affected_packages": [ - { - "package": { - "type": "apache", - "namespace": null, - "name": "tomcat", - "version": null, - "qualifiers": null, - "subpath": null - }, - "affected_version_range": "vers:apache/>=9.0.0+M1|<=9.0.41|!=9.0.43", - "fixed_version": null - }, - { - "package": { - "type": "maven", - "namespace": "org.apache.tomcat", - "name": "tomcat", - "version": null, - "qualifiers": null, - "subpath": null - }, - "affected_version_range": "vers:maven/>=9.0.0.M1|<=9.0.41|!=9.0.43", - "fixed_version": null - } - ], - "references": [ - { - "reference_id": "CVE-2021-25122", - "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-25122", - "severities": [ - { - "system": "apache_tomcat", - "value": "Important", - "scoring_elements": "" - } - ] - }, - { - "reference_id": "", - "url": "https://github.com/apache/tomcat/commit/d47c20a776e8919eaca8da9390a32bc8bf8210b1", - "severities": [] - } - ], - "date_published": null, - "weaknesses": [] - }, - { - "aliases": [ - "CVE-2020-9484" - ], - "summary": "", - "affected_packages": [ - { - "package": { - "type": "apache", - "namespace": null, - "name": "tomcat", - "version": null, - "qualifiers": null, - "subpath": null - }, - "affected_version_range": "vers:apache/>=9.0.0+M1|<=9.0.34|!=9.0.35", - "fixed_version": null - }, - { - "package": { - "type": "maven", - "namespace": "org.apache.tomcat", - "name": "tomcat", - "version": null, - "qualifiers": null, - "subpath": null - }, - "affected_version_range": "vers:maven/>=9.0.0.M1|<=9.0.34|!=9.0.35", - "fixed_version": null - } - ], - "references": [ - { - "reference_id": "CVE-2020-9484", - "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-9484", - "severities": [ - { - "system": "apache_tomcat", - "value": "Important", - "scoring_elements": "" - } - ] - }, - { - "reference_id": "", - "url": "https://github.com/apache/tomcat/commit/3aa8f28db7efb311cdd1b6fe15a9cd3b167a2222", - "severities": [] - } - ], - "date_published": null, - "weaknesses": [] - }, - { - "aliases": [ - "CVE-2018-8014" - ], - "summary": "", - "affected_packages": [ - { - "package": { - "type": "apache", - "namespace": null, - "name": "tomcat", - "version": null, - "qualifiers": null, - "subpath": null - }, - "affected_version_range": "vers:apache/>=9.0.0+M1|<=9.0.8|!=9.0.9", - "fixed_version": null - }, - { - "package": { - "type": "maven", - "namespace": "org.apache.tomcat", - "name": "tomcat", - "version": null, - "qualifiers": null, - "subpath": null - }, - "affected_version_range": "vers:maven/>=9.0.0.M1|<=9.0.8|!=9.0.9", - "fixed_version": null - } - ], - "references": [ - { - "reference_id": "CVE-2018-8014", - "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-8014", - "severities": [ - { - "system": "apache_tomcat", - "value": "Low", - "scoring_elements": "" - } - ] - }, - { - "reference_id": "", - "url": "https://svn.apache.org/viewvc?view=rev&rev=1831726", - "severities": [] - } - ], - "date_published": null, - "weaknesses": [] - }, - { - "aliases": [ - "CVE-2016-3092" - ], - "summary": "", - "affected_packages": [ - { - "package": { - "type": "apache", - "namespace": null, - "name": "tomcat", - "version": null, - "qualifiers": null, - "subpath": null - }, - "affected_version_range": "vers:apache/>=8.0.0+RC1|<=8.0.35|!=8.0.36|>=8.5.0|<=8.5.2|!=8.5.3", - "fixed_version": null - }, - { - "package": { - "type": "maven", - "namespace": "org.apache.tomcat", - "name": "tomcat", - "version": null, - "qualifiers": null, - "subpath": null - }, - "affected_version_range": "vers:maven/>=8.0.0.RC1|<=8.0.35|!=8.0.36|>=8.5.0|<=8.5.2|!=8.5.3", - "fixed_version": null - } - ], - "references": [ - { - "reference_id": "CVE-2016-3092", - "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-3092", - "severities": [ - { - "system": "apache_tomcat", - "value": "Moderate", - "scoring_elements": "" - } - ] - }, - { - "reference_id": "", - "url": "https://svn.apache.org/viewvc?view=rev&rev=1743722", - "severities": [] - }, - { - "reference_id": "", - "url": "https://svn.apache.org/viewvc?view=rev&rev=1743738", - "severities": [] - } - ], - "date_published": null, - "weaknesses": [] - }, - { - "aliases": [ - "CVE-2008-5515" - ], - "summary": "", - "affected_packages": [ - { - "package": { - "type": "apache", - "namespace": null, - "name": "tomcat", - "version": null, - "qualifiers": null, - "subpath": null - }, - "affected_version_range": "vers:apache/>=5.5.0|<=5.5.27|!=5.5.28", - "fixed_version": null - }, - { - "package": { - "type": "maven", - "namespace": "org.apache.tomcat", - "name": "tomcat", - "version": null, - "qualifiers": null, - "subpath": null - }, - "affected_version_range": "vers:maven/>=5.5.0|<=5.5.27|!=5.5.28", - "fixed_version": null - } - ], - "references": [ - { - "reference_id": "CVE-2008-5515", - "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-5515", - "severities": [ - { - "system": "apache_tomcat", - "value": "Important", - "scoring_elements": "" - } - ] - }, - { - "reference_id": "", - "url": "https://svn.apache.org/viewvc?view=rev&rev=782757", - "severities": [] - }, - { - "reference_id": "", - "url": "https://svn.apache.org/viewvc?view=rev&rev=783291", - "severities": [] - } - ], - "date_published": null, - "weaknesses": [] - }, - { - "aliases": [ - "CVE-2009-0033" - ], - "summary": "", - "affected_packages": [ - { - "package": { - "type": "apache", - "namespace": null, - "name": "tomcat", - "version": null, - "qualifiers": null, - "subpath": null - }, - "affected_version_range": "vers:apache/>=5.5.0|<=5.5.27|!=5.5.28", - "fixed_version": null - }, - { - "package": { - "type": "maven", - "namespace": "org.apache.tomcat", - "name": "tomcat", - "version": null, - "qualifiers": null, - "subpath": null - }, - "affected_version_range": "vers:maven/>=5.5.0|<=5.5.27|!=5.5.28", - "fixed_version": null - } - ], - "references": [ - { - "reference_id": "CVE-2009-0033", - "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-0033", - "severities": [ - { - "system": "apache_tomcat", - "value": "Important", - "scoring_elements": "" - } - ] - }, - { - "reference_id": "", - "url": "https://svn.apache.org/viewvc?view=rev&rev=781362", - "severities": [] - } - ], - "date_published": null, - "weaknesses": [] - }, - { - "aliases": [ - "CVE-2009-0580" - ], - "summary": "", - "affected_packages": [ - { - "package": { - "type": "apache", - "namespace": null, - "name": "tomcat", - "version": null, - "qualifiers": null, - "subpath": null - }, - "affected_version_range": "vers:apache/>=5.5.0|<=5.5.27|!=5.5.28", - "fixed_version": null - }, - { - "package": { - "type": "maven", - "namespace": "org.apache.tomcat", - "name": "tomcat", - "version": null, - "qualifiers": null, - "subpath": null - }, - "affected_version_range": "vers:maven/>=5.5.0|<=5.5.27|!=5.5.28", - "fixed_version": null - } - ], - "references": [ - { - "reference_id": "CVE-2009-0580", - "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-0580", - "severities": [ - { - "system": "apache_tomcat", - "value": "Low", - "scoring_elements": "" - } - ] - }, - { - "reference_id": "", - "url": "https://svn.apache.org/viewvc?view=rev&rev=781379", - "severities": [] - } - ], - "date_published": null, - "weaknesses": [] - }, - { - "aliases": [ - "CVE-2009-0781" - ], - "summary": "", - "affected_packages": [ - { - "package": { - "type": "apache", - "namespace": null, - "name": "tomcat", - "version": null, - "qualifiers": null, - "subpath": null - }, - "affected_version_range": "vers:apache/>=5.5.0|<=5.5.27|!=5.5.28", - "fixed_version": null - }, - { - "package": { - "type": "maven", - "namespace": "org.apache.tomcat", - "name": "tomcat", - "version": null, - "qualifiers": null, - "subpath": null - }, - "affected_version_range": "vers:maven/>=5.5.0|<=5.5.27|!=5.5.28", - "fixed_version": null - } - ], - "references": [ - { - "reference_id": "CVE-2009-0781", - "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-0781", - "severities": [ - { - "system": "apache_tomcat", - "value": "Low", - "scoring_elements": "" - } - ] - }, - { - "reference_id": "", - "url": "https://svn.apache.org/viewvc?view=rev&rev=750928", - "severities": [] - } - ], - "date_published": null, - "weaknesses": [] - }, - { - "aliases": [ - "CVE-2009-0783" - ], - "summary": "", - "affected_packages": [ - { - "package": { - "type": "apache", - "namespace": null, - "name": "tomcat", - "version": null, - "qualifiers": null, - "subpath": null - }, - "affected_version_range": "vers:apache/>=5.5.0|<=5.5.27|!=5.5.28", - "fixed_version": null - }, - { - "package": { - "type": "maven", - "namespace": "org.apache.tomcat", - "name": "tomcat", - "version": null, - "qualifiers": null, - "subpath": null - }, - "affected_version_range": "vers:maven/>=5.5.0|<=5.5.27|!=5.5.28", - "fixed_version": null - } - ], - "references": [ - { - "reference_id": "CVE-2009-0783", - "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-0783", - "severities": [ - { - "system": "apache_tomcat", - "value": "Low", - "scoring_elements": "" - } - ] - }, - { - "reference_id": "", - "url": "https://svn.apache.org/viewvc?view=rev&rev=681156", - "severities": [] - }, - { - "reference_id": "", - "url": "https://svn.apache.org/viewvc?view=rev&rev=781542", - "severities": [] - } - ], - "date_published": null, - "weaknesses": [] - }, - { - "aliases": [ - "CVE-2005-4836" - ], - "summary": "", - "affected_packages": [ - { - "package": { - "type": "apache", - "namespace": null, - "name": "tomcat", - "version": null, - "qualifiers": null, - "subpath": null - }, - "affected_version_range": "vers:apache/<=4.1.0+SVN|>=4.1.15", - "fixed_version": null - }, - { - "package": { - "type": "maven", - "namespace": "org.apache.tomcat", - "name": "tomcat", - "version": null, - "qualifiers": null, - "subpath": null - }, - "affected_version_range": "vers:maven/<=4.1.SVN|>=4.1.15", - "fixed_version": null - } - ], - "references": [ - { - "reference_id": "CVE-2005-4836", - "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2005-4836", - "severities": [ - { - "system": "apache_tomcat", - "value": "Moderate", - "scoring_elements": "" - } - ] - } - ], - "date_published": null, - "weaknesses": [] - }, - { - "aliases": [ - "CVE-2008-4308" - ], - "summary": "", - "affected_packages": [ - { - "package": { - "type": "apache", - "namespace": null, - "name": "tomcat", - "version": null, - "qualifiers": null, - "subpath": null - }, - "affected_version_range": "vers:apache/>=4.1.32|<=4.1.34|!=4.1.35", - "fixed_version": null - }, - { - "package": { - "type": "maven", - "namespace": "org.apache.tomcat", - "name": "tomcat", - "version": null, - "qualifiers": null, - "subpath": null - }, - "affected_version_range": "vers:maven/>=4.1.32|<=4.1.34|!=4.1.35", - "fixed_version": null - } - ], - "references": [ - { - "reference_id": "CVE-2008-4308", - "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-4308", - "severities": [ - { - "system": "apache_tomcat", - "value": "Low", - "scoring_elements": "" - } - ] - } - ], - "date_published": null, - "weaknesses": [] - }, - { - "aliases": [ - "CVE-2002-0935" - ], - "summary": "", - "affected_packages": [ - { - "package": { - "type": "apache", - "namespace": null, - "name": "tomcat", - "version": null, - "qualifiers": null, - "subpath": null - }, - "affected_version_range": "vers:apache/>=4.0.0|<=4.0.2|4.0.3|>=4.0.4|<=4.0.6|>=4.1.0|<=4.1.2|!=4.1.3", - "fixed_version": null - }, - { - "package": { - "type": "maven", - "namespace": "org.apache.tomcat", - "name": "tomcat", - "version": null, - "qualifiers": null, - "subpath": null - }, - "affected_version_range": "vers:maven/>=4.0.0|<=4.0.2|4.0.3|>=4.0.4|<=4.0.6|>=4.1.0|<=4.1.2|!=4.1.3", - "fixed_version": null - } - ], - "references": [ - { - "reference_id": "CVE-2002-0935", - "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2002-0935", - "severities": [ - { - "system": "apache_tomcat", - "value": "Important", - "scoring_elements": "" - } - ] - } - ], - "date_published": null, - "weaknesses": [] - }, - { - "aliases": [ - "CVE-2002-2007" - ], - "summary": "", - "affected_packages": [ - { - "package": { - "type": "apache", - "namespace": null, - "name": "tomcat", - "version": null, - "qualifiers": null, - "subpath": null - }, - "affected_version_range": "vers:apache/>=3.2.3|<=3.2.4|!=3.3.0-a", - "fixed_version": null - }, - { - "package": { - "type": "maven", - "namespace": "org.apache.tomcat", - "name": "tomcat", - "version": null, - "qualifiers": null, - "subpath": null - }, - "affected_version_range": "vers:maven/>=3.2.3|<=3.2.4|!=3.3a", - "fixed_version": null - } - ], - "references": [ - { - "reference_id": "CVE-2002-2007", - "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2002-2007", - "severities": [ - { - "system": "apache_tomcat", - "value": "Moderate", - "scoring_elements": "" - } - ] - } - ], - "date_published": null, - "weaknesses": [] - }, - { - "aliases": [ - "CVE-2002-2006" - ], - "summary": "", - "affected_packages": [ - { - "package": { - "type": "apache", - "namespace": null, - "name": "tomcat", - "version": null, - "qualifiers": null, - "subpath": null - }, - "affected_version_range": "vers:apache/>=3.1.0|<=3.1.1|>=3.2.0|<=3.2.4|!=3.3.0-a", - "fixed_version": null - }, - { - "package": { - "type": "maven", - "namespace": "org.apache.tomcat", - "name": "tomcat", - "version": null, - "qualifiers": null, - "subpath": null - }, - "affected_version_range": "vers:maven/>=3.1|<=3.1.1|>=3.2|<=3.2.4|!=3.3a", - "fixed_version": null - } - ], - "references": [ - { - "reference_id": "CVE-2002-2006", - "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2002-2006", - "severities": [ - { - "system": "apache_tomcat", - "value": "Low", - "scoring_elements": "" - } - ] - } - ], - "date_published": null, - "weaknesses": [] - }, - { - "aliases": [ - "CVE-2000-0760" - ], - "summary": "", - "affected_packages": [ - { - "package": { - "type": "apache", - "namespace": null, - "name": "tomcat", - "version": null, - "qualifiers": null, - "subpath": null - }, - "affected_version_range": "vers:apache/>=3.1.0|<=3.1.1|>=3.2.0|<=3.2.4|!=3.3.0-a", - "fixed_version": null - }, - { - "package": { - "type": "maven", - "namespace": "org.apache.tomcat", - "name": "tomcat", - "version": null, - "qualifiers": null, - "subpath": null - }, - "affected_version_range": "vers:maven/>=3.1|<=3.1.1|>=3.2|<=3.2.4|!=3.3a", - "fixed_version": null - } - ], - "references": [ - { - "reference_id": "CVE-2000-0760", - "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2000-0760", - "severities": [ - { - "system": "apache_tomcat", - "value": "Low", - "scoring_elements": "" - } - ] - } - ], - "date_published": null, - "weaknesses": [] - } -] + { + "aliases": [ + "CVE-2020-9484" + ], + "summary": "", + "affected_packages": [ + { + "package": { + "type": "apache", + "namespace": null, + "name": "tomcat", + "version": null, + "qualifiers": null, + "subpath": null + }, + "affected_version_range": "vers:apache/>=9.0.0+M1|<=9.0.41|!=9.0.43", + "fixed_version": null + }, + { + "package": { + "type": "maven", + "namespace": "org.apache.tomcat", + "name": "tomcat", + "version": null, + "qualifiers": null, + "subpath": null + }, + "affected_version_range": "vers:maven/>=9.0.0.M1|<=9.0.41|!=9.0.43", + "fixed_version": null + } + ], + "references": [ + { + "reference_id": "CVE-2020-9484", + "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-9484", + "severities": [ + { + "system": "apache_tomcat", + "value": "Low", + "scoring_elements": "" + } + ] + }, + { + "reference_id": "", + "url": "https://github.com/apache/tomcat/commit/4785433a226a20df6acbea49296e1ce7e23de453", + "severities": [] + } + ], + "date_published": null, + "weaknesses": [] + }, + { + "aliases": [ + "CVE-2021-25329" + ], + "summary": "", + "affected_packages": [ + { + "package": { + "type": "apache", + "namespace": null, + "name": "tomcat", + "version": null, + "qualifiers": null, + "subpath": null + }, + "affected_version_range": "vers:apache/>=9.0.0+M1|<=9.0.41|!=9.0.43", + "fixed_version": null + }, + { + "package": { + "type": "maven", + "namespace": "org.apache.tomcat", + "name": "tomcat", + "version": null, + "qualifiers": null, + "subpath": null + }, + "affected_version_range": "vers:maven/>=9.0.0.M1|<=9.0.41|!=9.0.43", + "fixed_version": null + } + ], + "references": [ + { + "reference_id": "CVE-2021-25329", + "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-25329", + "severities": [ + { + "system": "apache_tomcat", + "value": "Low", + "scoring_elements": "" + } + ] + }, + { + "reference_id": "", + "url": "https://github.com/apache/tomcat/commit/4785433a226a20df6acbea49296e1ce7e23de453", + "severities": [] + } + ], + "date_published": null, + "weaknesses": [] + }, + { + "aliases": [ + "CVE-2021-25122" + ], + "summary": "", + "affected_packages": [ + { + "package": { + "type": "apache", + "namespace": null, + "name": "tomcat", + "version": null, + "qualifiers": null, + "subpath": null + }, + "affected_version_range": "vers:apache/>=9.0.0+M1|<=9.0.41|!=9.0.43", + "fixed_version": null + }, + { + "package": { + "type": "maven", + "namespace": "org.apache.tomcat", + "name": "tomcat", + "version": null, + "qualifiers": null, + "subpath": null + }, + "affected_version_range": "vers:maven/>=9.0.0.M1|<=9.0.41|!=9.0.43", + "fixed_version": null + } + ], + "references": [ + { + "reference_id": "CVE-2021-25122", + "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-25122", + "severities": [ + { + "system": "apache_tomcat", + "value": "Important", + "scoring_elements": "" + } + ] + }, + { + "reference_id": "", + "url": "https://github.com/apache/tomcat/commit/d47c20a776e8919eaca8da9390a32bc8bf8210b1", + "severities": [] + } + ], + "date_published": null, + "weaknesses": [] + }, + { + "aliases": [ + "CVE-2020-9484" + ], + "summary": "", + "affected_packages": [ + { + "package": { + "type": "apache", + "namespace": null, + "name": "tomcat", + "version": null, + "qualifiers": null, + "subpath": null + }, + "affected_version_range": "vers:apache/>=9.0.0+M1|<=9.0.34|!=9.0.35", + "fixed_version": null + }, + { + "package": { + "type": "maven", + "namespace": "org.apache.tomcat", + "name": "tomcat", + "version": null, + "qualifiers": null, + "subpath": null + }, + "affected_version_range": "vers:maven/>=9.0.0.M1|<=9.0.34|!=9.0.35", + "fixed_version": null + } + ], + "references": [ + { + "reference_id": "CVE-2020-9484", + "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-9484", + "severities": [ + { + "system": "apache_tomcat", + "value": "Important", + "scoring_elements": "" + } + ] + }, + { + "reference_id": "", + "url": "https://github.com/apache/tomcat/commit/3aa8f28db7efb311cdd1b6fe15a9cd3b167a2222", + "severities": [] + } + ], + "date_published": null, + "weaknesses": [] + }, + { + "aliases": [ + "CVE-2018-8014" + ], + "summary": "", + "affected_packages": [ + { + "package": { + "type": "apache", + "namespace": null, + "name": "tomcat", + "version": null, + "qualifiers": null, + "subpath": null + }, + "affected_version_range": "vers:apache/>=9.0.0+M1|<=9.0.8|!=9.0.9", + "fixed_version": null + }, + { + "package": { + "type": "maven", + "namespace": "org.apache.tomcat", + "name": "tomcat", + "version": null, + "qualifiers": null, + "subpath": null + }, + "affected_version_range": "vers:maven/>=9.0.0.M1|<=9.0.8|!=9.0.9", + "fixed_version": null + } + ], + "references": [ + { + "reference_id": "CVE-2018-8014", + "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-8014", + "severities": [ + { + "system": "apache_tomcat", + "value": "Low", + "scoring_elements": "" + } + ] + }, + { + "reference_id": "", + "url": "https://svn.apache.org/viewvc?view=rev&rev=1831726", + "severities": [] + } + ], + "date_published": null, + "weaknesses": [] + }, + { + "aliases": [ + "CVE-2016-3092" + ], + "summary": "", + "affected_packages": [ + { + "package": { + "type": "apache", + "namespace": null, + "name": "tomcat", + "version": null, + "qualifiers": null, + "subpath": null + }, + "affected_version_range": "vers:apache/>=8.0.0+RC1|<=8.0.35|!=8.0.36|>=8.5.0|<=8.5.2|!=8.5.3", + "fixed_version": null + }, + { + "package": { + "type": "maven", + "namespace": "org.apache.tomcat", + "name": "tomcat", + "version": null, + "qualifiers": null, + "subpath": null + }, + "affected_version_range": "vers:maven/>=8.0.0.RC1|<=8.0.35|!=8.0.36|>=8.5.0|<=8.5.2|!=8.5.3", + "fixed_version": null + } + ], + "references": [ + { + "reference_id": "CVE-2016-3092", + "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-3092", + "severities": [ + { + "system": "apache_tomcat", + "value": "Moderate", + "scoring_elements": "" + } + ] + }, + { + "reference_id": "", + "url": "https://svn.apache.org/viewvc?view=rev&rev=1743722", + "severities": [] + }, + { + "reference_id": "", + "url": "https://svn.apache.org/viewvc?view=rev&rev=1743738", + "severities": [] + } + ], + "date_published": null, + "weaknesses": [] + }, + { + "aliases": [ + "CVE-2008-5515" + ], + "summary": "", + "affected_packages": [ + { + "package": { + "type": "apache", + "namespace": null, + "name": "tomcat", + "version": null, + "qualifiers": null, + "subpath": null + }, + "affected_version_range": "vers:apache/>=5.5.0|<=5.5.27|!=5.5.28", + "fixed_version": null + }, + { + "package": { + "type": "maven", + "namespace": "org.apache.tomcat", + "name": "tomcat", + "version": null, + "qualifiers": null, + "subpath": null + }, + "affected_version_range": "vers:maven/>=5.5.0|<=5.5.27|!=5.5.28", + "fixed_version": null + } + ], + "references": [ + { + "reference_id": "CVE-2008-5515", + "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-5515", + "severities": [ + { + "system": "apache_tomcat", + "value": "Important", + "scoring_elements": "" + } + ] + }, + { + "reference_id": "", + "url": "https://svn.apache.org/viewvc?view=rev&rev=782757", + "severities": [] + }, + { + "reference_id": "", + "url": "https://svn.apache.org/viewvc?view=rev&rev=783291", + "severities": [] + } + ], + "date_published": null, + "weaknesses": [] + }, + { + "aliases": [ + "CVE-2009-0033" + ], + "summary": "", + "affected_packages": [ + { + "package": { + "type": "apache", + "namespace": null, + "name": "tomcat", + "version": null, + "qualifiers": null, + "subpath": null + }, + "affected_version_range": "vers:apache/>=5.5.0|<=5.5.27|!=5.5.28", + "fixed_version": null + }, + { + "package": { + "type": "maven", + "namespace": "org.apache.tomcat", + "name": "tomcat", + "version": null, + "qualifiers": null, + "subpath": null + }, + "affected_version_range": "vers:maven/>=5.5.0|<=5.5.27|!=5.5.28", + "fixed_version": null + } + ], + "references": [ + { + "reference_id": "CVE-2009-0033", + "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-0033", + "severities": [ + { + "system": "apache_tomcat", + "value": "Important", + "scoring_elements": "" + } + ] + }, + { + "reference_id": "", + "url": "https://svn.apache.org/viewvc?view=rev&rev=781362", + "severities": [] + } + ], + "date_published": null, + "weaknesses": [] + }, + { + "aliases": [ + "CVE-2009-0580" + ], + "summary": "", + "affected_packages": [ + { + "package": { + "type": "apache", + "namespace": null, + "name": "tomcat", + "version": null, + "qualifiers": null, + "subpath": null + }, + "affected_version_range": "vers:apache/>=5.5.0|<=5.5.27|!=5.5.28", + "fixed_version": null + }, + { + "package": { + "type": "maven", + "namespace": "org.apache.tomcat", + "name": "tomcat", + "version": null, + "qualifiers": null, + "subpath": null + }, + "affected_version_range": "vers:maven/>=5.5.0|<=5.5.27|!=5.5.28", + "fixed_version": null + } + ], + "references": [ + { + "reference_id": "CVE-2009-0580", + "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-0580", + "severities": [ + { + "system": "apache_tomcat", + "value": "Low", + "scoring_elements": "" + } + ] + }, + { + "reference_id": "", + "url": "https://svn.apache.org/viewvc?view=rev&rev=781379", + "severities": [] + } + ], + "date_published": null, + "weaknesses": [] + }, + { + "aliases": [ + "CVE-2009-0781" + ], + "summary": "", + "affected_packages": [ + { + "package": { + "type": "apache", + "namespace": null, + "name": "tomcat", + "version": null, + "qualifiers": null, + "subpath": null + }, + "affected_version_range": "vers:apache/>=5.5.0|<=5.5.27|!=5.5.28", + "fixed_version": null + }, + { + "package": { + "type": "maven", + "namespace": "org.apache.tomcat", + "name": "tomcat", + "version": null, + "qualifiers": null, + "subpath": null + }, + "affected_version_range": "vers:maven/>=5.5.0|<=5.5.27|!=5.5.28", + "fixed_version": null + } + ], + "references": [ + { + "reference_id": "CVE-2009-0781", + "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-0781", + "severities": [ + { + "system": "apache_tomcat", + "value": "Low", + "scoring_elements": "" + } + ] + }, + { + "reference_id": "", + "url": "https://svn.apache.org/viewvc?view=rev&rev=750928", + "severities": [] + } + ], + "date_published": null, + "weaknesses": [] + }, + { + "aliases": [ + "CVE-2009-0783" + ], + "summary": "", + "affected_packages": [ + { + "package": { + "type": "apache", + "namespace": null, + "name": "tomcat", + "version": null, + "qualifiers": null, + "subpath": null + }, + "affected_version_range": "vers:apache/>=5.5.0|<=5.5.27|!=5.5.28", + "fixed_version": null + }, + { + "package": { + "type": "maven", + "namespace": "org.apache.tomcat", + "name": "tomcat", + "version": null, + "qualifiers": null, + "subpath": null + }, + "affected_version_range": "vers:maven/>=5.5.0|<=5.5.27|!=5.5.28", + "fixed_version": null + } + ], + "references": [ + { + "reference_id": "CVE-2009-0783", + "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-0783", + "severities": [ + { + "system": "apache_tomcat", + "value": "Low", + "scoring_elements": "" + } + ] + }, + { + "reference_id": "", + "url": "https://svn.apache.org/viewvc?view=rev&rev=681156", + "severities": [] + }, + { + "reference_id": "", + "url": "https://svn.apache.org/viewvc?view=rev&rev=781542", + "severities": [] + } + ], + "date_published": null, + "weaknesses": [] + }, + { + "aliases": [ + "CVE-2005-4836" + ], + "summary": "", + "affected_packages": [ + { + "package": { + "type": "apache", + "namespace": null, + "name": "tomcat", + "version": null, + "qualifiers": null, + "subpath": null + }, + "affected_version_range": "vers:apache/<=4.1.0+SVN|>=4.1.15", + "fixed_version": null + }, + { + "package": { + "type": "maven", + "namespace": "org.apache.tomcat", + "name": "tomcat", + "version": null, + "qualifiers": null, + "subpath": null + }, + "affected_version_range": "vers:maven/<=4.1.SVN|>=4.1.15", + "fixed_version": null + } + ], + "references": [ + { + "reference_id": "CVE-2005-4836", + "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2005-4836", + "severities": [ + { + "system": "apache_tomcat", + "value": "Moderate", + "scoring_elements": "" + } + ] + } + ], + "date_published": null, + "weaknesses": [] + }, + { + "aliases": [ + "CVE-2008-4308" + ], + "summary": "", + "affected_packages": [ + { + "package": { + "type": "apache", + "namespace": null, + "name": "tomcat", + "version": null, + "qualifiers": null, + "subpath": null + }, + "affected_version_range": "vers:apache/>=4.1.32|<=4.1.34|!=4.1.35", + "fixed_version": null + }, + { + "package": { + "type": "maven", + "namespace": "org.apache.tomcat", + "name": "tomcat", + "version": null, + "qualifiers": null, + "subpath": null + }, + "affected_version_range": "vers:maven/>=4.1.32|<=4.1.34|!=4.1.35", + "fixed_version": null + } + ], + "references": [ + { + "reference_id": "CVE-2008-4308", + "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-4308", + "severities": [ + { + "system": "apache_tomcat", + "value": "Low", + "scoring_elements": "" + } + ] + } + ], + "date_published": null, + "weaknesses": [] + }, + { + "aliases": [ + "CVE-2002-0935" + ], + "summary": "", + "affected_packages": [ + { + "package": { + "type": "apache", + "namespace": null, + "name": "tomcat", + "version": null, + "qualifiers": null, + "subpath": null + }, + "affected_version_range": "vers:apache/>=4.0.0|<=4.0.2|4.0.3|>=4.0.4|<=4.0.6|>=4.1.0|<=4.1.2|!=4.1.3", + "fixed_version": null + }, + { + "package": { + "type": "maven", + "namespace": "org.apache.tomcat", + "name": "tomcat", + "version": null, + "qualifiers": null, + "subpath": null + }, + "affected_version_range": "vers:maven/>=4.0.0|<=4.0.2|4.0.3|>=4.0.4|<=4.0.6|>=4.1.0|<=4.1.2|!=4.1.3", + "fixed_version": null + } + ], + "references": [ + { + "reference_id": "CVE-2002-0935", + "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2002-0935", + "severities": [ + { + "system": "apache_tomcat", + "value": "Important", + "scoring_elements": "" + } + ] + } + ], + "date_published": null, + "weaknesses": [] + }, + { + "aliases": [ + "CVE-2002-2007" + ], + "summary": "", + "affected_packages": [ + { + "package": { + "type": "apache", + "namespace": null, + "name": "tomcat", + "version": null, + "qualifiers": null, + "subpath": null + }, + "affected_version_range": "vers:apache/>=3.2.3|<=3.2.4|!=3.3.0-a", + "fixed_version": null + }, + { + "package": { + "type": "maven", + "namespace": "org.apache.tomcat", + "name": "tomcat", + "version": null, + "qualifiers": null, + "subpath": null + }, + "affected_version_range": "vers:maven/>=3.2.3|<=3.2.4|!=3.3a", + "fixed_version": null + } + ], + "references": [ + { + "reference_id": "CVE-2002-2007", + "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2002-2007", + "severities": [ + { + "system": "apache_tomcat", + "value": "Moderate", + "scoring_elements": "" + } + ] + } + ], + "date_published": null, + "weaknesses": [] + }, + { + "aliases": [ + "CVE-2002-2006" + ], + "summary": "", + "affected_packages": [ + { + "package": { + "type": "apache", + "namespace": null, + "name": "tomcat", + "version": null, + "qualifiers": null, + "subpath": null + }, + "affected_version_range": "vers:apache/>=3.1.0|<=3.1.1|>=3.2.0|<=3.2.4|!=3.3.0-a", + "fixed_version": null + }, + { + "package": { + "type": "maven", + "namespace": "org.apache.tomcat", + "name": "tomcat", + "version": null, + "qualifiers": null, + "subpath": null + }, + "affected_version_range": "vers:maven/>=3.1|<=3.1.1|>=3.2|<=3.2.4|!=3.3a", + "fixed_version": null + } + ], + "references": [ + { + "reference_id": "CVE-2002-2006", + "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2002-2006", + "severities": [ + { + "system": "apache_tomcat", + "value": "Low", + "scoring_elements": "" + } + ] + } + ], + "date_published": null, + "weaknesses": [] + }, + { + "aliases": [ + "CVE-2000-0760" + ], + "summary": "", + "affected_packages": [ + { + "package": { + "type": "apache", + "namespace": null, + "name": "tomcat", + "version": null, + "qualifiers": null, + "subpath": null + }, + "affected_version_range": "vers:apache/>=3.1.0|<=3.1.1|>=3.2.0|<=3.2.4|!=3.3.0-a", + "fixed_version": null + }, + { + "package": { + "type": "maven", + "namespace": "org.apache.tomcat", + "name": "tomcat", + "version": null, + "qualifiers": null, + "subpath": null + }, + "affected_version_range": "vers:maven/>=3.1|<=3.1.1|>=3.2|<=3.2.4|!=3.3a", + "fixed_version": null + } + ], + "references": [ + { + "reference_id": "CVE-2000-0760", + "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2000-0760", + "severities": [ + { + "system": "apache_tomcat", + "value": "Low", + "scoring_elements": "" + } + ] + } + ], + "date_published": null, + "weaknesses": [] + } +] \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/nvd/nvd-expected.json b/vulnerabilities/tests/test_data/nvd/nvd-expected.json index 1ce76c038..1a77da93d 100644 --- a/vulnerabilities/tests/test_data/nvd/nvd-expected.json +++ b/vulnerabilities/tests/test_data/nvd/nvd-expected.json @@ -44,7 +44,9 @@ } ], "date_published": "2012-07-25T19:55:00+00:00", - "weaknesses": [189] + "weaknesses": [ + 189 + ] }, { "aliases": [ @@ -326,6 +328,8 @@ } ], "date_published": "2003-01-17T05:00:00+00:00", - "weaknesses": [200] + "weaknesses": [ + 200 + ] } ] \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/nvd/nvd-rejected-expected.json b/vulnerabilities/tests/test_data/nvd/nvd-rejected-expected.json new file mode 100644 index 000000000..a5cde4417 --- /dev/null +++ b/vulnerabilities/tests/test_data/nvd/nvd-rejected-expected.json @@ -0,0 +1,18 @@ +[ + { + "aliases": [ + "CVE-2022-0094" + ], + "summary": "** REJECT ** DO NOT USE THIS CANDIDATE NUMBER. ConsultIDs: none. Reason: This candidate is unused by its CNA. Notes: none.", + "affected_packages": [], + "references": [ + { + "reference_id": "CVE-2022-0094", + "url": "https://nvd.nist.gov/vuln/detail/CVE-2022-0094", + "severities": [] + } + ], + "date_published": "2023-05-12T05:15:00+00:00", + "weaknesses": [] + } +] \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/nvd/rejected_nvd.json b/vulnerabilities/tests/test_data/nvd/rejected_nvd.json new file mode 100644 index 000000000..f9b060877 --- /dev/null +++ b/vulnerabilities/tests/test_data/nvd/rejected_nvd.json @@ -0,0 +1,40 @@ +{ + "CVE_Items": [ + { + "cve": { + "data_type": "CVE", + "data_format": "MITRE", + "data_version": "4.0", + "CVE_data_meta": { + "ID": "CVE-2022-0094", + "ASSIGNER": "cve@mitre.org" + }, + "problemtype": { + "problemtype_data": [ + { + "description": [] + } + ] + }, + "references": { + "reference_data": [] + }, + "description": { + "description_data": [ + { + "lang": "en", + "value": "** REJECT ** DO NOT USE THIS CANDIDATE NUMBER. ConsultIDs: none. Reason: This candidate is unused by its CNA. Notes: none." + } + ] + } + }, + "configurations": { + "CVE_data_version": "4.0", + "nodes": [] + }, + "impact": {}, + "publishedDate": "2023-05-12T05:15Z", + "lastModifiedDate": "2023-05-12T05:15Z" + } + ] +} \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/parse-advisory-npm-expected.json b/vulnerabilities/tests/test_data/parse-advisory-npm-expected.json index 938f92152..ea3a94dff 100644 --- a/vulnerabilities/tests/test_data/parse-advisory-npm-expected.json +++ b/vulnerabilities/tests/test_data/parse-advisory-npm-expected.json @@ -54,6 +54,6 @@ } ], "date_published": "2016-10-27T00:00:00+00:00", - "weaknesses": [] + "weaknesses": [] } ] \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/vulnerability_status_improver/CVE-2023-35866.json b/vulnerabilities/tests/test_data/vulnerability_status_improver/CVE-2023-35866.json new file mode 100644 index 000000000..2c88f5722 --- /dev/null +++ b/vulnerabilities/tests/test_data/vulnerability_status_improver/CVE-2023-35866.json @@ -0,0 +1,71 @@ +{ + "dataType": "CVE_RECORD", + "dataVersion": 5, + "cveMetadata": { + "state": "PUBLISHED", + "cveId": "CVE-2023-35866", + "assignerOrgId": "8254265b-2729-46b6-b9e3-3dfca2d5bfca", + "assignerShortName": "mitre", + "dateUpdated": "2023-06-21T00:00:00", + "dateReserved": "2023-06-19T00:00:00", + "datePublished": "2023-06-19T00:00:00" + }, + "containers": { + "cna": { + "providerMetadata": { + "orgId": "8254265b-2729-46b6-b9e3-3dfca2d5bfca", + "shortName": "mitre", + "dateUpdated": "2023-06-21T00:00:00" + }, + "descriptions": [ + { + "lang": "en", + "value": "In KeePassXC through 2.7.5, a local attacker can make changes to the Database security settings, including master password and second-factor authentication, within an authenticated KeePassXC Database session, without the need to authenticate these changes by entering the password and/or second-factor authentication to confirm changes. NOTE: the vendor's position is \"asking the user for their password prior to making any changes to the database settings adds no additional protection against a local attacker.\"" + } + ], + "tags": [ + "disputed" + ], + "affected": [ + { + "vendor": "n/a", + "product": "n/a", + "versions": [ + { + "version": "n/a", + "status": "affected" + } + ] + } + ], + "references": [ + { + "url": "https://github.com/keepassxreboot/keepassxc/issues/9391" + }, + { + "url": "https://github.com/keepassxreboot/keepassxc/issues/9339" + }, + { + "url": "https://github.com/keepassxreboot/keepassxc/issues/9339#issuecomment-1598219482" + }, + { + "url": "https://keepassxc.org/docs/#faq-yubikey-2fa" + }, + { + "url": "https://medium.com/%40cybercitizen.tech/keepassxc-vulnerability-cve-2023-35866-dc7d447c4903" + } + ], + "problemTypes": [ + { + "descriptions": [ + { + "type": "text", + "lang": "en", + "description": "n/a" + } + ] + } + ] + } + } +} \ No newline at end of file diff --git a/vulnerabilities/tests/test_nvd.py b/vulnerabilities/tests/test_nvd.py index af7e2f19b..702faa7f4 100644 --- a/vulnerabilities/tests/test_nvd.py +++ b/vulnerabilities/tests/test_nvd.py @@ -15,10 +15,11 @@ BASE_DIR = os.path.dirname(os.path.abspath(__file__)) TEST_DATA = os.path.join(BASE_DIR, "test_data/nvd/nvd_test.json") +REJECTED_CVE = os.path.join(BASE_DIR, "test_data/nvd/rejected_nvd.json") -def load_test_data(): - with open(TEST_DATA) as f: +def load_test_data(file): + with open(file) as f: return json.load(f) @@ -38,7 +39,26 @@ def sorted_advisory_data(advisory_data): def test_to_advisories_skips_hardware(regen=REGEN): expected_file = os.path.join(BASE_DIR, "test_data/nvd/nvd-expected.json") - test_data = load_test_data() + test_data = load_test_data(file=TEST_DATA) + result = [data.to_dict() for data in nvd.to_advisories(test_data)] + result = sorted_advisory_data(result) + + if regen: + with open(expected_file, "w") as f: + json.dump(result, f, indent=2) + expected = result + else: + with open(expected_file) as f: + expected = json.load(f) + expected = sorted_advisory_data(expected) + + assert result == expected + + +def test_to_advisories_marks_rejected_cve(regen=REGEN): + expected_file = os.path.join(BASE_DIR, "test_data/nvd/nvd-rejected-expected.json") + + test_data = load_test_data(file=REJECTED_CVE) result = [data.to_dict() for data in nvd.to_advisories(test_data)] result = sorted_advisory_data(result) diff --git a/vulnerabilities/tests/test_vulnerability_status_improver.py b/vulnerabilities/tests/test_vulnerability_status_improver.py new file mode 100644 index 000000000..0314af236 --- /dev/null +++ b/vulnerabilities/tests/test_vulnerability_status_improver.py @@ -0,0 +1,65 @@ +import os +from datetime import datetime +from unittest import mock + +import pytest + +from vulnerabilities.importers.nvd import NVDImporter +from vulnerabilities.improvers.vulnerability_status import VulnerabilityStatusImprover +from vulnerabilities.improvers.vulnerability_status import get_status_from_api +from vulnerabilities.models import Advisory +from vulnerabilities.models import Alias +from vulnerabilities.models import Vulnerability +from vulnerabilities.models import VulnerabilityStatusType + +BASE_DIR = os.path.dirname(os.path.abspath(__file__)) + + +TEST_DATA = os.path.join( + BASE_DIR, + "test_data/vulnerability_status_improver", +) + + +@pytest.mark.django_db(transaction=True) +def test_interesting_advisories(): + Advisory.objects.create( + aliases=["CVE-1"], + created_by=NVDImporter.qualified_name, + summary="1", + date_collected=datetime.now(), + ) + Advisory.objects.create( + aliases=["CVE-1"], + created_by=NVDImporter.qualified_name, + summary="2", + date_collected=datetime.now(), + ) + advs = VulnerabilityStatusImprover().interesting_advisories + assert len(list(advs)) == 1 + + +@mock.patch("vulnerabilities.utils.fetch_response") +def test_get_status_from_api(mock_response): + response = os.path.join(TEST_DATA, f"CVE-2023-35866.json") + mock_response.return_value = response + status = get_status_from_api(cve_id="CVE-2023-35866") + assert status == VulnerabilityStatusType.DISPUTED + + +@pytest.mark.django_db(transaction=True) +@mock.patch("vulnerabilities.utils.fetch_response") +def test_improver_end_to_end(mock_response): + response = os.path.join(TEST_DATA, f"CVE-2023-35866.json") + mock_response.return_value = response + adv = Advisory.objects.create( + aliases=["CVE-2023-35866"], + created_by=NVDImporter.qualified_name, + summary="1", + date_collected=datetime.now(), + ) + v1 = Vulnerability.objects.create(summary="test") + Alias.objects.create(alias="CVE-2023-35866", vulnerability=v1) + VulnerabilityStatusImprover().get_inferences(advisory_data=adv) + v1 = Vulnerability.objects.get(summary="test") + assert v1.status == VulnerabilityStatusType.DISPUTED diff --git a/vulnerabilities/views.py b/vulnerabilities/views.py index 4500f6220..fe406a0a8 100644 --- a/vulnerabilities/views.py +++ b/vulnerabilities/views.py @@ -23,7 +23,7 @@ from vulnerabilities.forms import ApiUserCreationForm from vulnerabilities.forms import PackageSearchForm from vulnerabilities.forms import VulnerabilitySearchForm -from vulnerabilities.models import Weakness +from vulnerabilities.models import VulnerabilityStatusType from vulnerabilities.utils import get_severity_range from vulnerablecode.settings import env @@ -121,6 +121,7 @@ def get_context_data(self, **kwargs): weaknesses_present_in_db = [ weakness_object for weakness_object in weaknesses if weakness_object.weakness ] + status = self.object.get_status_label context.update( { "vulnerability": self.object, @@ -134,6 +135,7 @@ def get_context_data(self, **kwargs): "affected_packages": self.object.affected_packages.all(), "fixed_by_packages": self.object.fixed_by_packages.all(), "weaknesses": weaknesses_present_in_db, + "status": status, } ) return context From a114debf94f16c528f3e865325c45aa2aef5e859 Mon Sep 17 00:00:00 2001 From: ziad hany Date: Wed, 15 Nov 2023 10:52:28 +0200 Subject: [PATCH 5/5] Remove GitLabBasicImprover (#1137) Add get_cwes_from_github_advisory function Add CWE support for github importer Add CWE support for osv Add CWE support for gitlab and redhat Signed-off-by: ziadhany --- vulnerabilities/importers/github.py | 32 ++++- vulnerabilities/importers/gitlab.py | 8 +- vulnerabilities/importers/osv.py | 5 + vulnerabilities/importers/redhat.py | 9 +- vulnerabilities/improvers/default.py | 2 + .../test_data/gitlab/composer-expected.json | 2 +- .../gitlab/composer-improver-expected.json | 2 +- .../test_data/gitlab/golang-expected.json | 2 +- .../gitlab/golang-improver-expected.json | 4 +- .../test_data/gitlab/maven-expected.json | 2 +- .../gitlab/maven-improver-expected.json | 4 +- .../tests/test_data/gitlab/npm-expected.json | 2 +- .../gitlab/npm-improver-expected.json | 4 +- .../test_data/gitlab/nuget-expected.json | 2 +- .../gitlab/nuget-improver-expected.json | 4 +- .../tests/test_data/gitlab/pypi-expected.json | 2 +- .../gitlab/pypi-improver-expected.json | 4 +- .../pysec-advisories_with_cwe-expected.json | 124 ++++++++++++++++++ .../pysec/pysec-advisory_with_cwe.json | 82 ++++++++++++ .../test_data/redhat/redhat-expected.json | 2 +- vulnerabilities/tests/test_github.py | 22 ++++ vulnerabilities/tests/test_pysec.py | 13 ++ 22 files changed, 311 insertions(+), 22 deletions(-) create mode 100644 vulnerabilities/tests/test_data/pysec/pysec-advisories_with_cwe-expected.json create mode 100644 vulnerabilities/tests/test_data/pysec/pysec-advisory_with_cwe.json diff --git a/vulnerabilities/importers/github.py b/vulnerabilities/importers/github.py index c816d3faa..8ef1b3a9c 100644 --- a/vulnerabilities/importers/github.py +++ b/vulnerabilities/importers/github.py @@ -11,6 +11,7 @@ from typing import Iterable from typing import Optional +from cwe2.database import Database from dateutil import parser as dateparser from packageurl import PackageURL from univers.version_range import RANGE_CLASS_BY_SCHEMES @@ -24,11 +25,11 @@ from vulnerabilities.importer import Reference from vulnerabilities.importer import VulnerabilitySeverity from vulnerabilities.utils import dedupe +from vulnerabilities.utils import get_cwe_id from vulnerabilities.utils import get_item logger = logging.getLogger(__name__) - PACKAGE_TYPE_BY_GITHUB_ECOSYSTEM = { "MAVEN": "maven", "NUGET": "nuget", @@ -63,6 +64,11 @@ url } severity + cwes(first: 10){ + nodes { + cweId + } + } publishedAt } firstPatchedVersion{ @@ -227,10 +233,34 @@ def process_response(resp: dict, package_type: str) -> Iterable[AdvisoryData]: else: logger.error(f"Unknown identifier type {identifier_type!r} and value {value!r}") + weaknesses = get_cwes_from_github_advisory(advisory) + yield AdvisoryData( aliases=sorted(dedupe(aliases)), summary=summary, references=references, affected_packages=affected_packages, date_published=date_published, + weaknesses=weaknesses, ) + + +def get_cwes_from_github_advisory(advisory) -> [int]: + """ + Return the cwe-id list from advisory ex: [ 522 ] + by extracting the cwe_list from advisory ex: [{'cweId': 'CWE-522'}] + then remove the CWE- from string and convert it to integer 522 and Check if the CWE in CWE-Database + """ + weaknesses = [] + db = Database() + cwe_list = get_item(advisory, "cwes", "nodes") or [] + for cwe_item in cwe_list: + cwe_string = get_item(cwe_item, "cweId") + if cwe_string: + cwe_id = get_cwe_id(cwe_string) + try: + db.get(cwe_id) + weaknesses.append(cwe_id) + except Exception: + logger.error("Invalid CWE id") + return weaknesses diff --git a/vulnerabilities/importers/gitlab.py b/vulnerabilities/importers/gitlab.py index 4d8f7d5f2..561b1a7d9 100644 --- a/vulnerabilities/importers/gitlab.py +++ b/vulnerabilities/importers/gitlab.py @@ -28,10 +28,10 @@ from vulnerabilities.importer import Importer from vulnerabilities.importer import Reference from vulnerabilities.utils import build_description +from vulnerabilities.utils import get_cwe_id logger = logging.getLogger(__name__) - PURL_TYPE_BY_GITLAB_SCHEME = { "conan": "conan", "gem": "gem", @@ -44,7 +44,6 @@ "pypi": "pypi", } - GITLAB_SCHEME_BY_PURL_TYPE = {v: k for k, v in PURL_TYPE_BY_GITLAB_SCHEME.items()} @@ -186,6 +185,10 @@ def parse_gitlab_advisory(file): summary = build_description(gitlab_advisory.get("title"), gitlab_advisory.get("description")) urls = gitlab_advisory.get("urls") references = [Reference.from_url(u) for u in urls] + + cwe_ids = gitlab_advisory.get("cwe_ids") or [] + cwe_list = list(map(get_cwe_id, cwe_ids)) + date_published = dateparser.parse(gitlab_advisory.get("pubdate")) date_published = date_published.replace(tzinfo=pytz.UTC) package_slug = gitlab_advisory.get("package_slug") @@ -251,4 +254,5 @@ def parse_gitlab_advisory(file): references=references, date_published=date_published, affected_packages=affected_packages, + weaknesses=cwe_list, ) diff --git a/vulnerabilities/importers/osv.py b/vulnerabilities/importers/osv.py index c4ee58685..cb06b2162 100644 --- a/vulnerabilities/importers/osv.py +++ b/vulnerabilities/importers/osv.py @@ -27,6 +27,7 @@ from vulnerabilities.severity_systems import SCORING_SYSTEMS from vulnerabilities.utils import build_description from vulnerabilities.utils import dedupe +from vulnerabilities.utils import get_cwe_id logger = logging.getLogger(__name__) @@ -74,6 +75,9 @@ def parse_advisory_data(raw_data: dict, supported_ecosystem) -> Optional[Advisor fixed_version=version, ) ) + database_specific = raw_data.get("database_specific") or {} + cwe_ids = database_specific.get("cwe_ids") or [] + weaknesses = list(map(get_cwe_id, cwe_ids)) return AdvisoryData( aliases=aliases, @@ -81,6 +85,7 @@ def parse_advisory_data(raw_data: dict, supported_ecosystem) -> Optional[Advisor references=references, affected_packages=affected_packages, date_published=date_published, + weaknesses=weaknesses, ) diff --git a/vulnerabilities/importers/redhat.py b/vulnerabilities/importers/redhat.py index e24480ddd..4e14a7f86 100644 --- a/vulnerabilities/importers/redhat.py +++ b/vulnerabilities/importers/redhat.py @@ -8,6 +8,7 @@ # import logging +import re from typing import Dict from typing import Iterable from typing import List @@ -23,6 +24,7 @@ from vulnerabilities.importer import Reference from vulnerabilities.importer import VulnerabilitySeverity from vulnerabilities.rpm_utils import rpm_to_purl +from vulnerabilities.utils import get_cwe_id from vulnerabilities.utils import get_item from vulnerabilities.utils import requests_with_5xx_retry @@ -61,7 +63,6 @@ def get_data_from_url(url): class RedhatImporter(Importer): - spdx_license_expression = "CC-BY-4.0" license_url = "https://access.redhat.com/documentation/en-us/red_hat_security_data_api/1.0/html/red_hat_security_data_api/legal-notice" @@ -135,6 +136,11 @@ def to_advisory(advisory_data): scoring_elements=cvssv3_vector, ) ) + cwe_list = [] + # cwe_string : CWE-409","CWE-121->CWE-787","(CWE-401|CWE-404)","(CWE-190|CWE-911)->CWE-416" + cwe_string = advisory_data.get("CWE") + if cwe_string: + cwe_list = list(map(get_cwe_id, re.findall("CWE-[0-9]+", cwe_string))) aliases = [] alias = advisory_data.get("CVE") @@ -148,4 +154,5 @@ def to_advisory(advisory_data): summary=advisory_data.get("bugzilla_description") or "", affected_packages=affected_packages, references=references, + weaknesses=cwe_list, ) diff --git a/vulnerabilities/improvers/default.py b/vulnerabilities/improvers/default.py index 3e2f1913f..1b67eee5c 100644 --- a/vulnerabilities/improvers/default.py +++ b/vulnerabilities/improvers/default.py @@ -64,6 +64,7 @@ def get_inferences(self, advisory_data: AdvisoryData) -> Iterable[Inference]: affected_purls=affected_purls, fixed_purl=None, references=advisory_data.references, + weaknesses=advisory_data.weaknesses, ) else: for fixed_purl in fixed_purls or []: @@ -74,6 +75,7 @@ def get_inferences(self, advisory_data: AdvisoryData) -> Iterable[Inference]: affected_purls=affected_purls, fixed_purl=fixed_purl, references=advisory_data.references, + weaknesses=advisory_data.weaknesses, ) else: diff --git a/vulnerabilities/tests/test_data/gitlab/composer-expected.json b/vulnerabilities/tests/test_data/gitlab/composer-expected.json index 7160cc122..8dc515d70 100644 --- a/vulnerabilities/tests/test_data/gitlab/composer-expected.json +++ b/vulnerabilities/tests/test_data/gitlab/composer-expected.json @@ -25,5 +25,5 @@ } ], "date_published": "2018-03-15T00:00:00+00:00", - "weaknesses": [] + "weaknesses": [1035,937] } \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/gitlab/composer-improver-expected.json b/vulnerabilities/tests/test_data/gitlab/composer-improver-expected.json index 33b26cbef..b5a097cd6 100644 --- a/vulnerabilities/tests/test_data/gitlab/composer-improver-expected.json +++ b/vulnerabilities/tests/test_data/gitlab/composer-improver-expected.json @@ -22,6 +22,6 @@ "severities": [] } ], - "weaknesses": [] + "weaknesses": [1035,937] } ] \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/gitlab/golang-expected.json b/vulnerabilities/tests/test_data/gitlab/golang-expected.json index b3994a760..492eb1b9a 100644 --- a/vulnerabilities/tests/test_data/gitlab/golang-expected.json +++ b/vulnerabilities/tests/test_data/gitlab/golang-expected.json @@ -31,5 +31,5 @@ } ], "date_published": "2021-05-20T00:00:00+00:00", - "weaknesses": [] + "weaknesses": [1035,937] } \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/gitlab/golang-improver-expected.json b/vulnerabilities/tests/test_data/gitlab/golang-improver-expected.json index 20bc6462d..6a5401ca3 100644 --- a/vulnerabilities/tests/test_data/gitlab/golang-improver-expected.json +++ b/vulnerabilities/tests/test_data/gitlab/golang-improver-expected.json @@ -37,7 +37,7 @@ "severities": [] } ], - "weaknesses": [] + "weaknesses": [1035,937] }, { "vulnerability_id": null, @@ -68,6 +68,6 @@ "severities": [] } ], - "weaknesses": [] + "weaknesses": [1035,937] } ] \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/gitlab/maven-expected.json b/vulnerabilities/tests/test_data/gitlab/maven-expected.json index 658f0757f..b42d85d6e 100644 --- a/vulnerabilities/tests/test_data/gitlab/maven-expected.json +++ b/vulnerabilities/tests/test_data/gitlab/maven-expected.json @@ -46,5 +46,5 @@ } ], "date_published": "2021-11-15T00:00:00+00:00", - "weaknesses": [] + "weaknesses": [1035,937,94] } \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/gitlab/maven-improver-expected.json b/vulnerabilities/tests/test_data/gitlab/maven-improver-expected.json index 206ec5c7b..6d4a4d8e0 100644 --- a/vulnerabilities/tests/test_data/gitlab/maven-improver-expected.json +++ b/vulnerabilities/tests/test_data/gitlab/maven-improver-expected.json @@ -100,7 +100,7 @@ "severities": [] } ], - "weaknesses": [] + "weaknesses": [1035,937,94] }, { "vulnerability_id": null, @@ -146,6 +146,6 @@ "severities": [] } ], - "weaknesses": [] + "weaknesses": [1035,937,94] } ] \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/gitlab/npm-expected.json b/vulnerabilities/tests/test_data/gitlab/npm-expected.json index d6eeac5bc..6612c1172 100644 --- a/vulnerabilities/tests/test_data/gitlab/npm-expected.json +++ b/vulnerabilities/tests/test_data/gitlab/npm-expected.json @@ -36,5 +36,5 @@ } ], "date_published": "2020-06-05T00:00:00+00:00", - "weaknesses": [] + "weaknesses": [1035,937] } \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/gitlab/npm-improver-expected.json b/vulnerabilities/tests/test_data/gitlab/npm-improver-expected.json index 8f849befd..2ac0cdba8 100644 --- a/vulnerabilities/tests/test_data/gitlab/npm-improver-expected.json +++ b/vulnerabilities/tests/test_data/gitlab/npm-improver-expected.json @@ -50,7 +50,7 @@ "severities": [] } ], - "weaknesses": [] + "weaknesses": [1035,937] }, { "vulnerability_id": null, @@ -86,6 +86,6 @@ "severities": [] } ], - "weaknesses": [] + "weaknesses": [1035,937] } ] \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/gitlab/nuget-expected.json b/vulnerabilities/tests/test_data/gitlab/nuget-expected.json index b226794c9..de76a9289 100644 --- a/vulnerabilities/tests/test_data/gitlab/nuget-expected.json +++ b/vulnerabilities/tests/test_data/gitlab/nuget-expected.json @@ -31,5 +31,5 @@ } ], "date_published": "2022-01-08T00:00:00+00:00", - "weaknesses": [] + "weaknesses": [1035,770,937] } \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/gitlab/nuget-improver-expected.json b/vulnerabilities/tests/test_data/gitlab/nuget-improver-expected.json index 914df9bcd..40e4850ca 100644 --- a/vulnerabilities/tests/test_data/gitlab/nuget-improver-expected.json +++ b/vulnerabilities/tests/test_data/gitlab/nuget-improver-expected.json @@ -37,7 +37,7 @@ "severities": [] } ], - "weaknesses": [] + "weaknesses": [1035,770,937] }, { "vulnerability_id": null, @@ -68,6 +68,6 @@ "severities": [] } ], - "weaknesses": [] + "weaknesses": [1035,770,937] } ] \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/gitlab/pypi-expected.json b/vulnerabilities/tests/test_data/gitlab/pypi-expected.json index 55f88215f..47b31e8f5 100644 --- a/vulnerabilities/tests/test_data/gitlab/pypi-expected.json +++ b/vulnerabilities/tests/test_data/gitlab/pypi-expected.json @@ -30,5 +30,5 @@ } ], "date_published": "2019-07-17T00:00:00+00:00", - "weaknesses": [] + "weaknesses": [1035, 937] } \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/gitlab/pypi-improver-expected.json b/vulnerabilities/tests/test_data/gitlab/pypi-improver-expected.json index ee1942f44..aa4f03b33 100644 --- a/vulnerabilities/tests/test_data/gitlab/pypi-improver-expected.json +++ b/vulnerabilities/tests/test_data/gitlab/pypi-improver-expected.json @@ -44,7 +44,7 @@ "severities": [] } ], - "weaknesses": [] + "weaknesses": [1035, 937] }, { "vulnerability_id": null, @@ -74,6 +74,6 @@ "severities": [] } ], - "weaknesses": [] + "weaknesses": [1035, 937] } ] \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/pysec/pysec-advisories_with_cwe-expected.json b/vulnerabilities/tests/test_data/pysec/pysec-advisories_with_cwe-expected.json new file mode 100644 index 000000000..7bf695d39 --- /dev/null +++ b/vulnerabilities/tests/test_data/pysec/pysec-advisories_with_cwe-expected.json @@ -0,0 +1,124 @@ +{ + "aliases": [ + "CVE-2022-24840", + "GHSA-4w8f-hjm9-xwgf" + ], + "summary": "Path Traversal in django-s3file\n### Impact\n\nIt was possible to traverse the entire AWS S3 bucket and in most cases to access or delete files.\nThe issue was discovered by the maintainer. There were no reports of the vulnerability\nbeing known to or exploited by a third party, before the release of the patch.\n\nIf the `AWS_LOCATION` setting was set, traversal was limited to that location only.\nIf all your files handling views (like form views) require authentication or special permission, the thread is limited to privileged users.\n\n### Patches\n\nThe vulnerability has been fixed in version 5.5.1 and above.\n\n### Workarounds\n\nThere is no feasible workaround. We must urge all users to immediately updated to a patched version.\n\n### Detailed attack vector description\n\nAn attacker may use a request with malicious form data to traverse the entire AWS S3 bucket and perform destructive operations.\n\nAn attack could look as follows:\n```bash\ncurl -X POST -F \"s3file=file\" -F \"file=/priviliged/location/secrets.txt\" https://www.example.com/any/path/will/work/\n```\n\nThis will result in a request with files set and opened:\n\n```python\n>>> request.FILES.getlist(\"file\")\n[File(\"/priviliged/location/secrets.txt\")]\n```\n\nSince this behavior is injected via a middleware, any view can be called this way and will carry any files defined by the attacker.\n\nVia the `s3file` form field, any input name can be specified, including multiple inputs. For each input, multiple files can be freely\npicked of the S3 bucket.\n\n#### Scenarios and their practicality\n\nThere are four scenarios that would be considered practical in most setups:\n\n1. Illegal file injection,\n2. file deletion,\n3. file retrieval & tree traversal.\n4. code injection & remote code execution.\n\n##### File deletion\n\nAn attacker knows the location of a privileged file, like a static asset. Next, the file is injected into a form view. The upload to function will move the file to a new location. This is effectively deleting the file, since the previous references to it are invalid, and will cause S3 to return a 404. Furthermore, the new location is unknown to the site operator.\n\n##### File retrieval & tree traversal\n\nAn attacker knows the URL of a secret file and injects it into a form view. The view will move the file to a public location, making it accessible to the attacker. Since most form views will not be rate limited, this could also be used to guess files and traverse the file tree.\n\n##### Illegal file injection\n\nAn attacker uses any form to upload a file to the temporary upload location. Next, the attacker injects that file into a request, does not validate the contents or is not equipped to handle the mime type. The latter could be used as a potential DOS vector.\n\nIn practice, this is not a practical risk in most hardened setup. Files should always be sanitized before processing, since files can be included in a request even without this security issues.\n\n### For more information\nIf you have any questions or comments about this advisory:\n* Open an issue on [GitHub](https://github.com/codingjoe/django-s3file/issues)\n* Email us at [johannes@maron.family](mailto:johannes@maron.family)", + "affected_packages": [ + { + "package": { + "type": "pypi", + "namespace": null, + "name": "django-s3file", + "version": null, + "qualifiers": null, + "subpath": null + }, + "affected_version_range": null, + "fixed_version": "5.5.1" + } + ], + "references": [ + { + "reference_id": "", + "url": "https://github.com/codingjoe/django-s3file/security/advisories/GHSA-4w8f-hjm9-xwgf", + "severities": [ + { + "system": "cvssv3.1", + "value": "9.1", + "scoring_elements": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N" + }, + { + "system": "generic_textual", + "value": "CRITICAL", + "scoring_elements": "" + } + ] + }, + { + "reference_id": "", + "url": "https://nvd.nist.gov/vuln/detail/CVE-2022-24840", + "severities": [ + { + "system": "cvssv3.1", + "value": "9.1", + "scoring_elements": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N" + }, + { + "system": "generic_textual", + "value": "CRITICAL", + "scoring_elements": "" + } + ] + }, + { + "reference_id": "", + "url": "https://github.com/codingjoe/django-s3file/commit/68ccd2c621a40eb66fdd6af2be9d5fcc9c373318", + "severities": [ + { + "system": "cvssv3.1", + "value": "9.1", + "scoring_elements": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N" + }, + { + "system": "generic_textual", + "value": "CRITICAL", + "scoring_elements": "" + } + ] + }, + { + "reference_id": "", + "url": "https://github.com/codingjoe/django-s3file", + "severities": [ + { + "system": "cvssv3.1", + "value": "9.1", + "scoring_elements": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N" + }, + { + "system": "generic_textual", + "value": "CRITICAL", + "scoring_elements": "" + } + ] + }, + { + "reference_id": "", + "url": "https://github.com/codingjoe/django-s3file/releases/tag/5.5.1", + "severities": [ + { + "system": "cvssv3.1", + "value": "9.1", + "scoring_elements": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N" + }, + { + "system": "generic_textual", + "value": "CRITICAL", + "scoring_elements": "" + } + ] + }, + { + "reference_id": "", + "url": "https://github.com/pypa/advisory-database/tree/main/vulns/django-s3file/PYSEC-2022-208.yaml", + "severities": [ + { + "system": "cvssv3.1", + "value": "9.1", + "scoring_elements": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N" + }, + { + "system": "generic_textual", + "value": "CRITICAL", + "scoring_elements": "" + } + ] + } + ], + "date_published": "2022-06-06T21:24:24+00:00", + "weaknesses": [ + 22, + 96 + ] +} \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/pysec/pysec-advisory_with_cwe.json b/vulnerabilities/tests/test_data/pysec/pysec-advisory_with_cwe.json new file mode 100644 index 000000000..fd2e8a6d2 --- /dev/null +++ b/vulnerabilities/tests/test_data/pysec/pysec-advisory_with_cwe.json @@ -0,0 +1,82 @@ +{ + "schema_version": "1.4.0", + "id": "GHSA-4w8f-hjm9-xwgf", + "modified": "2022-06-06T21:24:24Z", + "published": "2022-06-06T21:24:24Z", + "aliases": [ + "CVE-2022-24840" + ], + "summary": "Path Traversal in django-s3file", + "details": "### Impact\n\nIt was possible to traverse the entire AWS S3 bucket and in most cases to access or delete files.\nThe issue was discovered by the maintainer. There were no reports of the vulnerability\nbeing known to or exploited by a third party, before the release of the patch.\n\nIf the `AWS_LOCATION` setting was set, traversal was limited to that location only.\nIf all your files handling views (like form views) require authentication or special permission, the thread is limited to privileged users.\n\n### Patches\n\nThe vulnerability has been fixed in version 5.5.1 and above.\n\n### Workarounds\n\nThere is no feasible workaround. We must urge all users to immediately updated to a patched version.\n\n### Detailed attack vector description\n\nAn attacker may use a request with malicious form data to traverse the entire AWS S3 bucket and perform destructive operations.\n\nAn attack could look as follows:\n```bash\ncurl -X POST -F \"s3file=file\" -F \"file=/priviliged/location/secrets.txt\" https://www.example.com/any/path/will/work/\n```\n\nThis will result in a request with files set and opened:\n\n```python\n>>> request.FILES.getlist(\"file\")\n[File(\"/priviliged/location/secrets.txt\")]\n```\n\nSince this behavior is injected via a middleware, any view can be called this way and will carry any files defined by the attacker.\n\nVia the `s3file` form field, any input name can be specified, including multiple inputs. For each input, multiple files can be freely\npicked of the S3 bucket.\n\n#### Scenarios and their practicality\n\nThere are four scenarios that would be considered practical in most setups:\n\n1. Illegal file injection,\n2. file deletion,\n3. file retrieval & tree traversal.\n4. code injection & remote code execution.\n\n##### File deletion\n\nAn attacker knows the location of a privileged file, like a static asset. Next, the file is injected into a form view. The upload to function will move the file to a new location. This is effectively deleting the file, since the previous references to it are invalid, and will cause S3 to return a 404. Furthermore, the new location is unknown to the site operator.\n\n##### File retrieval & tree traversal\n\nAn attacker knows the URL of a secret file and injects it into a form view. The view will move the file to a public location, making it accessible to the attacker. Since most form views will not be rate limited, this could also be used to guess files and traverse the file tree.\n\n##### Illegal file injection\n\nAn attacker uses any form to upload a file to the temporary upload location. Next, the attacker injects that file into a request, does not validate the contents or is not equipped to handle the mime type. The latter could be used as a potential DOS vector.\n\nIn practice, this is not a practical risk in most hardened setup. Files should always be sanitized before processing, since files can be included in a request even without this security issues.\n\n### For more information\nIf you have any questions or comments about this advisory:\n* Open an issue on [GitHub](https://github.com/codingjoe/django-s3file/issues)\n* Email us at [johannes@maron.family](mailto:johannes@maron.family)\n", + "severity": [ + { + "type": "CVSS_V3", + "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N" + } + ], + "affected": [ + { + "package": { + "ecosystem": "PyPI", + "name": "django-s3file" + }, + "ecosystem_specific": { + "affected_functions": [ + "s3file.forms.S3FileInputMixin", + "s3file.forms.S3FileInputMixin.build_attrs", + "s3file.middleware.S3FileMiddleware.__call__", + "s3file.middleware.S3FileMiddleware.get_files_from_storage" + ] + }, + "ranges": [ + { + "type": "ECOSYSTEM", + "events": [ + { + "introduced": "0" + }, + { + "fixed": "5.5.1" + } + ] + } + ] + } + ], + "references": [ + { + "type": "WEB", + "url": "https://github.com/codingjoe/django-s3file/security/advisories/GHSA-4w8f-hjm9-xwgf" + }, + { + "type": "ADVISORY", + "url": "https://nvd.nist.gov/vuln/detail/CVE-2022-24840" + }, + { + "type": "WEB", + "url": "https://github.com/codingjoe/django-s3file/commit/68ccd2c621a40eb66fdd6af2be9d5fcc9c373318" + }, + { + "type": "PACKAGE", + "url": "https://github.com/codingjoe/django-s3file" + }, + { + "type": "WEB", + "url": "https://github.com/codingjoe/django-s3file/releases/tag/5.5.1" + }, + { + "type": "WEB", + "url": "https://github.com/pypa/advisory-database/tree/main/vulns/django-s3file/PYSEC-2022-208.yaml" + } + ], + "database_specific": { + "cwe_ids": [ + "CWE-22", + "CWE-96" + ], + "severity": "CRITICAL", + "github_reviewed": true, + "github_reviewed_at": "2022-06-06T21:24:24Z", + "nvd_published_at": "2022-06-09T04:15:00Z" + } +} \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/redhat/redhat-expected.json b/vulnerabilities/tests/test_data/redhat/redhat-expected.json index dbaa18636..3e91555de 100644 --- a/vulnerabilities/tests/test_data/redhat/redhat-expected.json +++ b/vulnerabilities/tests/test_data/redhat/redhat-expected.json @@ -221,6 +221,6 @@ } ], "date_published": null, - "weaknesses": [] + "weaknesses": [400] } ] \ No newline at end of file diff --git a/vulnerabilities/tests/test_github.py b/vulnerabilities/tests/test_github.py index b0c2491ed..0f2e634d5 100644 --- a/vulnerabilities/tests/test_github.py +++ b/vulnerabilities/tests/test_github.py @@ -24,6 +24,7 @@ from vulnerabilities.importer import Reference from vulnerabilities.importer import VulnerabilitySeverity from vulnerabilities.importers.github import GitHubAPIImporter +from vulnerabilities.importers.github import get_cwes_from_github_advisory from vulnerabilities.importers.github import process_response from vulnerabilities.improvers.valid_versions import GitHubBasicImprover from vulnerabilities.tests.util_tests import VULNERABLECODE_REGEN_TEST_FIXTURES as REGEN @@ -311,3 +312,24 @@ def test_get_package_versions(mock_response): assert PackageURL(type="gem", name="foo") in improver.versions_fetcher_by_purl assert PackageURL(type="pypi", name="django") in improver.versions_fetcher_by_purl assert PackageURL(type="pypi", name="foo") in improver.versions_fetcher_by_purl + + +def test_get_cwes_from_github_advisory(): + assert get_cwes_from_github_advisory( + {"cwes": {"nodes": [{"cweId": "CWE-502"}, {"cweId": "CWE-770"}]}} + ) == [502, 770] + assert get_cwes_from_github_advisory( + { + "cwes": { + "nodes": [ + {"cweId": "CWE-173"}, + {"cweId": "CWE-200"}, + {"cweId": "CWE-378"}, + {"cweId": "CWE-732"}, + ] + } + } + ) == [173, 200, 378, 732] + assert get_cwes_from_github_advisory( + {"cwes": {"nodes": [{"cweId": "CWE-11111111111"}, {"cweId": "CWE-200"}]}} # invalid cwe-id + ) == [200] diff --git a/vulnerabilities/tests/test_pysec.py b/vulnerabilities/tests/test_pysec.py index f5d8107ac..efdcafe55 100644 --- a/vulnerabilities/tests/test_pysec.py +++ b/vulnerabilities/tests/test_pysec.py @@ -43,3 +43,16 @@ def test_to_advisories_without_summary(self): expected_file=expected_file, regen=REGEN, ) + + def test_to_advisories_with_cwe(self): + with open(os.path.join(TEST_DATA, "pysec-advisory_with_cwe.json")) as f: + mock_response = json.load(f) + + results = parse_advisory_data(mock_response, "pypi").to_dict() + + expected_file = os.path.join(TEST_DATA, "pysec-advisories_with_cwe-expected.json") + check_results_against_json( + results=results, + expected_file=expected_file, + regen=REGEN, + )