From 82949e7e6cd78ee5d14207012acbfb498727f592 Mon Sep 17 00:00:00 2001 From: ziad hany Date: Tue, 23 Dec 2025 03:36:45 +0200 Subject: [PATCH 1/6] Fix OSV to handel affected_packages correctly Add support to collect commits Signed-off-by: ziad hany --- vulnerabilities/importers/osv_v2.py | 420 ++++++++++++++++++ .../v2_importers/github_osv_importer.py | 3 +- .../pipelines/v2_importers/oss_fuzz.py | 3 +- .../pipelines/v2_importers/pypa_importer.py | 5 +- .../test_data/osv_test/github/github-1.json | 84 ++++ .../test_data/osv_test/github/github-2.json | 64 +++ .../osv_test/github/github-expected-1.json | 77 ++++ .../osv_test/github/github-expected-2.json | 43 ++ .../osv_test/oss-fuzz/oss-fuzz-1.yaml | 45 ++ .../osv_test/oss-fuzz/oss-fuzz-2.yaml | 30 ++ .../oss-fuzz/oss-fuzz-expected-1.json | 23 + .../oss-fuzz/oss-fuzz-expected-2.json | 47 ++ .../tests/test_data/osv_test/pypa/pypa-1.yaml | 73 +++ .../tests/test_data/osv_test/pypa/pypa-2.yaml | 83 ++++ .../tests/test_data/osv_test/pypa/pypa-3.yaml | 274 ++++++++++++ .../tests/test_data/osv_test/pypa/pypa-4.yaml | 46 ++ .../tests/test_data/osv_test/pypa/pypa-5.yaml | 46 ++ .../osv_test/pypa/pypa-expected-1.json | 105 +++++ .../osv_test/pypa/pypa-expected-2.json | 69 +++ .../osv_test/pypa/pypa-expected-3.json | 81 ++++ .../osv_test/pypa/pypa-expected-4.json | 67 +++ .../osv_test/pypa/pypa-expected-5.json | 55 +++ vulnerabilities/tests/test_osv_v2.py | 111 +++++ 23 files changed, 1849 insertions(+), 5 deletions(-) create mode 100644 vulnerabilities/importers/osv_v2.py create mode 100644 vulnerabilities/tests/test_data/osv_test/github/github-1.json create mode 100644 vulnerabilities/tests/test_data/osv_test/github/github-2.json create mode 100644 vulnerabilities/tests/test_data/osv_test/github/github-expected-1.json create mode 100644 vulnerabilities/tests/test_data/osv_test/github/github-expected-2.json create mode 100644 vulnerabilities/tests/test_data/osv_test/oss-fuzz/oss-fuzz-1.yaml create mode 100644 vulnerabilities/tests/test_data/osv_test/oss-fuzz/oss-fuzz-2.yaml create mode 100644 vulnerabilities/tests/test_data/osv_test/oss-fuzz/oss-fuzz-expected-1.json create mode 100644 vulnerabilities/tests/test_data/osv_test/oss-fuzz/oss-fuzz-expected-2.json create mode 100644 vulnerabilities/tests/test_data/osv_test/pypa/pypa-1.yaml create mode 100644 vulnerabilities/tests/test_data/osv_test/pypa/pypa-2.yaml create mode 100644 vulnerabilities/tests/test_data/osv_test/pypa/pypa-3.yaml create mode 100644 vulnerabilities/tests/test_data/osv_test/pypa/pypa-4.yaml create mode 100644 vulnerabilities/tests/test_data/osv_test/pypa/pypa-5.yaml create mode 100644 vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-1.json create mode 100644 vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-2.json create mode 100644 vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-3.json create mode 100644 vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-4.json create mode 100644 vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-5.json create mode 100644 vulnerabilities/tests/test_osv_v2.py diff --git a/vulnerabilities/importers/osv_v2.py b/vulnerabilities/importers/osv_v2.py new file mode 100644 index 000000000..dbbe3e096 --- /dev/null +++ b/vulnerabilities/importers/osv_v2.py @@ -0,0 +1,420 @@ +# +# 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/aboutcode-org/vulnerablecode for support or download. +# See https://aboutcode.org for more information about nexB OSS projects. +# + +import json +import logging +from typing import Iterable +from typing import List +from typing import Optional + +import dateparser +from cvss.exceptions import CVSS3MalformedError +from cvss.exceptions import CVSS4MalformedError +from packageurl import PackageURL +from univers.version_constraint import VersionConstraint +from univers.version_range import RANGE_CLASS_BY_SCHEMES +from univers.versions import InvalidVersion +from univers.versions import SemverVersion + +from vulnerabilities.importer import AdvisoryData +from vulnerabilities.importer import AffectedPackageV2 +from vulnerabilities.importer import PackageCommitPatchData +from vulnerabilities.importer import PatchData +from vulnerabilities.importer import Reference +from vulnerabilities.importer import ReferenceV2 +from vulnerabilities.importer import VulnerabilitySeverity +from vulnerabilities.pipes.advisory import classify_patch_source +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__) + +PURL_TYPE_BY_OSV_ECOSYSTEM = { + "npm": "npm", + "pypi": "pypi", + "maven": "maven", + "nuget": "nuget", + "packagist": "composer", + "rubygems": "gem", + "go": "golang", + "hex": "hex", + "cargo": "cargo", +} + + +def parse_advisory_data_v3( + raw_data: dict, supported_ecosystems, advisory_url: str, advisory_text: str +) -> Optional[AdvisoryData]: + """ + Return an AdvisoryData build from a ``raw_data`` mapping of OSV advisory and + a ``supported_ecosystem`` string. + """ + advisory_id = raw_data.get("id") or "" + if not advisory_id: + logger.error(f"Missing advisory id in OSV data: {raw_data}") + return None + summary = raw_data.get("summary") or "" + details = raw_data.get("details") or "" + summary = build_description(summary=summary, description=details) + aliases = raw_data.get("aliases") or [] + + date_published = get_published_date(raw_data=raw_data) + severities = list(get_severities(raw_data=raw_data)) + references = get_references_v2(raw_data=raw_data) + + patches = [] + affected_packages = [] + fixed_by_commit_patches = [] + introduced_by_commit_patches = [] + for affected_pkg in raw_data.get("affected") or []: + purl = get_affected_purl(affected_pkg=affected_pkg, raw_id=advisory_id) + + if not purl or purl.type not in supported_ecosystems: + logger.error(f"Unsupported package type: {affected_pkg!r} in OSV: {advisory_id!r}") + continue + + affected_constraints = [] + explicit_affected_constraints = get_explicit_affected_constraints( + affected_pkg=affected_pkg, + raw_id=advisory_id, + supported_ecosystem=purl.type, + ) + affected_constraints.extend(explicit_affected_constraints) + + fixed_constraints = [] + for r in affected_pkg.get("ranges") or []: + ( + affected_constraint, + fixed_constraint, + intro_commits, + fixed_commits, + ) = get_version_ranges_constraints( + ranges=r, + raw_id=advisory_id, + supported_ecosystem=purl.type, + ) + + affected_constraints.extend(affected_constraint) + fixed_constraints.extend(fixed_constraint) + + repo_url = r.get("repo") + commit_processing_queue = [ + (fixed_commits, fixed_by_commit_patches), + (intro_commits, introduced_by_commit_patches), + ] + + for commit_list, target_patch_list in commit_processing_queue: + for commit_hash in commit_list: + try: + base_purl, patch_objs = classify_patch_source( + url=repo_url, commit_hash=commit_hash, patch_text=None + ) + except Exception as e: + logger.error( + f"Invalid Commit Data: repo_url:{repo_url!r} - commit_hash: {commit_hash} for OSV id: {advisory_id}" + ) + continue + for patch_obj in patch_objs: + if isinstance(patch_obj, PackageCommitPatchData): + target_patch_list.append(patch_obj) + elif isinstance(patch_obj, PatchData): + patches.append(patch_obj) + elif isinstance(patch_obj, ReferenceV2): + references.append(patch_obj) + + version_range_class = RANGE_CLASS_BY_SCHEMES.get(purl.type) + + affected_version_range = None + if affected_constraints: + try: + affected_version_range = version_range_class(constraints=affected_constraints) + except Exception as e: + logger.error(f"Failed to build VersionRange for {advisory_id}: {e}") + + fixed_version_range = None + if fixed_constraints: + try: + fixed_version_range = version_range_class(constraints=fixed_constraints) + except Exception as e: + logger.error(f"Failed to build VersionRange for {advisory_id}: {e}") + + if ( + fixed_version_range + or affected_version_range + or fixed_by_commit_patches + or introduced_by_commit_patches + ): + affected_packages.append( + AffectedPackageV2( + package=purl, + affected_version_range=affected_version_range, + fixed_version_range=fixed_version_range, + fixed_by_commit_patches=fixed_by_commit_patches, + introduced_by_commit_patches=introduced_by_commit_patches, + ) + ) + + database_specific = raw_data.get("database_specific") or {} + cwe_ids = database_specific.get("cwe_ids") or [] + weaknesses = list(map(get_cwe_id, cwe_ids)) + + if advisory_id in aliases: + aliases.remove(advisory_id) + + return AdvisoryData( + advisory_id=advisory_id, + aliases=aliases, + summary=summary, + references_v2=references, + severities=severities, + affected_packages=affected_packages, + date_published=date_published, + weaknesses=weaknesses, + patches=patches, + url=advisory_url, + original_advisory_text=advisory_text or json.dumps(raw_data, indent=2, ensure_ascii=False), + ) + + +def extract_events(range_data) -> Iterable[str]: + """ + Return a list of fixed version strings given a ``fixed_range`` mapping of + OSV data. + + >>> list(extract_events( + ... {"type": "SEMVER", "events": [{"introduced": "0"},{"fixed": "1.6.0"}]})) + [('introduced', '0'), ('fixed', '1.6.0')] + + >>> list(extract_events( + ... {"type": "ECOSYSTEM","events":[{"introduced": "0"}, + ... {"fixed": "1.0.0"},{"fixed": "9.0.0"}]})) + [('introduced', '0'), ('fixed', '1.0.0'), ('fixed', '9.0.0')] + + >>> list(extract_events( + ... {"type": "GIT","events":[{"introduced": "6e5755a2a833bc64852eae12967d0a54d7adf629"}, + ... {"fixed": "c43455749b914feef56b178b256f29b3016146eb"}]})) + [('introduced', '6e5755a2a833bc64852eae12967d0a54d7adf629'), ('fixed', 'c43455749b914feef56b178b256f29b3016146eb')] + """ + events = range_data.get("events") or [] + for event_dict in events: + for event_type, version in event_dict.items(): + yield event_type, version + + +def get_published_date(raw_data): + published = raw_data.get("published") + return published and dateparser.parse(date_string=published) + + +def get_severities(raw_data) -> Iterable[VulnerabilitySeverity]: + """ + Yield VulnerabilitySeverity extracted from a mapping of OSV ``raw_data`` + """ + try: + for severity in raw_data.get("severity") or []: + vector = severity.get("score") + valid_vector = vector[:-1] if vector and vector.endswith("/") else vector + + if severity.get("type") == "CVSS_V3": + system = SCORING_SYSTEMS["cvssv3.1"] + score = system.compute(valid_vector) + yield VulnerabilitySeverity(system=system, value=score, scoring_elements=vector) + + elif severity.get("type") == "CVSS_V4": + system = SCORING_SYSTEMS["cvssv4"] + score = system.compute(valid_vector) + yield VulnerabilitySeverity(system=system, value=score, scoring_elements=vector) + + else: + logger.error( + f"Unsupported severity type: {severity!r} for OSV id: {raw_data.get('id')!r}" + ) + except (CVSS3MalformedError, CVSS4MalformedError) as e: + logger.error(f"Invalid severity {e}") + + ecosystem_specific = raw_data.get("ecosystem_specific") or {} + severity = ecosystem_specific.get("severity") + if severity: + yield VulnerabilitySeverity( + system=SCORING_SYSTEMS["generic_textual"], + value=severity, + ) + + database_specific = raw_data.get("database_specific") or {} + severity = database_specific.get("severity") + if severity: + yield VulnerabilitySeverity( + system=SCORING_SYSTEMS["generic_textual"], + value=severity, + ) + + +def get_references_v2(raw_data) -> List[Reference]: + """ + Return a list Reference extracted from a mapping of OSV ``raw_data`` given a + ``severities`` list of VulnerabilitySeverity. + """ + references = [] + for ref in raw_data.get("references") or []: + if not ref: + continue + url = ref["url"] + if not url: + logger.error(f"Reference without URL : {ref!r} for OSV id: {raw_data['id']!r}") + continue + references.append(ReferenceV2(url=ref["url"])) + return references + + +def get_affected_purl(affected_pkg, raw_id): + """ + Return an affected PackageURL or None given a mapping of ``affected_pkg`` + data and a ``raw_id``. + """ + package = affected_pkg.get("package") or {} + purl = package.get("purl") + if purl: + try: + purl = PackageURL.from_string(purl) + except ValueError: + logger.error( + f"Invalid PackageURL: {purl!r} for OSV " + f"affected_pkg {affected_pkg} and id: {raw_id}" + ) + else: + ecosys = package.get("ecosystem") + name = package.get("name") + if ecosys and name: + ecosys = ecosys.lower() + purl_type = PURL_TYPE_BY_OSV_ECOSYSTEM.get(ecosys) + if not purl_type: + return + namespace = "" + if purl_type == "maven": + namespace, _, name = name.partition(":") + + purl = PackageURL(type=purl_type, namespace=namespace, name=name) + else: + logger.error( + f"No PackageURL possible: {purl!r} for affected_pkg {affected_pkg} for OSV id: {raw_id}" + ) + return + try: + package_url = PackageURL.from_string(str(purl)) + return package_url + except: + logger.error( + f"Invalid PackageURL: {purl!r} for affected_pkg {affected_pkg} for OSV id: {raw_id}" + ) + return None + + +def get_explicit_affected_constraints(affected_pkg, raw_id, supported_ecosystem): + """ + Return a univers VersionRange for the ``affected_pkg`` package data mapping + or None. Use a ``raw_id`` OSV id and ``supported_ecosystem``. + """ + affected_versions = affected_pkg.get("versions") or [] + constraints = [] + + version_range_class = RANGE_CLASS_BY_SCHEMES.get(supported_ecosystem) + if not version_range_class: + logger.error(f"unsupported ecosystem {supported_ecosystem}") + return [] + + for version in affected_versions: + try: + version_obj = version_range_class.version_class(version) + constraint = VersionConstraint(comparator="=", version=version_obj) + constraints.append(constraint) + except Exception as e: + logger.error( + f"Invalid VersionRange for affected_pkg: {affected_pkg} " + f"for OSV id: {raw_id!r}: error:{e!r}" + ) + + return constraints + + +def get_version_ranges_constraints(ranges, raw_id, supported_ecosystem): + """ + Return a list of unique fixed univers Versions given a ``fixed_range`` + univers VersionRange and a ``raw_id``. + For example:: + >>> get_version_ranges_constraints(range={}, raw_id="GHSA-j3f7-7rmc-6wqj", supported_ecosystem="pypi",) + [] + >>> get_version_ranges_constraints( + ... ranges={"type": "ECOSYSTEM", "events": [{"fixed": "1.7.0"}], }, + ... raw_id="GHSA-j3f7-7rmc-6wqj", + ... supported_ecosystem="pypi", + ... ) + [PypiVersion(string='1.7.0')] + """ + fixed_commits = [] + intro_commits = [] + + if "type" not in ranges: + logger.error(f"Invalid fixed_range type for: {ranges} for OSV id: {raw_id!r}") + return [] + + range_type = ranges["type"] + + affected_constraints = [] + fixed_constraints = [] + version_range_class = RANGE_CLASS_BY_SCHEMES.get(supported_ecosystem) + + for event_type, event_value in extract_events(ranges): + if range_type == "GIT": + if event_value == "0": + event_value = "4b825dc642cb6eb9a060e54bf8d69288fbee4904" + + if event_type == "fixed": + fixed_commits.append(event_value) + elif event_type == "introduced": + intro_commits.append(event_value) + else: + logger.error(f"Invalid Commit: {event_value!r} for OSV id: {raw_id!r}") + + elif range_type in ("ECOSYSTEM", "SEMVER"): + if range_type == "ECOSYSTEM": + version_class = version_range_class.version_class if version_range_class else None + else: + version_class = SemverVersion # range_type = "SEMVER" + + try: + v_obj = version_class(event_value) + except InvalidVersion: + logger.error(f"Invalid SemverVersion: {event_value!r} for OSV id: {raw_id!r}") + continue + + if event_type == "introduced": + constraint = VersionConstraint(comparator=">=", version=v_obj) + affected_constraints.append(constraint) + + elif event_type == "fixed": + affected_constraint = VersionConstraint(comparator="<", version=v_obj) + affected_constraints.append(affected_constraint) + + fixed_constraint = VersionConstraint(comparator="=", version=v_obj) + fixed_constraints.append(fixed_constraint) + + elif event_type == "last_affected": + constraint = VersionConstraint(comparator="<=", version=v_obj) + affected_constraints.append(constraint) + else: + logger.error(f"Unsupported fixed version type: {event_value!r} for OSV id: {raw_id!r}") + + return ( + affected_constraints, + fixed_constraints, + dedupe(intro_commits), + dedupe(fixed_commits), + ) diff --git a/vulnerabilities/pipelines/v2_importers/github_osv_importer.py b/vulnerabilities/pipelines/v2_importers/github_osv_importer.py index 36f9d06b7..88c2616b1 100644 --- a/vulnerabilities/pipelines/v2_importers/github_osv_importer.py +++ b/vulnerabilities/pipelines/v2_importers/github_osv_importer.py @@ -14,6 +14,7 @@ from fetchcode.vcs import fetch_via_vcs from vulnerabilities.importer import AdvisoryData +from vulnerabilities.importers.osv_v2 import parse_advisory_data_v3 from vulnerabilities.pipelines import VulnerableCodeBaseImporterPipelineV2 from vulnerabilities.utils import get_advisory_url @@ -72,7 +73,7 @@ def collect_advisories(self) -> Iterable[AdvisoryData]: with open(file) as f: raw_data = json.load(f) advisory_text = file.read_text() - yield parse_advisory_data_v2( + yield parse_advisory_data_v3( raw_data=raw_data, supported_ecosystems=supported_ecosystems, advisory_url=advisory_url, diff --git a/vulnerabilities/pipelines/v2_importers/oss_fuzz.py b/vulnerabilities/pipelines/v2_importers/oss_fuzz.py index 9c5f78d90..a8ae41959 100644 --- a/vulnerabilities/pipelines/v2_importers/oss_fuzz.py +++ b/vulnerabilities/pipelines/v2_importers/oss_fuzz.py @@ -14,6 +14,7 @@ from fetchcode.vcs import fetch_via_vcs from vulnerabilities.importer import AdvisoryData +from vulnerabilities.importers.osv_v2 import parse_advisory_data_v3 from vulnerabilities.pipelines import VulnerableCodeBaseImporterPipelineV2 from vulnerabilities.utils import get_advisory_url @@ -56,7 +57,7 @@ def collect_advisories(self) -> Iterable[AdvisoryData]: ) advisory_text = advisory.read_text() advisory_dict = saneyaml.load(advisory_text) - yield parse_advisory_data_v2( + yield parse_advisory_data_v3( raw_data=advisory_dict, supported_ecosystems=["generic"], advisory_url=advisory_url, diff --git a/vulnerabilities/pipelines/v2_importers/pypa_importer.py b/vulnerabilities/pipelines/v2_importers/pypa_importer.py index fa5edaa0b..076623eec 100644 --- a/vulnerabilities/pipelines/v2_importers/pypa_importer.py +++ b/vulnerabilities/pipelines/v2_importers/pypa_importer.py @@ -14,6 +14,7 @@ from fetchcode.vcs import fetch_via_vcs from vulnerabilities.importer import AdvisoryData +from vulnerabilities.importers.osv_v2 import parse_advisory_data_v3 from vulnerabilities.pipelines import VulnerableCodeBaseImporterPipelineV2 from vulnerabilities.utils import get_advisory_url @@ -46,8 +47,6 @@ def advisories_count(self): return sum(1 for _ in vulns_directory.rglob("*.yaml")) def collect_advisories(self) -> Iterable[AdvisoryData]: - from vulnerabilities.importers.osv import parse_advisory_data_v2 - base_directory = Path(self.vcs_response.dest_dir) vulns_directory = base_directory / "vulns" @@ -59,7 +58,7 @@ def collect_advisories(self) -> Iterable[AdvisoryData]: ) advisory_text = advisory.read_text() advisory_dict = saneyaml.load(advisory_text) - yield parse_advisory_data_v2( + yield parse_advisory_data_v3( raw_data=advisory_dict, supported_ecosystems=["pypi"], advisory_url=advisory_url, diff --git a/vulnerabilities/tests/test_data/osv_test/github/github-1.json b/vulnerabilities/tests/test_data/osv_test/github/github-1.json new file mode 100644 index 000000000..a3c1a7dc8 --- /dev/null +++ b/vulnerabilities/tests/test_data/osv_test/github/github-1.json @@ -0,0 +1,84 @@ +{ + "schema_version": "1.4.0", + "id": "GHSA-2hjr-vmf3-xwvp", + "modified": "2024-07-26T14:18:08Z", + "published": "2024-07-26T06:30:47Z", + "aliases": [ + "CVE-2023-49921" + ], + "summary": "Elasticsearch Insertion of Sensitive Information into Log File", + "details": "An issue was discovered by Elastic whereby Watcher search input logged the search query results on DEBUG log level. This could lead to raw contents of documents stored in Elasticsearch to be printed in logs. Elastic has released 8.11.2 and 7.17.16 that resolves this issue by removing this excessive logging. This issue only affects users that use Watcher and have a Watch defined that uses the search input and additionally have set the search input’s logger to DEBUG or finer, for example using: org.elasticsearch.xpack.watcher.input.search, org.elasticsearch.xpack.watcher.input, org.elasticsearch.xpack.watcher, or wider, since the loggers are hierarchical.", + "severity": [ + { + "type": "CVSS_V3", + "score": "CVSS:3.1/AV:A/AC:L/PR:L/UI:R/S:U/C:H/I:N/A:N" + }, + { + "type": "CVSS_V4", + "score": "CVSS:4.0/AV:A/AC:L/AT:P/PR:L/UI:P/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N" + } + ], + "affected": [ + { + "package": { + "ecosystem": "Maven", + "name": "org.elasticsearch:elasticsearch" + }, + "ranges": [ + { + "type": "ECOSYSTEM", + "events": [ + { + "introduced": "0" + }, + { + "fixed": "7.17.16" + } + ] + } + ] + }, + { + "package": { + "ecosystem": "Maven", + "name": "org.elasticsearch:elasticsearch" + }, + "ranges": [ + { + "type": "ECOSYSTEM", + "events": [ + { + "introduced": "8.0.0" + }, + { + "fixed": "8.11.2" + } + ] + } + ] + } + ], + "references": [ + { + "type": "ADVISORY", + "url": "https://nvd.nist.gov/vuln/detail/CVE-2023-49921" + }, + { + "type": "WEB", + "url": "https://discuss.elastic.co/t/elasticsearch-8-11-2-7-17-16-security-update-esa-2023-29/349179" + }, + { + "type": "PACKAGE", + "url": "https://github.com/elastic/elasticsearch" + } + ], + "database_specific": { + "cwe_ids": [ + "CWE-532" + ], + "severity": "MODERATE", + "github_reviewed": true, + "github_reviewed_at": "2024-07-26T14:18:08Z", + "nvd_published_at": "2024-07-26T05:15:10Z" + } +} \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/osv_test/github/github-2.json b/vulnerabilities/tests/test_data/osv_test/github/github-2.json new file mode 100644 index 000000000..88662bdbd --- /dev/null +++ b/vulnerabilities/tests/test_data/osv_test/github/github-2.json @@ -0,0 +1,64 @@ +{ + "schema_version": "1.4.0", + "id": "GHSA-2jm2-2p35-rp3j", + "modified": "2025-11-19T21:55:33Z", + "published": "2025-11-19T21:00:37Z", + "aliases": [ + "CVE-2025-65103" + ], + "summary": "OpenSTAManager has Authenticated SQL Injection in API via 'display' parameter", + "details": "### Summary\nAn authenticated SQL Injection vulnerability in the API allows any user, regardless of permission level, to execute arbitrary SQL queries. By manipulating the `display` parameter in an API request, an attacker can exfiltrate, modify, or delete any data in the database, leading to a full system compromise.\n\n### Details\nThe vulnerability is located in the `retrieve()` method within `src/API/Manager.php`.\n\nUser input from the `display` GET parameter is processed without proper validation. The code strips the surrounding brackets `[]`, splits the string by commas, and then passes each resulting element directly into the `selectRaw()` function of the query builder.\n\n```php\n// User input from 'display' is taken without sanitization.\n$select = !empty($request['display']) ? explode(',', substr((string) $request['display'], 1, -1)) : null;\n\n// ...\n\n// The unsanitized input is passed directly to `selectRaw()`.\nforeach ($select as $s) {\n $query->selectRaw($s);\n}\n```\n\nSince `selectRaw()` is designed to execute raw SQL expressions, it executes any malicious SQL code provided in the `display` parameter.\n\n### PoC\n1. Log in to an OpenSTAManager instance as any user.\n2. Navigate to the user's profile page to obtain their personal API Token.\n3. Use this API token to send a specially crafted GET request to the API endpoint.\n\n**Time-Based Blind Injection Test:**\n\nReplace ``, ``, and `` with your actual values. `anagrafiche` is a valid resource.\n\n```bash\ncurl \"http:///openstamanager/api?token=&resource=anagrafiche&display=[1,SLEEP(5)]\"\n```\n\nThe server will delay its response by approximately 5 seconds, confirming the `SLEEP(5)` command was executed by the database.\n\n### Impact\nThis is a critical SQL Injection vulnerability. Any authenticated user, even those with the lowest privileges, can exploit this vulnerability to:\n\n* **Exfiltrate all data** from the database (e.g., user credentials, customer information, invoices, internal data).\n* **Modify or delete data**, compromising data integrity.\n* Potentially achieve further system compromise, depending on the database user's privileges and system configuration.", + "severity": [ + { + "type": "CVSS_V3", + "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H" + } + ], + "affected": [ + { + "package": { + "ecosystem": "Packagist", + "name": "devcode-it/openstamanager" + }, + "ranges": [ + { + "type": "ECOSYSTEM", + "events": [ + { + "introduced": "0" + }, + { + "fixed": "2.9.5" + } + ] + } + ], + "database_specific": { + "last_known_affected_version_range": "<= 2.9.4" + } + } + ], + "references": [ + { + "type": "WEB", + "url": "https://github.com/devcode-it/openstamanager/security/advisories/GHSA-2jm2-2p35-rp3j" + }, + { + "type": "ADVISORY", + "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-65103" + }, + { + "type": "PACKAGE", + "url": "https://github.com/devcode-it/openstamanager" + } + ], + "database_specific": { + "cwe_ids": [ + "CWE-89" + ], + "severity": "HIGH", + "github_reviewed": true, + "github_reviewed_at": "2025-11-19T21:00:37Z", + "nvd_published_at": "2025-11-19T20:15:54Z" + } +} \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/osv_test/github/github-expected-1.json b/vulnerabilities/tests/test_data/osv_test/github/github-expected-1.json new file mode 100644 index 000000000..21dadd09c --- /dev/null +++ b/vulnerabilities/tests/test_data/osv_test/github/github-expected-1.json @@ -0,0 +1,77 @@ +{ + "advisory_id": "GHSA-2hjr-vmf3-xwvp", + "aliases": [ + "CVE-2023-49921" + ], + "summary": "Elasticsearch Insertion of Sensitive Information into Log File\nAn issue was discovered by Elastic whereby Watcher search input logged the search query results on DEBUG log level. This could lead to raw contents of documents stored in Elasticsearch to be printed in logs. Elastic has released 8.11.2 and 7.17.16 that resolves this issue by removing this excessive logging. This issue only affects users that use Watcher and have a Watch defined that uses the search input and additionally have set the search input’s logger to DEBUG or finer, for example using: org.elasticsearch.xpack.watcher.input.search, org.elasticsearch.xpack.watcher.input, org.elasticsearch.xpack.watcher, or wider, since the loggers are hierarchical.", + "affected_packages": [ + { + "package": { + "type": "maven", + "namespace": "org.elasticsearch", + "name": "elasticsearch", + "version": "", + "qualifiers": "", + "subpath": "" + }, + "affected_version_range": "vers:maven/>=0|<7.17.16", + "fixed_version_range": "vers:maven/7.17.16", + "introduced_by_commit_patches": [], + "fixed_by_commit_patches": [] + }, + { + "package": { + "type": "maven", + "namespace": "org.elasticsearch", + "name": "elasticsearch", + "version": "", + "qualifiers": "", + "subpath": "" + }, + "affected_version_range": "vers:maven/>=8.0.0|<8.11.2", + "fixed_version_range": "vers:maven/8.11.2", + "introduced_by_commit_patches": [], + "fixed_by_commit_patches": [] + } + ], + "references_v2": [ + { + "reference_id": "", + "reference_type": "", + "url": "https://nvd.nist.gov/vuln/detail/CVE-2023-49921" + }, + { + "reference_id": "", + "reference_type": "", + "url": "https://discuss.elastic.co/t/elasticsearch-8-11-2-7-17-16-security-update-esa-2023-29/349179" + }, + { + "reference_id": "", + "reference_type": "", + "url": "https://github.com/elastic/elasticsearch" + } + ], + "patches": [], + "severities": [ + { + "system": "cvssv3.1", + "value": "5.2", + "scoring_elements": "CVSS:3.1/AV:A/AC:L/PR:L/UI:R/S:U/C:H/I:N/A:N" + }, + { + "system": "cvssv4", + "value": "4.1", + "scoring_elements": "CVSS:4.0/AV:A/AC:L/AT:P/PR:L/UI:P/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N" + }, + { + "system": "generic_textual", + "value": "MODERATE", + "scoring_elements": "" + } + ], + "date_published": "2024-07-26T06:30:47+00:00", + "weaknesses": [ + 532 + ], + "url": "https://test.com" +} \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/osv_test/github/github-expected-2.json b/vulnerabilities/tests/test_data/osv_test/github/github-expected-2.json new file mode 100644 index 000000000..3660fb7bc --- /dev/null +++ b/vulnerabilities/tests/test_data/osv_test/github/github-expected-2.json @@ -0,0 +1,43 @@ +{ + "advisory_id": "GHSA-2jm2-2p35-rp3j", + "aliases": [ + "CVE-2025-65103" + ], + "summary": "OpenSTAManager has Authenticated SQL Injection in API via 'display' parameter\n### Summary\nAn authenticated SQL Injection vulnerability in the API allows any user, regardless of permission level, to execute arbitrary SQL queries. By manipulating the `display` parameter in an API request, an attacker can exfiltrate, modify, or delete any data in the database, leading to a full system compromise.\n\n### Details\nThe vulnerability is located in the `retrieve()` method within `src/API/Manager.php`.\n\nUser input from the `display` GET parameter is processed without proper validation. The code strips the surrounding brackets `[]`, splits the string by commas, and then passes each resulting element directly into the `selectRaw()` function of the query builder.\n\n```php\n// User input from 'display' is taken without sanitization.\n$select = !empty($request['display']) ? explode(',', substr((string) $request['display'], 1, -1)) : null;\n\n// ...\n\n// The unsanitized input is passed directly to `selectRaw()`.\nforeach ($select as $s) {\n $query->selectRaw($s);\n}\n```\n\nSince `selectRaw()` is designed to execute raw SQL expressions, it executes any malicious SQL code provided in the `display` parameter.\n\n### PoC\n1. Log in to an OpenSTAManager instance as any user.\n2. Navigate to the user's profile page to obtain their personal API Token.\n3. Use this API token to send a specially crafted GET request to the API endpoint.\n\n**Time-Based Blind Injection Test:**\n\nReplace ``, ``, and `` with your actual values. `anagrafiche` is a valid resource.\n\n```bash\ncurl \"http:///openstamanager/api?token=&resource=anagrafiche&display=[1,SLEEP(5)]\"\n```\n\nThe server will delay its response by approximately 5 seconds, confirming the `SLEEP(5)` command was executed by the database.\n\n### Impact\nThis is a critical SQL Injection vulnerability. Any authenticated user, even those with the lowest privileges, can exploit this vulnerability to:\n\n* **Exfiltrate all data** from the database (e.g., user credentials, customer information, invoices, internal data).\n* **Modify or delete data**, compromising data integrity.\n* Potentially achieve further system compromise, depending on the database user's privileges and system configuration.", + "affected_packages": [], + "references_v2": [ + { + "reference_id": "", + "reference_type": "", + "url": "https://github.com/devcode-it/openstamanager/security/advisories/GHSA-2jm2-2p35-rp3j" + }, + { + "reference_id": "", + "reference_type": "", + "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-65103" + }, + { + "reference_id": "", + "reference_type": "", + "url": "https://github.com/devcode-it/openstamanager" + } + ], + "patches": [], + "severities": [ + { + "system": "cvssv3.1", + "value": "8.8", + "scoring_elements": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H" + }, + { + "system": "generic_textual", + "value": "HIGH", + "scoring_elements": "" + } + ], + "date_published": "2025-11-19T21:00:37+00:00", + "weaknesses": [ + 89 + ], + "url": "https://test.com" +} \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/osv_test/oss-fuzz/oss-fuzz-1.yaml b/vulnerabilities/tests/test_data/osv_test/oss-fuzz/oss-fuzz-1.yaml new file mode 100644 index 000000000..799a9a59c --- /dev/null +++ b/vulnerabilities/tests/test_data/osv_test/oss-fuzz/oss-fuzz-1.yaml @@ -0,0 +1,45 @@ +affected: +- ecosystem_specific: + severity: LOW + package: + ecosystem: OSS-Fuzz + name: apache-commons-configuration + purl: pkg:generic/apache-commons-configuration + ranges: + - events: + - introduced: 4117b2050ab011f131d5a81c824bf89ddde303d4 + repo: https://gitbox.apache.org/repos/asf/commons-configuration.git + type: GIT + versions: + - commons-configuration-2.10.0-RC1 + - commons-configuration-2.10.1-RC1 + - commons-configuration-2.9.0-RC1 + - rel/commons-configuration-2.10.0 + - rel/commons-configuration-2.10.1 + - rel/commons-configuration-2.9.0 + - commons-configuration-2.11.0-RC1 + - rel/commons-configuration-2.11.0 + - commons-configuration-2.11.1-RC1 + - commons-configuration-2.12.0-RC1 + - commons-configuration-2.12.0 + - rel/commons-configuration-2.12.0 + - commons-configuration-2.13.0-RC1 + - rel/commons-configuration-2.13.0 +details: | + OSS-Fuzz report: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=66703 + + ``` + Crash type: Security exception + Crash state: + java.base/java.util.stream.AbstractPipeline.evaluate + java.base/java.util.stream.ReferencePipeline.collect + org.apache.commons.configuration2.AbstractYAMLBasedConfiguration.parseCollection + ``` +id: OSV-2024-269 +modified: '2025-11-29T14:27:29.156170Z' +published: '2024-04-18T00:04:02.456948Z' +references: +- type: REPORT + url: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=66703 +schema_version: 1.6.0 +summary: Security exception in java.base/java.util.stream.AbstractPipeline.evaluate \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/osv_test/oss-fuzz/oss-fuzz-2.yaml b/vulnerabilities/tests/test_data/osv_test/oss-fuzz/oss-fuzz-2.yaml new file mode 100644 index 000000000..cee5fb792 --- /dev/null +++ b/vulnerabilities/tests/test_data/osv_test/oss-fuzz/oss-fuzz-2.yaml @@ -0,0 +1,30 @@ +id: OSV-2022-96 +summary: Heap-buffer-overflow in sequence_compression_api.c +details: | + OSS-Fuzz report: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=44122 + + ``` + Crash type: Heap-buffer-overflow WRITE 16 + Crash state: + sequence_compression_api.c + ``` +modified: '2022-04-13T03:04:31.675527Z' +published: '2022-01-29T00:00:24.594329Z' +references: +- type: REPORT + url: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=44122 +affected: +- package: + name: zstd + ecosystem: OSS-Fuzz + purl: pkg:generic/zstd + ranges: + - type: GIT + repo: https://github.com/facebook/zstd + events: + - introduced: fc2ea97442460158a92d1e7b7c26e7486e45a605 + - fixed: 5684bae4f666f2730f2121048b0aa8472ac30457 + ecosystem_specific: + severity: HIGH + versions: [] +schema_version: 1.2.0 \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/osv_test/oss-fuzz/oss-fuzz-expected-1.json b/vulnerabilities/tests/test_data/osv_test/oss-fuzz/oss-fuzz-expected-1.json new file mode 100644 index 000000000..86bf4435b --- /dev/null +++ b/vulnerabilities/tests/test_data/osv_test/oss-fuzz/oss-fuzz-expected-1.json @@ -0,0 +1,23 @@ +{ + "advisory_id": "OSV-2024-269", + "aliases": [], + "summary": "Security exception in java.base/java.util.stream.AbstractPipeline.evaluate\nOSS-Fuzz report: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=66703\n\n```\nCrash type: Security exception\nCrash state:\njava.base/java.util.stream.AbstractPipeline.evaluate\njava.base/java.util.stream.ReferencePipeline.collect\norg.apache.commons.configuration2.AbstractYAMLBasedConfiguration.parseCollection\n```", + "affected_packages": [], + "references_v2": [ + { + "reference_id": "", + "reference_type": "", + "url": "https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=66703" + }, + { + "reference_id": "4117b2050ab011f131d5a81c824bf89ddde303d4", + "reference_type": "commit", + "url": "https://gitbox.apache.org/repos/asf/commons-configuration.git" + } + ], + "patches": [], + "severities": [], + "date_published": "2024-04-18T00:04:02.456948+00:00", + "weaknesses": [], + "url": "https://test.com" +} \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/osv_test/oss-fuzz/oss-fuzz-expected-2.json b/vulnerabilities/tests/test_data/osv_test/oss-fuzz/oss-fuzz-expected-2.json new file mode 100644 index 000000000..481221ff7 --- /dev/null +++ b/vulnerabilities/tests/test_data/osv_test/oss-fuzz/oss-fuzz-expected-2.json @@ -0,0 +1,47 @@ +{ + "advisory_id": "OSV-2022-96", + "aliases": [], + "summary": "Heap-buffer-overflow in sequence_compression_api.c\nOSS-Fuzz report: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=44122\n\n```\nCrash type: Heap-buffer-overflow WRITE 16\nCrash state:\nsequence_compression_api.c\n```", + "affected_packages": [ + { + "package": { + "type": "generic", + "namespace": "", + "name": "zstd", + "version": "", + "qualifiers": "", + "subpath": "" + }, + "affected_version_range": null, + "fixed_version_range": null, + "introduced_by_commit_patches": [ + { + "vcs_url": "https://github.com/facebook/zstd", + "commit_hash": "fc2ea97442460158a92d1e7b7c26e7486e45a605", + "patch_text": null, + "patch_checksum": null + } + ], + "fixed_by_commit_patches": [ + { + "vcs_url": "https://github.com/facebook/zstd", + "commit_hash": "5684bae4f666f2730f2121048b0aa8472ac30457", + "patch_text": null, + "patch_checksum": null + } + ] + } + ], + "references_v2": [ + { + "reference_id": "", + "reference_type": "", + "url": "https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=44122" + } + ], + "patches": [], + "severities": [], + "date_published": "2022-01-29T00:00:24.594329+00:00", + "weaknesses": [], + "url": "https://test.com" +} \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/osv_test/pypa/pypa-1.yaml b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-1.yaml new file mode 100644 index 000000000..986336a36 --- /dev/null +++ b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-1.yaml @@ -0,0 +1,73 @@ +affected: +- package: + ecosystem: PyPI + name: ipa + purl: pkg:pypi/ipa + ranges: + - events: + - introduced: '0' + - fixed: 91f4af7e6af53e1c6bf17ed36cb2161863eddae4 + - fixed: 18eea90ebb24a9c22248f0b7e18646cc6e3e3e0f + - fixed: a1991aeac19c3fec1fdd0d184c6760c90c9f9fc9 + - fixed: 31e41eea6c2322689826e6065ceba82551c565aa + - fixed: a40285c5a0288669b72f9d991508d4405885bffc + repo: https://fedoraproject.org/wiki/Infrastructure/Fedorahosted-retirement + type: GIT + - events: + - introduced: '0' + type: ECOSYSTEM + versions: + - 4.10.2 + - 4.12.2 + - 4.4.0.dev1 + - 4.5.0 + - 4.5.2 + - 4.5.4 + - 4.6.2 + - 4.6.3 + - 4.6.4 + - 4.6.5 + - 4.6.7 + - 4.7.0 + - 4.7.1 + - 4.7.2 + - 4.7.4 + - 4.7.5 + - 4.8.0 + - 4.8.0rc1 + - 4.8.1 + - 4.8.2 + - 4.8.3 + - 4.8.5 + - 4.8.6 + - 4.8.7 + - 4.8.9 + - 4.9.12 +aliases: +- CVE-2012-5484 +details: The client in FreeIPA 2.x and 3.x before 3.1.2 does not properly obtain the + Certification Authority (CA) certificate from the server, which allows man-in-the-middle + attackers to spoof a join procedure via a crafted certificate. +id: PYSEC-2013-38 +modified: '2024-11-21T14:22:51.898526Z' +published: '2013-01-27T18:55:00Z' +references: +- type: ADVISORY + url: http://www.freeipa.org/page/CVE-2012-5484 +- type: WEB + url: http://git.fedorahosted.org/cgit/freeipa.git/commit/?id=91f4af7e6af53e1c6bf17ed36cb2161863eddae4 +- type: WEB + url: http://git.fedorahosted.org/cgit/freeipa.git/commit/?id=18eea90ebb24a9c22248f0b7e18646cc6e3e3e0f +- type: WEB + url: http://git.fedorahosted.org/cgit/freeipa.git/commit/?id=a1991aeac19c3fec1fdd0d184c6760c90c9f9fc9 +- type: WEB + url: http://git.fedorahosted.org/cgit/freeipa.git/commit/?id=31e41eea6c2322689826e6065ceba82551c565aa +- type: WEB + url: http://git.fedorahosted.org/cgit/freeipa.git/commit/?id=a40285c5a0288669b72f9d991508d4405885bffc +- type: WEB + url: http://www.freeipa.org/page/Releases/3.1.2 +- type: ADVISORY + url: http://rhn.redhat.com/errata/RHSA-2013-0188.html +- type: ADVISORY + url: http://rhn.redhat.com/errata/RHSA-2013-0189.html +withdrawn: '2024-11-22T04:37:04Z' \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/osv_test/pypa/pypa-2.yaml b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-2.yaml new file mode 100644 index 000000000..0057a35e9 --- /dev/null +++ b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-2.yaml @@ -0,0 +1,83 @@ +id: PYSEC-2024-158 +modified: 2025-01-14T05:22:11.856636Z +published: 2024-12-13T05:15:07Z +aliases: +- CVE-2024-21543 +details: Versions of the package djoser before 2.3.0 are vulnerable to Authentication + Bypass when the authenticate() function fails. This is because the system falls + back to querying the database directly, granting access to users with valid credentials, + and eventually bypassing custom authentication checks such as two-factor authentication, + LDAP validations, or requirements from configured AUTHENTICATION_BACKENDS. +affected: +- package: + ecosystem: PyPI + name: djoser + purl: pkg:pypi/djoser + ranges: + - type: GIT + events: + - introduced: "0" + - fixed: d33c3993c0c735f23cbedc60fa59fce69354f19d + repo: https://github.com/sunscrapers/djoser + - type: ECOSYSTEM + events: + - introduced: "0" + - fixed: 2.3.0 + versions: + - 0.0.1 + - 0.0.2 + - 0.0.3 + - 0.1.0 + - 0.2.0 + - 0.2.1 + - 0.3.0 + - 0.3.1 + - 0.3.2 + - 0.4.0 + - 0.4.1 + - 0.4.2 + - 0.4.3 + - 0.5.0 + - 0.5.1 + - 0.5.2 + - 0.5.3 + - 0.5.4 + - 0.6.0 + - 0.7.0 + - 1.0.0 + - 1.0.1 + - 1.1.0 + - 1.1.1 + - 1.1.2 + - 1.1.3 + - 1.1.4 + - 1.1.5 + - 1.2.2 + - 1.3.3 + - 1.4.1 + - 1.5.1 + - 1.6.0 + - 1.7.0 + - 2.0.0 + - 2.0.1 + - 2.0.2 + - 2.0.3 + - 2.0.4 + - 2.0.5 + - 2.1.0 + - 2.2.0 + - 2.2.0a0 + - 2.2.1 + - 2.2.2 + - 2.2.3 +references: +- type: FIX + url: https://github.com/sunscrapers/djoser/commit/d33c3993c0c735f23cbedc60fa59fce69354f19d +- type: REPORT + url: https://github.com/sunscrapers/djoser/issues/795 +- type: WEB + url: https://github.com/sunscrapers/djoser/pull/819 +- type: WEB + url: https://github.com/sunscrapers/djoser/releases/tag/2.3.0 +- type: WEB + url: https://security.snyk.io/vuln/SNYK-PYTHON-DJOSER-8366540 \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/osv_test/pypa/pypa-3.yaml b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-3.yaml new file mode 100644 index 000000000..8c193dad6 --- /dev/null +++ b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-3.yaml @@ -0,0 +1,274 @@ +id: PYSEC-2024-26 +modified: 2024-02-06T20:20:18.162431Z +published: 2024-01-29T23:15:00Z +aliases: +- CVE-2024-23829 +- GHSA-8qpw-xqxj-h4r2 +details: aiohttp is an asynchronous HTTP client/server framework for asyncio and Python. + Security-sensitive parts of the Python HTTP parser retained minor differences in + allowable character sets, that must trigger error handling to robustly match frame + boundaries of proxies in order to protect against injection of additional requests. + Additionally, validation could trigger exceptions that were not handled consistently + with processing of other malformed input. Being more lenient than internet standards + require could, depending on deployment environment, assist in request smuggling. + The unhandled exception could cause excessive resource consumption on the application + server and/or its logging facilities. This vulnerability exists due to an incomplete + fix for CVE-2023-47627. Version 3.9.2 fixes this vulnerability. +affected: +- package: + ecosystem: PyPI + name: aiohttp + purl: pkg:pypi/aiohttp + ranges: + - type: GIT + events: + - introduced: "0" + - fixed: 33ccdfb0a12690af5bb49bda2319ec0907fa7827 + repo: https://github.com/aio-libs/aiohttp + - type: ECOSYSTEM + events: + - introduced: "0" + - fixed: 3.9.2 + versions: + - "0.1" + - 0.10.0 + - 0.10.1 + - 0.10.2 + - 0.11.0 + - 0.12.0 + - 0.13.0 + - 0.13.1 + - 0.14.0 + - 0.14.1 + - 0.14.2 + - 0.14.3 + - 0.14.4 + - 0.15.0 + - 0.15.1 + - 0.15.2 + - 0.15.3 + - 0.16.0 + - 0.16.1 + - 0.16.2 + - 0.16.3 + - 0.16.4 + - 0.16.5 + - 0.16.6 + - 0.17.0 + - 0.17.1 + - 0.17.2 + - 0.17.3 + - 0.17.4 + - 0.18.0 + - 0.18.1 + - 0.18.2 + - 0.18.3 + - 0.18.4 + - 0.19.0 + - "0.2" + - 0.20.0 + - 0.20.1 + - 0.20.2 + - 0.21.0 + - 0.21.1 + - 0.21.2 + - 0.21.4 + - 0.21.5 + - 0.21.6 + - 0.22.0 + - 0.22.0a0 + - 0.22.0b0 + - 0.22.0b1 + - 0.22.0b2 + - 0.22.0b3 + - 0.22.0b4 + - 0.22.0b5 + - 0.22.0b6 + - 0.22.1 + - 0.22.2 + - 0.22.3 + - 0.22.4 + - 0.22.5 + - "0.3" + - "0.4" + - 0.4.1 + - 0.4.2 + - 0.4.3 + - 0.4.4 + - 0.5.0 + - 0.6.0 + - 0.6.1 + - 0.6.2 + - 0.6.3 + - 0.6.4 + - 0.6.5 + - 0.7.0 + - 0.7.1 + - 0.7.2 + - 0.7.3 + - 0.8.0 + - 0.8.1 + - 0.8.2 + - 0.8.3 + - 0.8.4 + - 0.9.0 + - 0.9.1 + - 0.9.2 + - 0.9.3 + - 1.0.0 + - 1.0.1 + - 1.0.2 + - 1.0.3 + - 1.0.5 + - 1.1.0 + - 1.1.1 + - 1.1.2 + - 1.1.3 + - 1.1.4 + - 1.1.5 + - 1.1.6 + - 1.2.0 + - 1.3.0 + - 1.3.1 + - 1.3.2 + - 1.3.3 + - 1.3.4 + - 1.3.5 + - 2.0.0 + - 2.0.0rc1 + - 2.0.1 + - 2.0.2 + - 2.0.3 + - 2.0.4 + - 2.0.5 + - 2.0.6 + - 2.0.7 + - 2.1.0 + - 2.2.0 + - 2.2.1 + - 2.2.2 + - 2.2.3 + - 2.2.4 + - 2.2.5 + - 2.3.0 + - 2.3.0a1 + - 2.3.0a2 + - 2.3.0a3 + - 2.3.0a4 + - 2.3.1 + - 2.3.10 + - 2.3.1a1 + - 2.3.2 + - 2.3.2b2 + - 2.3.2b3 + - 2.3.3 + - 2.3.4 + - 2.3.5 + - 2.3.6 + - 2.3.7 + - 2.3.8 + - 2.3.9 + - 3.0.0 + - 3.0.0b0 + - 3.0.0b1 + - 3.0.0b2 + - 3.0.0b3 + - 3.0.0b4 + - 3.0.1 + - 3.0.2 + - 3.0.3 + - 3.0.4 + - 3.0.5 + - 3.0.6 + - 3.0.7 + - 3.0.8 + - 3.0.9 + - 3.1.0 + - 3.1.1 + - 3.1.2 + - 3.1.3 + - 3.2.0 + - 3.2.1 + - 3.3.0 + - 3.3.0a0 + - 3.3.1 + - 3.3.2 + - 3.3.2a0 + - 3.4.0 + - 3.4.0a0 + - 3.4.0a3 + - 3.4.0b1 + - 3.4.0b2 + - 3.4.1 + - 3.4.2 + - 3.4.3 + - 3.4.4 + - 3.5.0 + - 3.5.0a1 + - 3.5.0b1 + - 3.5.0b2 + - 3.5.0b3 + - 3.5.1 + - 3.5.2 + - 3.5.3 + - 3.5.4 + - 3.6.0 + - 3.6.0a0 + - 3.6.0a1 + - 3.6.0a11 + - 3.6.0a12 + - 3.6.0a2 + - 3.6.0a3 + - 3.6.0a4 + - 3.6.0a5 + - 3.6.0a6 + - 3.6.0a7 + - 3.6.0a8 + - 3.6.0a9 + - 3.6.0b0 + - 3.6.1 + - 3.6.1b3 + - 3.6.1b4 + - 3.6.2 + - 3.6.2a0 + - 3.6.2a1 + - 3.6.2a2 + - 3.6.3 + - 3.7.0 + - 3.7.0b0 + - 3.7.0b1 + - 3.7.1 + - 3.7.2 + - 3.7.3 + - 3.7.4 + - 3.7.4.post0 + - 3.8.0 + - 3.8.0a7 + - 3.8.0b0 + - 3.8.1 + - 3.8.2 + - 3.8.3 + - 3.8.4 + - 3.8.5 + - 3.8.6 + - 3.9.0 + - 3.9.0b0 + - 3.9.0b1 + - 3.9.0rc0 + - 3.9.1 +severity: +- type: CVSS_V3 + score: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:L +references: +- type: EVIDENCE + url: https://github.com/aio-libs/aiohttp/security/advisories/GHSA-8qpw-xqxj-h4r2 +- type: FIX + url: https://github.com/aio-libs/aiohttp/security/advisories/GHSA-8qpw-xqxj-h4r2 +- type: ADVISORY + url: https://github.com/aio-libs/aiohttp/security/advisories/GHSA-8qpw-xqxj-h4r2 +- type: FIX + url: https://github.com/aio-libs/aiohttp/pull/8074 +- type: FIX + url: https://github.com/aio-libs/aiohttp/commit/33ccdfb0a12690af5bb49bda2319ec0907fa7827 +- type: ARTICLE + url: https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/XXWVZIVAYWEBHNRIILZVB3R3SDQNNAA7/ \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/osv_test/pypa/pypa-4.yaml b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-4.yaml new file mode 100644 index 000000000..1782244db --- /dev/null +++ b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-4.yaml @@ -0,0 +1,46 @@ +affected: +- package: + ecosystem: PyPI + name: ansible-runner + purl: pkg:pypi/ansible-runner + ranges: + - events: + - introduced: 2.0.0 + - fixed: 2.1.0 + type: ECOSYSTEM + versions: + - 2.0.0 + - 2.0.1 + - 2.0.2 + - 2.0.3 + - 2.0.4 + - 2.1.0.0a1 + - 2.1.0.0a2 + - 2.1.0.0b1 +aliases: +- CVE-2021-3702 +- GHSA-772j-xvf9-qpf5 +details: A race condition flaw was found in ansible-runner, where an attacker could + watch for rapid creation and deletion of a temporary directory, substitute their + directory at that name, and then have access to ansible-runner's private_data_dir + the next time ansible-runner made use of the private_data_dir. The highest Threat + out of this flaw is to integrity and confidentiality. +id: PYSEC-2022-43068 +modified: '2024-11-25T18:33:04.123836Z' +published: '2022-08-23T16:15:00Z' +references: +- type: REPORT + url: https://bugzilla.redhat.com/show_bug.cgi?id=1977965 +- type: FIX + url: https://bugzilla.redhat.com/show_bug.cgi?id=1977965 +- type: ADVISORY + url: https://bugzilla.redhat.com/show_bug.cgi?id=1977965 +- type: ADVISORY + url: https://access.redhat.com/security/cve/CVE-2021-3702 +- type: FIX + url: https://github.com/ansible/ansible-runner/pull/742/commits +- type: WEB + url: https://github.com/ansible/ansible-runner/pull/742/commits +severity: +- score: CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:N + type: CVSS_V3 \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/osv_test/pypa/pypa-5.yaml b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-5.yaml new file mode 100644 index 000000000..8fc994762 --- /dev/null +++ b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-5.yaml @@ -0,0 +1,46 @@ +id: PYSEC-2021-796 +details: TensorFlow is an end-to-end open source platform for machine learning. In + affected versions TFLite's [`expand_dims.cc`](https://github.com/tensorflow/tensorflow/blob/149562d49faa709ea80df1d99fc41d005b81082a/tensorflow/lite/kernels/expand_dims.cc#L36-L50) + contains a vulnerability which allows reading one element outside of bounds of heap + allocated data. If `axis` is a large negative value (e.g., `-100000`), then after + the first `if` it would still be negative. The check following the `if` statement + will pass and the `for` loop would read one element before the start of `input_dims.data` + (when `i = 0`). We have patched the issue in GitHub commit d94ffe08a65400f898241c0374e9edc6fa8ed257. + The fix will be included in TensorFlow 2.6.0. We will also cherrypick this commit + on TensorFlow 2.5.1, TensorFlow 2.4.3, and TensorFlow 2.3.4, as these are also affected + and still in supported range. +affected: +- package: + name: tensorflow-gpu + ecosystem: PyPI + purl: pkg:pypi/tensorflow-gpu + ranges: + - type: GIT + repo: https://github.com/tensorflow/tensorflow + events: + - introduced: "0" + - fixed: d94ffe08a65400f898241c0374e9edc6fa8ed257 + - type: ECOSYSTEM + events: + - introduced: 2.3.0 + - fixed: 2.3.4 + - introduced: 2.4.0 + - fixed: 2.4.3 + versions: + - 2.3.0 + - 2.3.1 + - 2.3.2 + - 2.3.3 + - 2.4.0 + - 2.4.1 + - 2.4.2 +references: +- type: FIX + url: https://github.com/tensorflow/tensorflow/commit/d94ffe08a65400f898241c0374e9edc6fa8ed257 +- type: ADVISORY + url: https://github.com/tensorflow/tensorflow/security/advisories/GHSA-c545-c4f9-rf6v +aliases: +- CVE-2021-37685 +- GHSA-c545-c4f9-rf6v +modified: "2021-12-09T06:35:39.778016Z" +published: "2021-08-12T23:15:00Z" \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-1.json b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-1.json new file mode 100644 index 000000000..97d650d7b --- /dev/null +++ b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-1.json @@ -0,0 +1,105 @@ +{ + "advisory_id": "PYSEC-2013-38", + "aliases": [ + "CVE-2012-5484" + ], + "summary": "The client in FreeIPA 2.x and 3.x before 3.1.2 does not properly obtain the Certification Authority (CA) certificate from the server, which allows man-in-the-middle attackers to spoof a join procedure via a crafted certificate.", + "affected_packages": [ + { + "package": { + "type": "pypi", + "namespace": "", + "name": "ipa", + "version": "", + "qualifiers": "", + "subpath": "" + }, + "affected_version_range": "vers:pypi/>=0|4.4.0.dev1|4.5.0|4.5.2|4.5.4|4.6.2|4.6.3|4.6.4|4.6.5|4.6.7|4.7.0|4.7.1|4.7.2|4.7.4|4.7.5|4.8.0rc1|4.8.0|4.8.1|4.8.2|4.8.3|4.8.5|4.8.6|4.8.7|4.8.9|4.9.12|4.10.2|4.12.2", + "fixed_version_range": null, + "introduced_by_commit_patches": [], + "fixed_by_commit_patches": [] + } + ], + "references_v2": [ + { + "reference_id": "", + "reference_type": "", + "url": "http://www.freeipa.org/page/CVE-2012-5484" + }, + { + "reference_id": "", + "reference_type": "", + "url": "http://git.fedorahosted.org/cgit/freeipa.git/commit/?id=91f4af7e6af53e1c6bf17ed36cb2161863eddae4" + }, + { + "reference_id": "", + "reference_type": "", + "url": "http://git.fedorahosted.org/cgit/freeipa.git/commit/?id=18eea90ebb24a9c22248f0b7e18646cc6e3e3e0f" + }, + { + "reference_id": "", + "reference_type": "", + "url": "http://git.fedorahosted.org/cgit/freeipa.git/commit/?id=a1991aeac19c3fec1fdd0d184c6760c90c9f9fc9" + }, + { + "reference_id": "", + "reference_type": "", + "url": "http://git.fedorahosted.org/cgit/freeipa.git/commit/?id=31e41eea6c2322689826e6065ceba82551c565aa" + }, + { + "reference_id": "", + "reference_type": "", + "url": "http://git.fedorahosted.org/cgit/freeipa.git/commit/?id=a40285c5a0288669b72f9d991508d4405885bffc" + }, + { + "reference_id": "", + "reference_type": "", + "url": "http://www.freeipa.org/page/Releases/3.1.2" + }, + { + "reference_id": "", + "reference_type": "", + "url": "http://rhn.redhat.com/errata/RHSA-2013-0188.html" + }, + { + "reference_id": "", + "reference_type": "", + "url": "http://rhn.redhat.com/errata/RHSA-2013-0189.html" + }, + { + "reference_id": "91f4af7e6af53e1c6bf17ed36cb2161863eddae4", + "reference_type": "commit", + "url": "https://fedoraproject.org/wiki/Infrastructure/Fedorahosted-retirement" + }, + { + "reference_id": "18eea90ebb24a9c22248f0b7e18646cc6e3e3e0f", + "reference_type": "commit", + "url": "https://fedoraproject.org/wiki/Infrastructure/Fedorahosted-retirement" + }, + { + "reference_id": "a1991aeac19c3fec1fdd0d184c6760c90c9f9fc9", + "reference_type": "commit", + "url": "https://fedoraproject.org/wiki/Infrastructure/Fedorahosted-retirement" + }, + { + "reference_id": "31e41eea6c2322689826e6065ceba82551c565aa", + "reference_type": "commit", + "url": "https://fedoraproject.org/wiki/Infrastructure/Fedorahosted-retirement" + }, + { + "reference_id": "a40285c5a0288669b72f9d991508d4405885bffc", + "reference_type": "commit", + "url": "https://fedoraproject.org/wiki/Infrastructure/Fedorahosted-retirement" + }, + { + "reference_id": "4b825dc642cb6eb9a060e54bf8d69288fbee4904", + "reference_type": "commit", + "url": "https://fedoraproject.org/wiki/Infrastructure/Fedorahosted-retirement" + } + ], + "patches": [], + "severities": [], + "date_published": "2013-01-27T18:55:00+00:00", + "weaknesses": [], + "url": "https://test.com" +} \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-2.json b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-2.json new file mode 100644 index 000000000..eed98cdc1 --- /dev/null +++ b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-2.json @@ -0,0 +1,69 @@ +{ + "advisory_id": "PYSEC-2024-158", + "aliases": [ + "CVE-2024-21543" + ], + "summary": "Versions of the package djoser before 2.3.0 are vulnerable to Authentication Bypass when the authenticate() function fails. This is because the system falls back to querying the database directly, granting access to users with valid credentials, and eventually bypassing custom authentication checks such as two-factor authentication, LDAP validations, or requirements from configured AUTHENTICATION_BACKENDS.", + "affected_packages": [ + { + "package": { + "type": "pypi", + "namespace": "", + "name": "djoser", + "version": "", + "qualifiers": "", + "subpath": "" + }, + "affected_version_range": "vers:pypi/>=0|0.0.1|0.0.2|0.0.3|0.1.0|0.2.0|0.2.1|0.3.0|0.3.1|0.3.2|0.4.0|0.4.1|0.4.2|0.4.3|0.5.0|0.5.1|0.5.2|0.5.3|0.5.4|0.6.0|0.7.0|1.0.0|1.0.1|1.1.0|1.1.1|1.1.2|1.1.3|1.1.4|1.1.5|1.2.2|1.3.3|1.4.1|1.5.1|1.6.0|1.7.0|2.0.0|2.0.1|2.0.2|2.0.3|2.0.4|2.0.5|2.1.0|2.2.0a0|2.2.0|2.2.1|2.2.2|2.2.3|<2.3.0", + "fixed_version_range": "vers:pypi/2.3.0", + "introduced_by_commit_patches": [ + { + "vcs_url": "https://github.com/sunscrapers/djoser", + "commit_hash": "4b825dc642cb6eb9a060e54bf8d69288fbee4904", + "patch_text": null, + "patch_checksum": null + } + ], + "fixed_by_commit_patches": [ + { + "vcs_url": "https://github.com/sunscrapers/djoser", + "commit_hash": "d33c3993c0c735f23cbedc60fa59fce69354f19d", + "patch_text": null, + "patch_checksum": null + } + ] + } + ], + "references_v2": [ + { + "reference_id": "", + "reference_type": "", + "url": "https://github.com/sunscrapers/djoser/commit/d33c3993c0c735f23cbedc60fa59fce69354f19d" + }, + { + "reference_id": "", + "reference_type": "", + "url": "https://github.com/sunscrapers/djoser/issues/795" + }, + { + "reference_id": "", + "reference_type": "", + "url": "https://github.com/sunscrapers/djoser/pull/819" + }, + { + "reference_id": "", + "reference_type": "", + "url": "https://github.com/sunscrapers/djoser/releases/tag/2.3.0" + }, + { + "reference_id": "", + "reference_type": "", + "url": "https://security.snyk.io/vuln/SNYK-PYTHON-DJOSER-8366540" + } + ], + "patches": [], + "severities": [], + "date_published": "2024-12-13T05:15:07+00:00", + "weaknesses": [], + "url": "https://test.com" +} \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-3.json b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-3.json new file mode 100644 index 000000000..b6d07bf22 --- /dev/null +++ b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-3.json @@ -0,0 +1,81 @@ +{ + "advisory_id": "PYSEC-2024-26", + "aliases": [ + "CVE-2024-23829", + "GHSA-8qpw-xqxj-h4r2" + ], + "summary": "aiohttp is an asynchronous HTTP client/server framework for asyncio and Python. Security-sensitive parts of the Python HTTP parser retained minor differences in allowable character sets, that must trigger error handling to robustly match frame boundaries of proxies in order to protect against injection of additional requests. Additionally, validation could trigger exceptions that were not handled consistently with processing of other malformed input. Being more lenient than internet standards require could, depending on deployment environment, assist in request smuggling. The unhandled exception could cause excessive resource consumption on the application server and/or its logging facilities. This vulnerability exists due to an incomplete fix for CVE-2023-47627. Version 3.9.2 fixes this vulnerability.", + "affected_packages": [ + { + "package": { + "type": "pypi", + "namespace": "", + "name": "aiohttp", + "version": "", + "qualifiers": "", + "subpath": "" + }, + "affected_version_range": "vers:pypi/>=0|0.1|0.2|0.3|0.4|0.4.1|0.4.2|0.4.3|0.4.4|0.5.0|0.6.0|0.6.1|0.6.2|0.6.3|0.6.4|0.6.5|0.7.0|0.7.1|0.7.2|0.7.3|0.8.0|0.8.1|0.8.2|0.8.3|0.8.4|0.9.0|0.9.1|0.9.2|0.9.3|0.10.0|0.10.1|0.10.2|0.11.0|0.12.0|0.13.0|0.13.1|0.14.0|0.14.1|0.14.2|0.14.3|0.14.4|0.15.0|0.15.1|0.15.2|0.15.3|0.16.0|0.16.1|0.16.2|0.16.3|0.16.4|0.16.5|0.16.6|0.17.0|0.17.1|0.17.2|0.17.3|0.17.4|0.18.0|0.18.1|0.18.2|0.18.3|0.18.4|0.19.0|0.20.0|0.20.1|0.20.2|0.21.0|0.21.1|0.21.2|0.21.4|0.21.5|0.21.6|0.22.0a0|0.22.0b0|0.22.0b1|0.22.0b2|0.22.0b3|0.22.0b4|0.22.0b5|0.22.0b6|0.22.0|0.22.1|0.22.2|0.22.3|0.22.4|0.22.5|1.0.0|1.0.1|1.0.2|1.0.3|1.0.5|1.1.0|1.1.1|1.1.2|1.1.3|1.1.4|1.1.5|1.1.6|1.2.0|1.3.0|1.3.1|1.3.2|1.3.3|1.3.4|1.3.5|2.0.0rc1|2.0.0|2.0.1|2.0.2|2.0.3|2.0.4|2.0.5|2.0.6|2.0.7|2.1.0|2.2.0|2.2.1|2.2.2|2.2.3|2.2.4|2.2.5|2.3.0a1|2.3.0a2|2.3.0a3|2.3.0a4|2.3.0|2.3.1a1|2.3.1|2.3.2b2|2.3.2b3|2.3.2|2.3.3|2.3.4|2.3.5|2.3.6|2.3.7|2.3.8|2.3.9|2.3.10|3.0.0b0|3.0.0b1|3.0.0b2|3.0.0b3|3.0.0b4|3.0.0|3.0.1|3.0.2|3.0.3|3.0.4|3.0.5|3.0.6|3.0.7|3.0.8|3.0.9|3.1.0|3.1.1|3.1.2|3.1.3|3.2.0|3.2.1|3.3.0a0|3.3.0|3.3.1|3.3.2a0|3.3.2|3.4.0a0|3.4.0a3|3.4.0b1|3.4.0b2|3.4.0|3.4.1|3.4.2|3.4.3|3.4.4|3.5.0a1|3.5.0b1|3.5.0b2|3.5.0b3|3.5.0|3.5.1|3.5.2|3.5.3|3.5.4|3.6.0a0|3.6.0a1|3.6.0a2|3.6.0a3|3.6.0a4|3.6.0a5|3.6.0a6|3.6.0a7|3.6.0a8|3.6.0a9|3.6.0a11|3.6.0a12|3.6.0b0|3.6.0|3.6.1b3|3.6.1b4|3.6.1|3.6.2a0|3.6.2a1|3.6.2a2|3.6.2|3.6.3|3.7.0b0|3.7.0b1|3.7.0|3.7.1|3.7.2|3.7.3|3.7.4|3.7.4.post0|3.8.0a7|3.8.0b0|3.8.0|3.8.1|3.8.2|3.8.3|3.8.4|3.8.5|3.8.6|3.9.0b0|3.9.0b1|3.9.0rc0|3.9.0|3.9.1|<3.9.2", + "fixed_version_range": "vers:pypi/3.9.2", + "introduced_by_commit_patches": [ + { + "vcs_url": "https://github.com/aio-libs/aiohttp", + "commit_hash": "4b825dc642cb6eb9a060e54bf8d69288fbee4904", + "patch_text": null, + "patch_checksum": null + } + ], + "fixed_by_commit_patches": [ + { + "vcs_url": "https://github.com/aio-libs/aiohttp", + "commit_hash": "33ccdfb0a12690af5bb49bda2319ec0907fa7827", + "patch_text": null, + "patch_checksum": null + } + ] + } + ], + "references_v2": [ + { + "reference_id": "", + "reference_type": "", + "url": "https://github.com/aio-libs/aiohttp/security/advisories/GHSA-8qpw-xqxj-h4r2" + }, + { + "reference_id": "", + "reference_type": "", + "url": "https://github.com/aio-libs/aiohttp/security/advisories/GHSA-8qpw-xqxj-h4r2" + }, + { + "reference_id": "", + "reference_type": "", + "url": "https://github.com/aio-libs/aiohttp/security/advisories/GHSA-8qpw-xqxj-h4r2" + }, + { + "reference_id": "", + "reference_type": "", + "url": "https://github.com/aio-libs/aiohttp/pull/8074" + }, + { + "reference_id": "", + "reference_type": "", + "url": "https://github.com/aio-libs/aiohttp/commit/33ccdfb0a12690af5bb49bda2319ec0907fa7827" + }, + { + "reference_id": "", + "reference_type": "", + "url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/XXWVZIVAYWEBHNRIILZVB3R3SDQNNAA7/" + } + ], + "patches": [], + "severities": [ + { + "system": "cvssv3.1", + "value": "6.5", + "scoring_elements": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:L" + } + ], + "date_published": "2024-01-29T23:15:00+00:00", + "weaknesses": [], + "url": "https://test.com" +} \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-4.json b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-4.json new file mode 100644 index 000000000..4bcafaa71 --- /dev/null +++ b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-4.json @@ -0,0 +1,67 @@ +{ + "advisory_id": "PYSEC-2022-43068", + "aliases": [ + "CVE-2021-3702", + "GHSA-772j-xvf9-qpf5" + ], + "summary": "A race condition flaw was found in ansible-runner, where an attacker could watch for rapid creation and deletion of a temporary directory, substitute their directory at that name, and then have access to ansible-runner's private_data_dir the next time ansible-runner made use of the private_data_dir. The highest Threat out of this flaw is to integrity and confidentiality.", + "affected_packages": [ + { + "package": { + "type": "pypi", + "namespace": "", + "name": "ansible-runner", + "version": "", + "qualifiers": "", + "subpath": "" + }, + "affected_version_range": "vers:pypi/2.0.0|>=2.0.0|2.0.1|2.0.2|2.0.3|2.0.4|2.1.0.0a1|2.1.0.0a2|2.1.0.0b1|<2.1.0", + "fixed_version_range": "vers:pypi/2.1.0", + "introduced_by_commit_patches": [], + "fixed_by_commit_patches": [] + } + ], + "references_v2": [ + { + "reference_id": "", + "reference_type": "", + "url": "https://bugzilla.redhat.com/show_bug.cgi?id=1977965" + }, + { + "reference_id": "", + "reference_type": "", + "url": "https://bugzilla.redhat.com/show_bug.cgi?id=1977965" + }, + { + "reference_id": "", + "reference_type": "", + "url": "https://bugzilla.redhat.com/show_bug.cgi?id=1977965" + }, + { + "reference_id": "", + "reference_type": "", + "url": "https://access.redhat.com/security/cve/CVE-2021-3702" + }, + { + "reference_id": "", + "reference_type": "", + "url": "https://github.com/ansible/ansible-runner/pull/742/commits" + }, + { + "reference_id": "", + "reference_type": "", + "url": "https://github.com/ansible/ansible-runner/pull/742/commits" + } + ], + "patches": [], + "severities": [ + { + "system": "cvssv3.1", + "value": "6.3", + "scoring_elements": "CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:N" + } + ], + "date_published": "2022-08-23T16:15:00+00:00", + "weaknesses": [], + "url": "https://test.com" +} \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-5.json b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-5.json new file mode 100644 index 000000000..e263545b6 --- /dev/null +++ b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-5.json @@ -0,0 +1,55 @@ +{ + "advisory_id": "PYSEC-2021-796", + "aliases": [ + "CVE-2021-37685", + "GHSA-c545-c4f9-rf6v" + ], + "summary": "TensorFlow is an end-to-end open source platform for machine learning. In affected versions TFLite's [`expand_dims.cc`](https://github.com/tensorflow/tensorflow/blob/149562d49faa709ea80df1d99fc41d005b81082a/tensorflow/lite/kernels/expand_dims.cc#L36-L50) contains a vulnerability which allows reading one element outside of bounds of heap allocated data. If `axis` is a large negative value (e.g., `-100000`), then after the first `if` it would still be negative. The check following the `if` statement will pass and the `for` loop would read one element before the start of `input_dims.data` (when `i = 0`). We have patched the issue in GitHub commit d94ffe08a65400f898241c0374e9edc6fa8ed257. The fix will be included in TensorFlow 2.6.0. We will also cherrypick this commit on TensorFlow 2.5.1, TensorFlow 2.4.3, and TensorFlow 2.3.4, as these are also affected and still in supported range.", + "affected_packages": [ + { + "package": { + "type": "pypi", + "namespace": "", + "name": "tensorflow-gpu", + "version": "", + "qualifiers": "", + "subpath": "" + }, + "affected_version_range": "vers:pypi/2.3.0|>=2.3.0|2.3.1|2.3.2|2.3.3|<2.3.4|2.4.0|>=2.4.0|2.4.1|2.4.2|<2.4.3", + "fixed_version_range": "vers:pypi/2.3.4|2.4.3", + "introduced_by_commit_patches": [ + { + "vcs_url": "https://github.com/tensorflow/tensorflow", + "commit_hash": "4b825dc642cb6eb9a060e54bf8d69288fbee4904", + "patch_text": null, + "patch_checksum": null + } + ], + "fixed_by_commit_patches": [ + { + "vcs_url": "https://github.com/tensorflow/tensorflow", + "commit_hash": "d94ffe08a65400f898241c0374e9edc6fa8ed257", + "patch_text": null, + "patch_checksum": null + } + ] + } + ], + "references_v2": [ + { + "reference_id": "", + "reference_type": "", + "url": "https://github.com/tensorflow/tensorflow/commit/d94ffe08a65400f898241c0374e9edc6fa8ed257" + }, + { + "reference_id": "", + "reference_type": "", + "url": "https://github.com/tensorflow/tensorflow/security/advisories/GHSA-c545-c4f9-rf6v" + } + ], + "patches": [], + "severities": [], + "date_published": "2021-08-12T23:15:00+00:00", + "weaknesses": [], + "url": "https://test.com" +} \ No newline at end of file diff --git a/vulnerabilities/tests/test_osv_v2.py b/vulnerabilities/tests/test_osv_v2.py new file mode 100644 index 000000000..397c8831f --- /dev/null +++ b/vulnerabilities/tests/test_osv_v2.py @@ -0,0 +1,111 @@ +# +# 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/aboutcode-org/vulnerablecode for support or download. +# See https://aboutcode.org for more information about nexB OSS projects. +# +import json +import os +from unittest import TestCase + +import saneyaml + +from vulnerabilities.importers.osv_v2 import parse_advisory_data_v3 +from vulnerabilities.tests import util_tests + +BASE_DIR = os.path.dirname(os.path.abspath(__file__)) +TEST_DATA = os.path.join(BASE_DIR, "test_data/osv_test") + + +class TestOSVImporter(TestCase): + def test_to_advisories_github1(self): + with open(os.path.join(TEST_DATA, "github/github-1.json")) as f: + mock_response = json.load(f) + expected_file = os.path.join(TEST_DATA, "github/github-expected-1.json") + imported_data = parse_advisory_data_v3( + mock_response, "maven", advisory_url="https://test.com", advisory_text="" + ) + result = imported_data.to_dict() + util_tests.check_results_against_json(result, expected_file) + + def test_to_advisories_github2(self): + with open(os.path.join(TEST_DATA, "github/github-2.json")) as f: + mock_response = json.load(f) + expected_file = os.path.join(TEST_DATA, "github/github-expected-2.json") + imported_data = parse_advisory_data_v3( + mock_response, "packagist", advisory_url="https://test.com", advisory_text="" + ) + result = imported_data.to_dict() + util_tests.check_results_against_json(result, expected_file) + + def test_to_advisories_oss_fuzz1(self): + with open(os.path.join(TEST_DATA, "oss-fuzz/oss-fuzz-1.yaml")) as f: + mock_response = saneyaml.load(f) + expected_file = os.path.join(TEST_DATA, "oss-fuzz/oss-fuzz-expected-1.json") + imported_data = parse_advisory_data_v3( + mock_response, "generic", advisory_url="https://test.com", advisory_text="" + ) + result = imported_data.to_dict() + util_tests.check_results_against_json(result, expected_file) + + def test_to_advisories_oss_fuzz2(self): + with open(os.path.join(TEST_DATA, "oss-fuzz/oss-fuzz-2.yaml")) as f: + mock_response = saneyaml.load(f) + expected_file = os.path.join(TEST_DATA, "oss-fuzz/oss-fuzz-expected-2.json") + imported_data = parse_advisory_data_v3( + mock_response, "generic", advisory_url="https://test.com", advisory_text="" + ) + result = imported_data.to_dict() + util_tests.check_results_against_json(result, expected_file) + + def test_to_advisories_pypa1(self): + with open(os.path.join(TEST_DATA, "pypa/pypa-1.yaml")) as f: + mock_response = saneyaml.load(f) + expected_file = os.path.join(TEST_DATA, "pypa/pypa-expected-1.json") + imported_data = parse_advisory_data_v3( + mock_response, "pypi", advisory_url="https://test.com", advisory_text="" + ) + result = imported_data.to_dict() + util_tests.check_results_against_json(result, expected_file) + + def test_to_advisories_pypa2(self): + with open(os.path.join(TEST_DATA, "pypa/pypa-2.yaml")) as f: + mock_response = saneyaml.load(f) + expected_file = os.path.join(TEST_DATA, "pypa/pypa-expected-2.json") + imported_data = parse_advisory_data_v3( + mock_response, "pypi", advisory_url="https://test.com", advisory_text="" + ) + result = imported_data.to_dict() + util_tests.check_results_against_json(result, expected_file) + + def test_to_advisories_pypa3(self): + with open(os.path.join(TEST_DATA, "pypa/pypa-3.yaml")) as f: + mock_response = saneyaml.load(f) + expected_file = os.path.join(TEST_DATA, "pypa/pypa-expected-3.json") + imported_data = parse_advisory_data_v3( + mock_response, "pypi", advisory_url="https://test.com", advisory_text="" + ) + result = imported_data.to_dict() + util_tests.check_results_against_json(result, expected_file) + + def test_to_advisories_pypa4(self): + with open(os.path.join(TEST_DATA, "pypa/pypa-4.yaml")) as f: + mock_response = saneyaml.load(f) + expected_file = os.path.join(TEST_DATA, "pypa/pypa-expected-4.json") + imported_data = parse_advisory_data_v3( + mock_response, "pypi", advisory_url="https://test.com", advisory_text="" + ) + result = imported_data.to_dict() + util_tests.check_results_against_json(result, expected_file) + + def test_to_advisories_pypa5(self): + with open(os.path.join(TEST_DATA, "pypa/pypa-5.yaml")) as f: + mock_response = saneyaml.load(f) + expected_file = os.path.join(TEST_DATA, "pypa/pypa-expected-5.json") + imported_data = parse_advisory_data_v3( + mock_response, "pypi", advisory_url="https://test.com", advisory_text="" + ) + result = imported_data.to_dict() + util_tests.check_results_against_json(result, expected_file) From 058a6f3da5b52f7e1b351da56bf5c88509ee313d Mon Sep 17 00:00:00 2001 From: ziad hany Date: Tue, 23 Dec 2025 10:44:40 +0200 Subject: [PATCH 2/6] Add more tests. Use parse_advisory_data_v3 for GitHub OSV. Signed-off-by: ziad hany --- vulnerabilities/importers/osv_v2.py | 61 +++-- .../v2_importers/github_osv_importer.py | 2 - .../pipelines/v2_importers/oss_fuzz.py | 2 - .../pipelines/v2_importers/pysec_importer.py | 4 +- .../tests/test_data/osv_test/pypa/pypa-5.yaml | 76 +++--- .../tests/test_data/osv_test/pypa/pypa-6.yaml | 255 ++++++++++++++++++ .../osv_test/pypa/pypa-expected-5.json | 66 ++++- .../osv_test/pypa/pypa-expected-6.json | 103 +++++++ vulnerabilities/tests/test_osv_v2.py | 10 + 9 files changed, 503 insertions(+), 76 deletions(-) create mode 100644 vulnerabilities/tests/test_data/osv_test/pypa/pypa-6.yaml create mode 100644 vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-6.json diff --git a/vulnerabilities/importers/osv_v2.py b/vulnerabilities/importers/osv_v2.py index dbbe3e096..2402cb93a 100644 --- a/vulnerabilities/importers/osv_v2.py +++ b/vulnerabilities/importers/osv_v2.py @@ -17,7 +17,7 @@ from cvss.exceptions import CVSS3MalformedError from cvss.exceptions import CVSS4MalformedError from packageurl import PackageURL -from univers.version_constraint import VersionConstraint +from univers.version_constraint import VersionConstraint, validate_comparators from univers.version_range import RANGE_CLASS_BY_SCHEMES from univers.versions import InvalidVersion from univers.versions import SemverVersion @@ -152,15 +152,18 @@ def parse_advisory_data_v3( or fixed_by_commit_patches or introduced_by_commit_patches ): - affected_packages.append( - AffectedPackageV2( - package=purl, - affected_version_range=affected_version_range, - fixed_version_range=fixed_version_range, - fixed_by_commit_patches=fixed_by_commit_patches, - introduced_by_commit_patches=introduced_by_commit_patches, + try: + affected_packages.append( + AffectedPackageV2( + package=purl, + affected_version_range=affected_version_range, + fixed_version_range=fixed_version_range, + fixed_by_commit_patches=fixed_by_commit_patches, + introduced_by_commit_patches=introduced_by_commit_patches, + ) ) - ) + except Exception as e: + logger.error(f"Invalid AffectedPackageV2 {e} for {advisory_id}") database_specific = raw_data.get("database_specific") or {} cwe_ids = database_specific.get("cwe_ids") or [] @@ -168,20 +171,22 @@ def parse_advisory_data_v3( if advisory_id in aliases: aliases.remove(advisory_id) - - return AdvisoryData( - advisory_id=advisory_id, - aliases=aliases, - summary=summary, - references_v2=references, - severities=severities, - affected_packages=affected_packages, - date_published=date_published, - weaknesses=weaknesses, - patches=patches, - url=advisory_url, - original_advisory_text=advisory_text or json.dumps(raw_data, indent=2, ensure_ascii=False), - ) + try: + return AdvisoryData( + advisory_id=advisory_id, + aliases=aliases, + summary=summary, + references_v2=references, + severities=severities, + affected_packages=affected_packages, + date_published=date_published, + weaknesses=weaknesses, + patches=patches, + url=advisory_url, + original_advisory_text=advisory_text or json.dumps(raw_data, indent=2, ensure_ascii=False), + ) + except Exception as e: + logger.error(f"Invalid AdvisoryData for {advisory_id}: {e}") def extract_events(range_data) -> Iterable[str]: @@ -335,12 +340,18 @@ def get_explicit_affected_constraints(affected_pkg, raw_id, supported_ecosystem) version_obj = version_range_class.version_class(version) constraint = VersionConstraint(comparator="=", version=version_obj) constraints.append(constraint) + validate_comparators(constraints) except Exception as e: logger.error( - f"Invalid VersionRange for affected_pkg: {affected_pkg} " - f"for OSV id: {raw_id!r}: error:{e!r}" + f"Invalid VersionConstraint: {version} " f"for OSV id: {raw_id!r}: error:{e!r}" ) + try: + validate_comparators(constraints) + except Exception as e: + logger.error( + f"InvalidConstraint: {version} " f"for OSV id: {raw_id!r}: error:{e!r}" + ) return constraints diff --git a/vulnerabilities/pipelines/v2_importers/github_osv_importer.py b/vulnerabilities/pipelines/v2_importers/github_osv_importer.py index 88c2616b1..ae195ec9b 100644 --- a/vulnerabilities/pipelines/v2_importers/github_osv_importer.py +++ b/vulnerabilities/pipelines/v2_importers/github_osv_importer.py @@ -48,8 +48,6 @@ def advisories_count(self): return sum(1 for _ in advisory_dir.rglob("*.json")) def collect_advisories(self) -> Iterable[AdvisoryData]: - from vulnerabilities.importers.osv import parse_advisory_data_v2 - supported_ecosystems = [ "pypi", "npm", diff --git a/vulnerabilities/pipelines/v2_importers/oss_fuzz.py b/vulnerabilities/pipelines/v2_importers/oss_fuzz.py index a8ae41959..e86162292 100644 --- a/vulnerabilities/pipelines/v2_importers/oss_fuzz.py +++ b/vulnerabilities/pipelines/v2_importers/oss_fuzz.py @@ -44,8 +44,6 @@ def advisories_count(self): return sum(1 for _ in vulns_directory.rglob("*.yaml")) def collect_advisories(self) -> Iterable[AdvisoryData]: - from vulnerabilities.importers.osv import parse_advisory_data_v2 - base_directory = Path(self.vcs_response.dest_dir) vulns_directory = base_directory / "vulns" diff --git a/vulnerabilities/pipelines/v2_importers/pysec_importer.py b/vulnerabilities/pipelines/v2_importers/pysec_importer.py index bea79cb98..52d58c75b 100644 --- a/vulnerabilities/pipelines/v2_importers/pysec_importer.py +++ b/vulnerabilities/pipelines/v2_importers/pysec_importer.py @@ -15,6 +15,7 @@ import requests from vulnerabilities.importer import AdvisoryData +from vulnerabilities.importers.osv_v2 import parse_advisory_data_v3 from vulnerabilities.pipelines import VulnerableCodeBaseImporterPipelineV2 @@ -47,7 +48,6 @@ def advisories_count(self) -> int: def collect_advisories(self) -> Iterable[AdvisoryData]: """Yield AdvisoryData using a zipped data dump of OSV data""" - from vulnerabilities.importers.osv import parse_advisory_data_v2 with ZipFile(BytesIO(self.advisory_zip)) as zip_file: for file_name in zip_file.namelist(): @@ -60,7 +60,7 @@ def collect_advisories(self) -> Iterable[AdvisoryData]: with zip_file.open(file_name) as f: vul_info = json.load(f) advisory_text = f.read() - yield parse_advisory_data_v2( + yield parse_advisory_data_v3( raw_data=vul_info, supported_ecosystems=["pypi"], advisory_url=self.url, diff --git a/vulnerabilities/tests/test_data/osv_test/pypa/pypa-5.yaml b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-5.yaml index 8fc994762..d63f2ba44 100644 --- a/vulnerabilities/tests/test_data/osv_test/pypa/pypa-5.yaml +++ b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-5.yaml @@ -1,46 +1,58 @@ -id: PYSEC-2021-796 -details: TensorFlow is an end-to-end open source platform for machine learning. In - affected versions TFLite's [`expand_dims.cc`](https://github.com/tensorflow/tensorflow/blob/149562d49faa709ea80df1d99fc41d005b81082a/tensorflow/lite/kernels/expand_dims.cc#L36-L50) - contains a vulnerability which allows reading one element outside of bounds of heap - allocated data. If `axis` is a large negative value (e.g., `-100000`), then after - the first `if` it would still be negative. The check following the `if` statement - will pass and the `for` loop would read one element before the start of `input_dims.data` - (when `i = 0`). We have patched the issue in GitHub commit d94ffe08a65400f898241c0374e9edc6fa8ed257. - The fix will be included in TensorFlow 2.6.0. We will also cherrypick this commit - on TensorFlow 2.5.1, TensorFlow 2.4.3, and TensorFlow 2.3.4, as these are also affected - and still in supported range. +id: PYSEC-2017-94 +details: Heap-based buffer overflow in the ALGnew function in block_templace.c in + Python Cryptography Toolkit (aka pycrypto) allows remote attackers to execute arbitrary + code as demonstrated by a crafted iv parameter to cryptmsg.py. affected: - package: - name: tensorflow-gpu + name: pycrypto ecosystem: PyPI - purl: pkg:pypi/tensorflow-gpu + purl: pkg:pypi/pycrypto ranges: - type: GIT - repo: https://github.com/tensorflow/tensorflow + repo: https://github.com/dlitz/pycrypto events: - - introduced: "0" - - fixed: d94ffe08a65400f898241c0374e9edc6fa8ed257 + - introduced: '0' + - fixed: 8dbe0dc3eea5c689d4f76b37b93fe216cf1f00d4 - type: ECOSYSTEM events: - - introduced: 2.3.0 - - fixed: 2.3.4 - - introduced: 2.4.0 - - fixed: 2.4.3 + - introduced: '0' versions: - - 2.3.0 - - 2.3.1 - - 2.3.2 - - 2.3.3 - - 2.4.0 + - 1.9a2 + - 1.9a5 + - 1.9a6 + - '2.0' + - 2.0.1 + - 2.1.0 + - '2.2' + - '2.3' + - '2.4' - 2.4.1 - - 2.4.2 + - '2.5' + - '2.6' + - 2.6.1 references: +- type: WEB + url: https://pony7.fr/ctf:public:32c3:cryptmsg +- type: WEB + url: https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/RJ37R2YLX56YZABFNAOWV4VTHTGYREAE/ +- type: WEB + url: https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/C6BWNADPLKDBBQBUT3P75W7HAJCE7M3B/ +- type: REPORT + url: https://github.com/dlitz/pycrypto/issues/176 - type: FIX - url: https://github.com/tensorflow/tensorflow/commit/d94ffe08a65400f898241c0374e9edc6fa8ed257 + url: https://github.com/dlitz/pycrypto/commit/8dbe0dc3eea5c689d4f76b37b93fe216cf1f00d4 +- type: REPORT + url: https://bugzilla.redhat.com/show_bug.cgi?id=1409754 +- type: WEB + url: http://www.securityfocus.com/bid/95122 +- type: WEB + url: http://www.openwall.com/lists/oss-security/2016/12/27/8 - type: ADVISORY - url: https://github.com/tensorflow/tensorflow/security/advisories/GHSA-c545-c4f9-rf6v + url: https://security.gentoo.org/glsa/201702-14 +- type: ADVISORY + url: https://github.com/advisories/GHSA-cq27-v7xp-c356 aliases: -- CVE-2021-37685 -- GHSA-c545-c4f9-rf6v -modified: "2021-12-09T06:35:39.778016Z" -published: "2021-08-12T23:15:00Z" \ No newline at end of file +- CVE-2013-7459 +- GHSA-cq27-v7xp-c356 +modified: '2021-08-27T03:22:16.665546Z' +published: '2017-02-15T15:59:00Z' \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/osv_test/pypa/pypa-6.yaml b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-6.yaml new file mode 100644 index 000000000..95d086f11 --- /dev/null +++ b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-6.yaml @@ -0,0 +1,255 @@ +id: PYSEC-2023-56 +details: Wagtail is an open source content management system built on Django. Prior + to versions 4.1.4 and 4.2.2, a memory exhaustion bug exists in Wagtail's handling + of uploaded images and documents. For both images and documents, files are loaded + into memory during upload for additional processing. A user with access to upload + images or documents through the Wagtail admin interface could upload a file so large + that it results in a crash of denial of service. The vulnerability is not exploitable + by an ordinary site visitor without access to the Wagtail admin. It can only be + exploited by admin users with permission to upload images or documents. Image uploads + are restricted to 10MB by default, however this validation only happens on the frontend + and on the backend after the vulnerable code. Patched versions have been released + as Wagtail 4.1.4 and Wagtail 4.2.2). Site owners who are unable to upgrade to the + new versions are encouraged to add extra protections outside of Wagtail to limit + the size of uploaded files. +affected: +- package: + name: wagtail + ecosystem: PyPI + purl: pkg:pypi/wagtail + ranges: + - type: GIT + repo: https://github.com/wagtail/wagtail + events: + - introduced: "0" + - fixed: cfa11bbe00dbe7ce8cd4c0bbfe2a898a690df2bf + - fixed: 3c0c64642b9e5b8d28b111263c7f4bddad6c3880 + - fixed: c9d2fcd650a88d76ae122646142245e5927a9165 + - fixed: d4022310cbe497993459c3136311467c7ac6329a + - type: ECOSYSTEM + events: + - introduced: "4.2" + - fixed: 4.2.2 + - introduced: "0" + - fixed: 4.1.4 + versions: + - "0.1" + - "0.2" + - "0.3" + - 0.3.1 + - "0.4" + - 0.4.1 + - "0.5" + - "0.6" + - "0.7" + - "0.8" + - 0.8.1 + - 0.8.10 + - 0.8.2 + - 0.8.3 + - 0.8.4 + - 0.8.5 + - 0.8.6 + - 0.8.7 + - 0.8.8 + - 0.8.9 + - "1.0" + - 1.0b1 + - 1.0b2 + - 1.0rc1 + - 1.0rc2 + - "1.1" + - "1.10" + - 1.10.1 + - 1.10rc1 + - "1.11" + - 1.11.1 + - 1.11rc1 + - "1.12" + - 1.12.1 + - 1.12.2 + - 1.12.3 + - 1.12.4 + - 1.12.5 + - 1.12.6 + - 1.12rc1 + - "1.13" + - 1.13.1 + - 1.13.2 + - 1.13.3 + - 1.13.4 + - 1.13rc1 + - 1.1rc1 + - "1.2" + - 1.2rc1 + - "1.3" + - 1.3.1 + - 1.3rc1 + - "1.4" + - 1.4.1 + - 1.4.2 + - 1.4.3 + - 1.4.4 + - 1.4.5 + - 1.4.6 + - 1.4rc1 + - "1.5" + - 1.5.1 + - 1.5.2 + - 1.5.3 + - 1.5rc1 + - "1.6" + - 1.6.1 + - 1.6.2 + - 1.6.3 + - 1.6rc1 + - "1.7" + - 1.7rc1 + - "1.8" + - 1.8.1 + - 1.8.2 + - 1.8rc1 + - "1.9" + - 1.9.1 + - 1.9rc1 + - "2.0" + - 2.0.1 + - 2.0.2 + - 2.0b1 + - 2.0rc1 + - "2.1" + - 2.1.1 + - 2.1.2 + - 2.1.3 + - "2.10" + - 2.10.1 + - 2.10.2 + - 2.10rc1 + - 2.10rc2 + - "2.11" + - 2.11.1 + - 2.11.2 + - 2.11.3 + - 2.11.4 + - 2.11.5 + - 2.11.6 + - 2.11.7 + - 2.11.8 + - 2.11.9 + - 2.11rc1 + - "2.12" + - 2.12.1 + - 2.12.2 + - 2.12.3 + - 2.12.4 + - 2.12.5 + - 2.12.6 + - 2.12rc1 + - "2.13" + - 2.13.1 + - 2.13.2 + - 2.13.3 + - 2.13.4 + - 2.13.5 + - 2.13rc1 + - 2.13rc2 + - 2.13rc3 + - "2.14" + - 2.14.1 + - 2.14.2 + - 2.14rc1 + - "2.15" + - 2.15.1 + - 2.15.2 + - 2.15.3 + - 2.15.4 + - 2.15.5 + - 2.15.6 + - 2.15rc1 + - 2.15rc2 + - "2.16" + - 2.16.1 + - 2.16.2 + - 2.16.3 + - 2.16rc1 + - 2.16rc2 + - 2.1rc1 + - 2.1rc2 + - "2.2" + - 2.2.1 + - 2.2.2 + - 2.2rc1 + - 2.2rc2 + - "2.3" + - 2.3rc1 + - 2.3rc2 + - "2.4" + - 2.4rc1 + - "2.5" + - 2.5.1 + - 2.5.2 + - 2.5rc1 + - "2.6" + - 2.6.1 + - 2.6.2 + - 2.6.3 + - 2.6rc1 + - "2.7" + - 2.7.1 + - 2.7.2 + - 2.7.3 + - 2.7.4 + - 2.7rc1 + - 2.7rc2 + - "2.8" + - 2.8.1 + - 2.8.2 + - 2.8rc1 + - "2.9" + - 2.9.1 + - 2.9.2 + - 2.9.3 + - 2.9rc1 + - "3.0" + - 3.0.1 + - 3.0.2 + - 3.0.3 + - 3.0rc1 + - 3.0rc2 + - 3.0rc3 + - "4.0" + - 4.0.1 + - 4.0.2 + - 4.0.3 + - 4.0.4 + - 4.0rc1 + - 4.0rc2 + - "4.1" + - 4.1.1 + - 4.1.2 + - 4.1.3 + - 4.1rc1 + - "4.2" + - 4.2.1 +references: +- type: FIX + url: https://github.com/wagtail/wagtail/commit/cfa11bbe00dbe7ce8cd4c0bbfe2a898a690df2bf +- type: WEB + url: https://github.com/wagtail/wagtail/releases/tag/v4.2.2 +- type: FIX + url: https://github.com/wagtail/wagtail/commit/3c0c64642b9e5b8d28b111263c7f4bddad6c3880 +- type: ADVISORY + url: https://github.com/wagtail/wagtail/security/advisories/GHSA-33pv-vcgh-jfg9 +- type: WEB + url: https://docs.wagtail.org/en/stable/reference/settings.html#wagtailimages-max-upload-size +- type: FIX + url: https://github.com/wagtail/wagtail/commit/c9d2fcd650a88d76ae122646142245e5927a9165 +- type: FIX + url: https://github.com/wagtail/wagtail/commit/d4022310cbe497993459c3136311467c7ac6329a +- type: WEB + url: https://github.com/wagtail/wagtail/releases/tag/v4.1.4 +aliases: +- CVE-2023-28837 +- GHSA-33pv-vcgh-jfg9 +modified: "2023-05-04T03:49:48.874145Z" +published: "2023-04-03T17:15:00Z" \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-5.json b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-5.json index e263545b6..8335da744 100644 --- a/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-5.json +++ b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-5.json @@ -1,25 +1,25 @@ { - "advisory_id": "PYSEC-2021-796", + "advisory_id": "PYSEC-2017-94", "aliases": [ - "CVE-2021-37685", - "GHSA-c545-c4f9-rf6v" + "CVE-2013-7459", + "GHSA-cq27-v7xp-c356" ], - "summary": "TensorFlow is an end-to-end open source platform for machine learning. In affected versions TFLite's [`expand_dims.cc`](https://github.com/tensorflow/tensorflow/blob/149562d49faa709ea80df1d99fc41d005b81082a/tensorflow/lite/kernels/expand_dims.cc#L36-L50) contains a vulnerability which allows reading one element outside of bounds of heap allocated data. If `axis` is a large negative value (e.g., `-100000`), then after the first `if` it would still be negative. The check following the `if` statement will pass and the `for` loop would read one element before the start of `input_dims.data` (when `i = 0`). We have patched the issue in GitHub commit d94ffe08a65400f898241c0374e9edc6fa8ed257. The fix will be included in TensorFlow 2.6.0. We will also cherrypick this commit on TensorFlow 2.5.1, TensorFlow 2.4.3, and TensorFlow 2.3.4, as these are also affected and still in supported range.", + "summary": "Heap-based buffer overflow in the ALGnew function in block_templace.c in Python Cryptography Toolkit (aka pycrypto) allows remote attackers to execute arbitrary code as demonstrated by a crafted iv parameter to cryptmsg.py.", "affected_packages": [ { "package": { "type": "pypi", "namespace": "", - "name": "tensorflow-gpu", + "name": "pycrypto", "version": "", "qualifiers": "", "subpath": "" }, - "affected_version_range": "vers:pypi/2.3.0|>=2.3.0|2.3.1|2.3.2|2.3.3|<2.3.4|2.4.0|>=2.4.0|2.4.1|2.4.2|<2.4.3", - "fixed_version_range": "vers:pypi/2.3.4|2.4.3", + "affected_version_range": "vers:pypi/>=0|1.9a2|1.9a5|1.9a6|2.0|2.0.1|2.1.0|2.2|2.3|2.4|2.4.1|2.5|2.6|2.6.1", + "fixed_version_range": null, "introduced_by_commit_patches": [ { - "vcs_url": "https://github.com/tensorflow/tensorflow", + "vcs_url": "https://github.com/dlitz/pycrypto", "commit_hash": "4b825dc642cb6eb9a060e54bf8d69288fbee4904", "patch_text": null, "patch_checksum": null @@ -27,8 +27,8 @@ ], "fixed_by_commit_patches": [ { - "vcs_url": "https://github.com/tensorflow/tensorflow", - "commit_hash": "d94ffe08a65400f898241c0374e9edc6fa8ed257", + "vcs_url": "https://github.com/dlitz/pycrypto", + "commit_hash": "8dbe0dc3eea5c689d4f76b37b93fe216cf1f00d4", "patch_text": null, "patch_checksum": null } @@ -39,17 +39,57 @@ { "reference_id": "", "reference_type": "", - "url": "https://github.com/tensorflow/tensorflow/commit/d94ffe08a65400f898241c0374e9edc6fa8ed257" + "url": "https://pony7.fr/ctf:public:32c3:cryptmsg" }, { "reference_id": "", "reference_type": "", - "url": "https://github.com/tensorflow/tensorflow/security/advisories/GHSA-c545-c4f9-rf6v" + "url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/RJ37R2YLX56YZABFNAOWV4VTHTGYREAE/" + }, + { + "reference_id": "", + "reference_type": "", + "url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/C6BWNADPLKDBBQBUT3P75W7HAJCE7M3B/" + }, + { + "reference_id": "", + "reference_type": "", + "url": "https://github.com/dlitz/pycrypto/issues/176" + }, + { + "reference_id": "", + "reference_type": "", + "url": "https://github.com/dlitz/pycrypto/commit/8dbe0dc3eea5c689d4f76b37b93fe216cf1f00d4" + }, + { + "reference_id": "", + "reference_type": "", + "url": "https://bugzilla.redhat.com/show_bug.cgi?id=1409754" + }, + { + "reference_id": "", + "reference_type": "", + "url": "http://www.securityfocus.com/bid/95122" + }, + { + "reference_id": "", + "reference_type": "", + "url": "http://www.openwall.com/lists/oss-security/2016/12/27/8" + }, + { + "reference_id": "", + "reference_type": "", + "url": "https://security.gentoo.org/glsa/201702-14" + }, + { + "reference_id": "", + "reference_type": "", + "url": "https://github.com/advisories/GHSA-cq27-v7xp-c356" } ], "patches": [], "severities": [], - "date_published": "2021-08-12T23:15:00+00:00", + "date_published": "2017-02-15T15:59:00+00:00", "weaknesses": [], "url": "https://test.com" } \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-6.json b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-6.json new file mode 100644 index 000000000..8f5075fc2 --- /dev/null +++ b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-6.json @@ -0,0 +1,103 @@ +{ + "advisory_id": "PYSEC-2023-56", + "aliases": [ + "CVE-2023-28837", + "GHSA-33pv-vcgh-jfg9" + ], + "summary": "Wagtail is an open source content management system built on Django. Prior to versions 4.1.4 and 4.2.2, a memory exhaustion bug exists in Wagtail's handling of uploaded images and documents. For both images and documents, files are loaded into memory during upload for additional processing. A user with access to upload images or documents through the Wagtail admin interface could upload a file so large that it results in a crash of denial of service. The vulnerability is not exploitable by an ordinary site visitor without access to the Wagtail admin. It can only be exploited by admin users with permission to upload images or documents. Image uploads are restricted to 10MB by default, however this validation only happens on the frontend and on the backend after the vulnerable code. Patched versions have been released as Wagtail 4.1.4 and Wagtail 4.2.2). Site owners who are unable to upgrade to the new versions are encouraged to add extra protections outside of Wagtail to limit the size of uploaded files.", + "affected_packages": [ + { + "package": { + "type": "pypi", + "namespace": "", + "name": "wagtail", + "version": "", + "qualifiers": "", + "subpath": "" + }, + "affected_version_range": "vers:pypi/>=0|0.1|0.2|0.3|0.3.1|0.4|0.4.1|0.5|0.6|0.7|0.8|0.8.1|0.8.2|0.8.3|0.8.4|0.8.5|0.8.6|0.8.7|0.8.8|0.8.9|0.8.10|1.0b1|1.0b2|1.0rc1|1.0rc2|1.0|1.1rc1|1.1|1.2rc1|1.2|1.3rc1|1.3|1.3.1|1.4rc1|1.4|1.4.1|1.4.2|1.4.3|1.4.4|1.4.5|1.4.6|1.5rc1|1.5|1.5.1|1.5.2|1.5.3|1.6rc1|1.6|1.6.1|1.6.2|1.6.3|1.7rc1|1.7|1.8rc1|1.8|1.8.1|1.8.2|1.9rc1|1.9|1.9.1|1.10rc1|1.10|1.10.1|1.11rc1|1.11|1.11.1|1.12rc1|1.12|1.12.1|1.12.2|1.12.3|1.12.4|1.12.5|1.12.6|1.13rc1|1.13|1.13.1|1.13.2|1.13.3|1.13.4|2.0b1|2.0rc1|2.0|2.0.1|2.0.2|2.1rc1|2.1rc2|2.1|2.1.1|2.1.2|2.1.3|2.2rc1|2.2rc2|2.2|2.2.1|2.2.2|2.3rc1|2.3rc2|2.3|2.4rc1|2.4|2.5rc1|2.5|2.5.1|2.5.2|2.6rc1|2.6|2.6.1|2.6.2|2.6.3|2.7rc1|2.7rc2|2.7|2.7.1|2.7.2|2.7.3|2.7.4|2.8rc1|2.8|2.8.1|2.8.2|2.9rc1|2.9|2.9.1|2.9.2|2.9.3|2.10rc1|2.10rc2|2.10|2.10.1|2.10.2|2.11rc1|2.11|2.11.1|2.11.2|2.11.3|2.11.4|2.11.5|2.11.6|2.11.7|2.11.8|2.11.9|2.12rc1|2.12|2.12.1|2.12.2|2.12.3|2.12.4|2.12.5|2.12.6|2.13rc1|2.13rc2|2.13rc3|2.13|2.13.1|2.13.2|2.13.3|2.13.4|2.13.5|2.14rc1|2.14|2.14.1|2.14.2|2.15rc1|2.15rc2|2.15|2.15.1|2.15.2|2.15.3|2.15.4|2.15.5|2.15.6|2.16rc1|2.16rc2|2.16|2.16.1|2.16.2|2.16.3|3.0rc1|3.0rc2|3.0rc3|3.0|3.0.1|3.0.2|3.0.3|4.0rc1|4.0rc2|4.0|4.0.1|4.0.2|4.0.3|4.0.4|4.1rc1|4.1|4.1.1|4.1.2|4.1.3|<4.1.4|4.2|>=4.2|4.2.1|<4.2.2", + "fixed_version_range": "vers:pypi/4.1.4|4.2.2", + "introduced_by_commit_patches": [ + { + "vcs_url": "https://github.com/wagtail/wagtail", + "commit_hash": "4b825dc642cb6eb9a060e54bf8d69288fbee4904", + "patch_text": null, + "patch_checksum": null + } + ], + "fixed_by_commit_patches": [ + { + "vcs_url": "https://github.com/wagtail/wagtail", + "commit_hash": "cfa11bbe00dbe7ce8cd4c0bbfe2a898a690df2bf", + "patch_text": null, + "patch_checksum": null + }, + { + "vcs_url": "https://github.com/wagtail/wagtail", + "commit_hash": "3c0c64642b9e5b8d28b111263c7f4bddad6c3880", + "patch_text": null, + "patch_checksum": null + }, + { + "vcs_url": "https://github.com/wagtail/wagtail", + "commit_hash": "c9d2fcd650a88d76ae122646142245e5927a9165", + "patch_text": null, + "patch_checksum": null + }, + { + "vcs_url": "https://github.com/wagtail/wagtail", + "commit_hash": "d4022310cbe497993459c3136311467c7ac6329a", + "patch_text": null, + "patch_checksum": null + } + ] + } + ], + "references_v2": [ + { + "reference_id": "", + "reference_type": "", + "url": "https://github.com/wagtail/wagtail/commit/cfa11bbe00dbe7ce8cd4c0bbfe2a898a690df2bf" + }, + { + "reference_id": "", + "reference_type": "", + "url": "https://github.com/wagtail/wagtail/releases/tag/v4.2.2" + }, + { + "reference_id": "", + "reference_type": "", + "url": "https://github.com/wagtail/wagtail/commit/3c0c64642b9e5b8d28b111263c7f4bddad6c3880" + }, + { + "reference_id": "", + "reference_type": "", + "url": "https://github.com/wagtail/wagtail/security/advisories/GHSA-33pv-vcgh-jfg9" + }, + { + "reference_id": "", + "reference_type": "", + "url": "https://docs.wagtail.org/en/stable/reference/settings.html#wagtailimages-max-upload-size" + }, + { + "reference_id": "", + "reference_type": "", + "url": "https://github.com/wagtail/wagtail/commit/c9d2fcd650a88d76ae122646142245e5927a9165" + }, + { + "reference_id": "", + "reference_type": "", + "url": "https://github.com/wagtail/wagtail/commit/d4022310cbe497993459c3136311467c7ac6329a" + }, + { + "reference_id": "", + "reference_type": "", + "url": "https://github.com/wagtail/wagtail/releases/tag/v4.1.4" + } + ], + "patches": [], + "severities": [], + "date_published": "2023-04-03T17:15:00+00:00", + "weaknesses": [], + "url": "https://test.com" +} \ No newline at end of file diff --git a/vulnerabilities/tests/test_osv_v2.py b/vulnerabilities/tests/test_osv_v2.py index 397c8831f..da33b1b82 100644 --- a/vulnerabilities/tests/test_osv_v2.py +++ b/vulnerabilities/tests/test_osv_v2.py @@ -109,3 +109,13 @@ def test_to_advisories_pypa5(self): ) result = imported_data.to_dict() util_tests.check_results_against_json(result, expected_file) + + def test_to_advisories_pypa6(self): + with open(os.path.join(TEST_DATA, "pypa/pypa-6.yaml")) as f: + mock_response = saneyaml.load(f) + expected_file = os.path.join(TEST_DATA, "pypa/pypa-expected-6.json") + imported_data = parse_advisory_data_v3( + mock_response, "pypi", advisory_url="https://test.com", advisory_text="" + ) + result = imported_data.to_dict() + util_tests.check_results_against_json(result, expected_file) From 85d2b530eb4da7af3b410a60160030a33df4c104 Mon Sep 17 00:00:00 2001 From: ziad hany Date: Tue, 23 Dec 2025 11:42:48 +0200 Subject: [PATCH 3/6] Fix the test for osv pipelines Update the function docs osv_v2 Signed-off-by: ziad hany --- vulnerabilities/importers/osv_v2.py | 35 +++++++++++-------- .../test_pypa_importer_pipeline_v2.py | 8 +++-- .../v2_importers/test_pysec_importer_v2.py | 8 +++-- 3 files changed, 32 insertions(+), 19 deletions(-) diff --git a/vulnerabilities/importers/osv_v2.py b/vulnerabilities/importers/osv_v2.py index 2402cb93a..c9f82d15a 100644 --- a/vulnerabilities/importers/osv_v2.py +++ b/vulnerabilities/importers/osv_v2.py @@ -17,7 +17,8 @@ from cvss.exceptions import CVSS3MalformedError from cvss.exceptions import CVSS4MalformedError from packageurl import PackageURL -from univers.version_constraint import VersionConstraint, validate_comparators +from univers.version_constraint import VersionConstraint +from univers.version_constraint import validate_comparators from univers.version_range import RANGE_CLASS_BY_SCHEMES from univers.versions import InvalidVersion from univers.versions import SemverVersion @@ -119,7 +120,7 @@ def parse_advisory_data_v3( ) except Exception as e: logger.error( - f"Invalid Commit Data: repo_url:{repo_url!r} - commit_hash: {commit_hash} for OSV id: {advisory_id}" + f"Invalid Commit Data: repo_url:{repo_url!r} - commit_hash: {commit_hash} error: {e} for OSV id: {advisory_id}" ) continue for patch_obj in patch_objs: @@ -183,7 +184,8 @@ def parse_advisory_data_v3( weaknesses=weaknesses, patches=patches, url=advisory_url, - original_advisory_text=advisory_text or json.dumps(raw_data, indent=2, ensure_ascii=False), + original_advisory_text=advisory_text + or json.dumps(raw_data, indent=2, ensure_ascii=False), ) except Exception as e: logger.error(f"Invalid AdvisoryData for {advisory_id}: {e}") @@ -324,8 +326,7 @@ def get_affected_purl(affected_pkg, raw_id): def get_explicit_affected_constraints(affected_pkg, raw_id, supported_ecosystem): """ - Return a univers VersionRange for the ``affected_pkg`` package data mapping - or None. Use a ``raw_id`` OSV id and ``supported_ecosystem``. + Return a list of explicit version constraints for the ``affected_pkg`` data. """ affected_versions = affected_pkg.get("versions") or [] constraints = [] @@ -340,7 +341,6 @@ def get_explicit_affected_constraints(affected_pkg, raw_id, supported_ecosystem) version_obj = version_range_class.version_class(version) constraint = VersionConstraint(comparator="=", version=version_obj) constraints.append(constraint) - validate_comparators(constraints) except Exception as e: logger.error( f"Invalid VersionConstraint: {version} " f"for OSV id: {raw_id!r}: error:{e!r}" @@ -349,25 +349,30 @@ def get_explicit_affected_constraints(affected_pkg, raw_id, supported_ecosystem) try: validate_comparators(constraints) except Exception as e: - logger.error( - f"InvalidConstraint: {version} " f"for OSV id: {raw_id!r}: error:{e!r}" - ) + logger.error(f"InvalidConstraint: {version} " f"for OSV id: {raw_id!r}: error:{e!r}") return constraints def get_version_ranges_constraints(ranges, raw_id, supported_ecosystem): """ - Return a list of unique fixed univers Versions given a ``fixed_range`` - univers VersionRange and a ``raw_id``. + Return a tuple containing lists of affected constraints, fixed constraints, + introduced commits, and fixed commits For example:: - >>> get_version_ranges_constraints(range={}, raw_id="GHSA-j3f7-7rmc-6wqj", supported_ecosystem="pypi",) + >>> get_version_ranges_constraints(ranges={}, raw_id="GHSA-j3f7-7rmc-6wqj", supported_ecosystem="pypi") [] - >>> get_version_ranges_constraints( - ... ranges={"type": "ECOSYSTEM", "events": [{"fixed": "1.7.0"}], }, + >>> affected, fixed, intro_commits, fixed_commits = get_version_ranges_constraints( + ... ranges={"type": "ECOSYSTEM", "events": [{"fixed": "1.7.0"}]}, ... raw_id="GHSA-j3f7-7rmc-6wqj", ... supported_ecosystem="pypi", ... ) - [PypiVersion(string='1.7.0')] + >>> affected + [VersionConstraint(comparator='<', version=PypiVersion(string='1.7.0'))] + >>> fixed + [VersionConstraint(comparator='=', version=PypiVersion(string='1.7.0'))] + >>> intro_commits + [] + >>> fixed_commits + [] """ fixed_commits = [] intro_commits = [] diff --git a/vulnerabilities/tests/pipelines/v2_importers/test_pypa_importer_pipeline_v2.py b/vulnerabilities/tests/pipelines/v2_importers/test_pypa_importer_pipeline_v2.py index 20aa63387..f8fa08d17 100644 --- a/vulnerabilities/tests/pipelines/v2_importers/test_pypa_importer_pipeline_v2.py +++ b/vulnerabilities/tests/pipelines/v2_importers/test_pypa_importer_pipeline_v2.py @@ -89,7 +89,9 @@ def test_collect_advisories(mock_pathlib, mock_vcs_response, mock_fetch_via_vcs) mock_vcs_response.dest_dir = str(mock_pathlib.parent) # Mock `parse_advisory_data` to return an AdvisoryData object - with patch("vulnerabilities.importers.osv.parse_advisory_data_v2") as mock_parse: + with patch( + "vulnerabilities.pipelines.v2_importers.pypa_importer.parse_advisory_data_v3" + ) as mock_parse: mock_parse.return_value = AdvisoryData( advisory_id="CVE-2021-1234", summary="Sample PyPI vulnerability", @@ -149,7 +151,9 @@ def test_collect_advisories_with_invalid_yaml(mock_pathlib, mock_vcs_response, m mock_vcs_response.dest_dir = str(mock_pathlib.parent) - with patch("vulnerabilities.importers.osv.parse_advisory_data_v2") as mock_parse: + with patch( + "vulnerabilities.pipelines.v2_importers.pypa_importer.parse_advisory_data_v3" + ) as mock_parse: # Mock parse_advisory_data to raise an error on invalid YAML mock_parse.side_effect = saneyaml.YAMLError("Invalid YAML") diff --git a/vulnerabilities/tests/pipelines/v2_importers/test_pysec_importer_v2.py b/vulnerabilities/tests/pipelines/v2_importers/test_pysec_importer_v2.py index 33c716889..48ac7e302 100644 --- a/vulnerabilities/tests/pipelines/v2_importers/test_pysec_importer_v2.py +++ b/vulnerabilities/tests/pipelines/v2_importers/test_pysec_importer_v2.py @@ -79,7 +79,9 @@ def test_collect_advisories(mock_requests_get, mock_zip_data): pipeline.fetch_zip() # Mock the `parse_advisory_data_v2` function to return a dummy AdvisoryData - with patch("vulnerabilities.importers.osv.parse_advisory_data_v2") as mock_parse: + with patch( + "vulnerabilities.pipelines.v2_importers.pysec_importer.parse_advisory_data_v3" + ) as mock_parse: mock_parse.return_value = AdvisoryData( advisory_id="PYSEC-1234", summary="Sample PyPI advisory", @@ -117,7 +119,9 @@ def test_collect_advisories_invalid_file(mock_requests_get, mock_zip_data): pipeline.fetch_zip() # Mock the `parse_advisory_data_v2` function - with patch("vulnerabilities.importers.osv.parse_advisory_data_v2") as mock_parse: + with patch( + "vulnerabilities.pipelines.v2_importers.pysec_importer.parse_advisory_data_v3" + ) as mock_parse: mock_parse.return_value = AdvisoryData( advisory_id="PYSEC-1234", summary="Sample PyPI advisory", From 4c46a984f61971d3837b7586490dcdfe1cbc15a1 Mon Sep 17 00:00:00 2001 From: ziad hany Date: Wed, 24 Dec 2025 02:52:20 +0200 Subject: [PATCH 4/6] Fix the test for osv pipelines Fix CVSSv4 vector length issue Signed-off-by: ziad hany --- vulnerabilities/importers/osv_v2.py | 46 +++++++++++++++---- ...alter_advisoryseverity_scoring_elements.py | 22 +++++++++ vulnerabilities/models.py | 2 +- .../osv_test/github/github-expected-1.json | 2 +- .../osv_test/github/github-expected-2.json | 17 ++++++- .../osv_test/pypa/pypa-expected-1.json | 2 +- .../osv_test/pypa/pypa-expected-2.json | 2 +- .../osv_test/pypa/pypa-expected-3.json | 2 +- .../osv_test/pypa/pypa-expected-5.json | 2 +- .../osv_test/pypa/pypa-expected-6.json | 2 +- vulnerabilities/tests/test_osv_v2.py | 2 +- 11 files changed, 83 insertions(+), 18 deletions(-) create mode 100644 vulnerabilities/migrations/0106_alter_advisoryseverity_scoring_elements.py diff --git a/vulnerabilities/importers/osv_v2.py b/vulnerabilities/importers/osv_v2.py index c9f82d15a..475bf9c02 100644 --- a/vulnerabilities/importers/osv_v2.py +++ b/vulnerabilities/importers/osv_v2.py @@ -18,7 +18,6 @@ from cvss.exceptions import CVSS4MalformedError from packageurl import PackageURL from univers.version_constraint import VersionConstraint -from univers.version_constraint import validate_comparators from univers.version_range import RANGE_CLASS_BY_SCHEMES from univers.versions import InvalidVersion from univers.versions import SemverVersion @@ -90,6 +89,13 @@ def parse_advisory_data_v3( ) affected_constraints.extend(explicit_affected_constraints) + last_known_affected = get_last_known_affected__constraint( + affected_pkg=affected_pkg, + raw_id=advisory_id, + supported_ecosystem=purl.type, + ) + affected_constraints.extend(last_known_affected) + fixed_constraints = [] for r in affected_pkg.get("ranges") or []: ( @@ -345,14 +351,32 @@ def get_explicit_affected_constraints(affected_pkg, raw_id, supported_ecosystem) logger.error( f"Invalid VersionConstraint: {version} " f"for OSV id: {raw_id!r}: error:{e!r}" ) - - try: - validate_comparators(constraints) - except Exception as e: - logger.error(f"InvalidConstraint: {version} " f"for OSV id: {raw_id!r}: error:{e!r}") return constraints +def get_last_known_affected__constraint(affected_pkg, raw_id, supported_ecosystem): + """ + Return the last_known_affected_version_range from the database_specific + """ + database_specific = affected_pkg.get("database_specific") or {} + last_known_value = database_specific.get("last_known_affected_version_range") + + if not last_known_value: + return [] + + try: + version_range_class = RANGE_CLASS_BY_SCHEMES.get(supported_ecosystem) + version_range = version_range_class.from_native(last_known_value) + return version_range.constraints + + except Exception as e: + logger.error( + f"Invalid VersionConstraint in last_known_affected_version_range: {last_known_value!r} " + f"for OSV id: {raw_id!r}: error:{e!r}" + ) + return [] + + def get_version_ranges_constraints(ranges, raw_id, supported_ecosystem): """ Return a tuple containing lists of affected constraints, fixed constraints, @@ -378,7 +402,7 @@ def get_version_ranges_constraints(ranges, raw_id, supported_ecosystem): intro_commits = [] if "type" not in ranges: - logger.error(f"Invalid fixed_range type for: {ranges} for OSV id: {raw_id!r}") + logger.error(f"Invalid Range type for: {ranges} for OSV id: {raw_id!r}") return [] range_type = ranges["type"] @@ -408,10 +432,12 @@ def get_version_ranges_constraints(ranges, raw_id, supported_ecosystem): try: v_obj = version_class(event_value) except InvalidVersion: - logger.error(f"Invalid SemverVersion: {event_value!r} for OSV id: {raw_id!r}") + logger.error(f"Invalid Version: {event_value!r} for OSV id: {raw_id!r}") continue if event_type == "introduced": + if event_value == "0": + continue constraint = VersionConstraint(comparator=">=", version=v_obj) affected_constraints.append(constraint) @@ -426,7 +452,9 @@ def get_version_ranges_constraints(ranges, raw_id, supported_ecosystem): constraint = VersionConstraint(comparator="<=", version=v_obj) affected_constraints.append(constraint) else: - logger.error(f"Unsupported fixed version type: {event_value!r} for OSV id: {raw_id!r}") + logger.error( + f"Unsupported version constraint type: {event_type}:{event_value!r} for OSV id: {raw_id!r}" + ) return ( affected_constraints, diff --git a/vulnerabilities/migrations/0106_alter_advisoryseverity_scoring_elements.py b/vulnerabilities/migrations/0106_alter_advisoryseverity_scoring_elements.py new file mode 100644 index 000000000..597601f9c --- /dev/null +++ b/vulnerabilities/migrations/0106_alter_advisoryseverity_scoring_elements.py @@ -0,0 +1,22 @@ +# Generated by Django 4.2.25 on 2025-12-23 17:38 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("vulnerabilities", "0105_packagecommitpatch_patch_and_more"), + ] + + operations = [ + migrations.AlterField( + model_name="advisoryseverity", + name="scoring_elements", + field=models.CharField( + help_text="Supporting scoring elements used to compute the score values. For example a CVSS vector string as used to compute a CVSS score.", + max_length=200, + null=True, + ), + ), + ] diff --git a/vulnerabilities/models.py b/vulnerabilities/models.py index f4b21eb49..c9095422d 100644 --- a/vulnerabilities/models.py +++ b/vulnerabilities/models.py @@ -2577,7 +2577,7 @@ class AdvisorySeverity(models.Model): value = models.CharField(max_length=50, help_text="Example: 9.0, Important, High", null=True) scoring_elements = models.CharField( - max_length=150, + max_length=200, null=True, help_text="Supporting scoring elements used to compute the score values. " "For example a CVSS vector string as used to compute a CVSS score.", diff --git a/vulnerabilities/tests/test_data/osv_test/github/github-expected-1.json b/vulnerabilities/tests/test_data/osv_test/github/github-expected-1.json index 21dadd09c..5ee4a2c06 100644 --- a/vulnerabilities/tests/test_data/osv_test/github/github-expected-1.json +++ b/vulnerabilities/tests/test_data/osv_test/github/github-expected-1.json @@ -14,7 +14,7 @@ "qualifiers": "", "subpath": "" }, - "affected_version_range": "vers:maven/>=0|<7.17.16", + "affected_version_range": "vers:maven/<7.17.16", "fixed_version_range": "vers:maven/7.17.16", "introduced_by_commit_patches": [], "fixed_by_commit_patches": [] diff --git a/vulnerabilities/tests/test_data/osv_test/github/github-expected-2.json b/vulnerabilities/tests/test_data/osv_test/github/github-expected-2.json index 3660fb7bc..5087fd5dc 100644 --- a/vulnerabilities/tests/test_data/osv_test/github/github-expected-2.json +++ b/vulnerabilities/tests/test_data/osv_test/github/github-expected-2.json @@ -4,7 +4,22 @@ "CVE-2025-65103" ], "summary": "OpenSTAManager has Authenticated SQL Injection in API via 'display' parameter\n### Summary\nAn authenticated SQL Injection vulnerability in the API allows any user, regardless of permission level, to execute arbitrary SQL queries. By manipulating the `display` parameter in an API request, an attacker can exfiltrate, modify, or delete any data in the database, leading to a full system compromise.\n\n### Details\nThe vulnerability is located in the `retrieve()` method within `src/API/Manager.php`.\n\nUser input from the `display` GET parameter is processed without proper validation. The code strips the surrounding brackets `[]`, splits the string by commas, and then passes each resulting element directly into the `selectRaw()` function of the query builder.\n\n```php\n// User input from 'display' is taken without sanitization.\n$select = !empty($request['display']) ? explode(',', substr((string) $request['display'], 1, -1)) : null;\n\n// ...\n\n// The unsanitized input is passed directly to `selectRaw()`.\nforeach ($select as $s) {\n $query->selectRaw($s);\n}\n```\n\nSince `selectRaw()` is designed to execute raw SQL expressions, it executes any malicious SQL code provided in the `display` parameter.\n\n### PoC\n1. Log in to an OpenSTAManager instance as any user.\n2. Navigate to the user's profile page to obtain their personal API Token.\n3. Use this API token to send a specially crafted GET request to the API endpoint.\n\n**Time-Based Blind Injection Test:**\n\nReplace ``, ``, and `` with your actual values. `anagrafiche` is a valid resource.\n\n```bash\ncurl \"http:///openstamanager/api?token=&resource=anagrafiche&display=[1,SLEEP(5)]\"\n```\n\nThe server will delay its response by approximately 5 seconds, confirming the `SLEEP(5)` command was executed by the database.\n\n### Impact\nThis is a critical SQL Injection vulnerability. Any authenticated user, even those with the lowest privileges, can exploit this vulnerability to:\n\n* **Exfiltrate all data** from the database (e.g., user credentials, customer information, invoices, internal data).\n* **Modify or delete data**, compromising data integrity.\n* Potentially achieve further system compromise, depending on the database user's privileges and system configuration.", - "affected_packages": [], + "affected_packages": [ + { + "package": { + "type": "composer", + "namespace": "devcode-it", + "name": "openstamanager", + "version": "", + "qualifiers": "", + "subpath": "" + }, + "affected_version_range": "vers:composer/<2.9.5", + "fixed_version_range": "vers:composer/2.9.5", + "introduced_by_commit_patches": [], + "fixed_by_commit_patches": [] + } + ], "references_v2": [ { "reference_id": "", diff --git a/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-1.json b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-1.json index 97d650d7b..5e74271a9 100644 --- a/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-1.json +++ b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-1.json @@ -14,7 +14,7 @@ "qualifiers": "", "subpath": "" }, - "affected_version_range": "vers:pypi/>=0|4.4.0.dev1|4.5.0|4.5.2|4.5.4|4.6.2|4.6.3|4.6.4|4.6.5|4.6.7|4.7.0|4.7.1|4.7.2|4.7.4|4.7.5|4.8.0rc1|4.8.0|4.8.1|4.8.2|4.8.3|4.8.5|4.8.6|4.8.7|4.8.9|4.9.12|4.10.2|4.12.2", + "affected_version_range": "vers:pypi/4.4.0.dev1|4.5.0|4.5.2|4.5.4|4.6.2|4.6.3|4.6.4|4.6.5|4.6.7|4.7.0|4.7.1|4.7.2|4.7.4|4.7.5|4.8.0rc1|4.8.0|4.8.1|4.8.2|4.8.3|4.8.5|4.8.6|4.8.7|4.8.9|4.9.12|4.10.2|4.12.2", "fixed_version_range": null, "introduced_by_commit_patches": [], "fixed_by_commit_patches": [] diff --git a/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-2.json b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-2.json index eed98cdc1..9c9f26080 100644 --- a/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-2.json +++ b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-2.json @@ -14,7 +14,7 @@ "qualifiers": "", "subpath": "" }, - "affected_version_range": "vers:pypi/>=0|0.0.1|0.0.2|0.0.3|0.1.0|0.2.0|0.2.1|0.3.0|0.3.1|0.3.2|0.4.0|0.4.1|0.4.2|0.4.3|0.5.0|0.5.1|0.5.2|0.5.3|0.5.4|0.6.0|0.7.0|1.0.0|1.0.1|1.1.0|1.1.1|1.1.2|1.1.3|1.1.4|1.1.5|1.2.2|1.3.3|1.4.1|1.5.1|1.6.0|1.7.0|2.0.0|2.0.1|2.0.2|2.0.3|2.0.4|2.0.5|2.1.0|2.2.0a0|2.2.0|2.2.1|2.2.2|2.2.3|<2.3.0", + "affected_version_range": "vers:pypi/0.0.1|0.0.2|0.0.3|0.1.0|0.2.0|0.2.1|0.3.0|0.3.1|0.3.2|0.4.0|0.4.1|0.4.2|0.4.3|0.5.0|0.5.1|0.5.2|0.5.3|0.5.4|0.6.0|0.7.0|1.0.0|1.0.1|1.1.0|1.1.1|1.1.2|1.1.3|1.1.4|1.1.5|1.2.2|1.3.3|1.4.1|1.5.1|1.6.0|1.7.0|2.0.0|2.0.1|2.0.2|2.0.3|2.0.4|2.0.5|2.1.0|2.2.0a0|2.2.0|2.2.1|2.2.2|2.2.3|<2.3.0", "fixed_version_range": "vers:pypi/2.3.0", "introduced_by_commit_patches": [ { diff --git a/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-3.json b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-3.json index b6d07bf22..c7be9d5ad 100644 --- a/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-3.json +++ b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-3.json @@ -15,7 +15,7 @@ "qualifiers": "", "subpath": "" }, - "affected_version_range": "vers:pypi/>=0|0.1|0.2|0.3|0.4|0.4.1|0.4.2|0.4.3|0.4.4|0.5.0|0.6.0|0.6.1|0.6.2|0.6.3|0.6.4|0.6.5|0.7.0|0.7.1|0.7.2|0.7.3|0.8.0|0.8.1|0.8.2|0.8.3|0.8.4|0.9.0|0.9.1|0.9.2|0.9.3|0.10.0|0.10.1|0.10.2|0.11.0|0.12.0|0.13.0|0.13.1|0.14.0|0.14.1|0.14.2|0.14.3|0.14.4|0.15.0|0.15.1|0.15.2|0.15.3|0.16.0|0.16.1|0.16.2|0.16.3|0.16.4|0.16.5|0.16.6|0.17.0|0.17.1|0.17.2|0.17.3|0.17.4|0.18.0|0.18.1|0.18.2|0.18.3|0.18.4|0.19.0|0.20.0|0.20.1|0.20.2|0.21.0|0.21.1|0.21.2|0.21.4|0.21.5|0.21.6|0.22.0a0|0.22.0b0|0.22.0b1|0.22.0b2|0.22.0b3|0.22.0b4|0.22.0b5|0.22.0b6|0.22.0|0.22.1|0.22.2|0.22.3|0.22.4|0.22.5|1.0.0|1.0.1|1.0.2|1.0.3|1.0.5|1.1.0|1.1.1|1.1.2|1.1.3|1.1.4|1.1.5|1.1.6|1.2.0|1.3.0|1.3.1|1.3.2|1.3.3|1.3.4|1.3.5|2.0.0rc1|2.0.0|2.0.1|2.0.2|2.0.3|2.0.4|2.0.5|2.0.6|2.0.7|2.1.0|2.2.0|2.2.1|2.2.2|2.2.3|2.2.4|2.2.5|2.3.0a1|2.3.0a2|2.3.0a3|2.3.0a4|2.3.0|2.3.1a1|2.3.1|2.3.2b2|2.3.2b3|2.3.2|2.3.3|2.3.4|2.3.5|2.3.6|2.3.7|2.3.8|2.3.9|2.3.10|3.0.0b0|3.0.0b1|3.0.0b2|3.0.0b3|3.0.0b4|3.0.0|3.0.1|3.0.2|3.0.3|3.0.4|3.0.5|3.0.6|3.0.7|3.0.8|3.0.9|3.1.0|3.1.1|3.1.2|3.1.3|3.2.0|3.2.1|3.3.0a0|3.3.0|3.3.1|3.3.2a0|3.3.2|3.4.0a0|3.4.0a3|3.4.0b1|3.4.0b2|3.4.0|3.4.1|3.4.2|3.4.3|3.4.4|3.5.0a1|3.5.0b1|3.5.0b2|3.5.0b3|3.5.0|3.5.1|3.5.2|3.5.3|3.5.4|3.6.0a0|3.6.0a1|3.6.0a2|3.6.0a3|3.6.0a4|3.6.0a5|3.6.0a6|3.6.0a7|3.6.0a8|3.6.0a9|3.6.0a11|3.6.0a12|3.6.0b0|3.6.0|3.6.1b3|3.6.1b4|3.6.1|3.6.2a0|3.6.2a1|3.6.2a2|3.6.2|3.6.3|3.7.0b0|3.7.0b1|3.7.0|3.7.1|3.7.2|3.7.3|3.7.4|3.7.4.post0|3.8.0a7|3.8.0b0|3.8.0|3.8.1|3.8.2|3.8.3|3.8.4|3.8.5|3.8.6|3.9.0b0|3.9.0b1|3.9.0rc0|3.9.0|3.9.1|<3.9.2", + "affected_version_range": "vers:pypi/0.1|0.2|0.3|0.4|0.4.1|0.4.2|0.4.3|0.4.4|0.5.0|0.6.0|0.6.1|0.6.2|0.6.3|0.6.4|0.6.5|0.7.0|0.7.1|0.7.2|0.7.3|0.8.0|0.8.1|0.8.2|0.8.3|0.8.4|0.9.0|0.9.1|0.9.2|0.9.3|0.10.0|0.10.1|0.10.2|0.11.0|0.12.0|0.13.0|0.13.1|0.14.0|0.14.1|0.14.2|0.14.3|0.14.4|0.15.0|0.15.1|0.15.2|0.15.3|0.16.0|0.16.1|0.16.2|0.16.3|0.16.4|0.16.5|0.16.6|0.17.0|0.17.1|0.17.2|0.17.3|0.17.4|0.18.0|0.18.1|0.18.2|0.18.3|0.18.4|0.19.0|0.20.0|0.20.1|0.20.2|0.21.0|0.21.1|0.21.2|0.21.4|0.21.5|0.21.6|0.22.0a0|0.22.0b0|0.22.0b1|0.22.0b2|0.22.0b3|0.22.0b4|0.22.0b5|0.22.0b6|0.22.0|0.22.1|0.22.2|0.22.3|0.22.4|0.22.5|1.0.0|1.0.1|1.0.2|1.0.3|1.0.5|1.1.0|1.1.1|1.1.2|1.1.3|1.1.4|1.1.5|1.1.6|1.2.0|1.3.0|1.3.1|1.3.2|1.3.3|1.3.4|1.3.5|2.0.0rc1|2.0.0|2.0.1|2.0.2|2.0.3|2.0.4|2.0.5|2.0.6|2.0.7|2.1.0|2.2.0|2.2.1|2.2.2|2.2.3|2.2.4|2.2.5|2.3.0a1|2.3.0a2|2.3.0a3|2.3.0a4|2.3.0|2.3.1a1|2.3.1|2.3.2b2|2.3.2b3|2.3.2|2.3.3|2.3.4|2.3.5|2.3.6|2.3.7|2.3.8|2.3.9|2.3.10|3.0.0b0|3.0.0b1|3.0.0b2|3.0.0b3|3.0.0b4|3.0.0|3.0.1|3.0.2|3.0.3|3.0.4|3.0.5|3.0.6|3.0.7|3.0.8|3.0.9|3.1.0|3.1.1|3.1.2|3.1.3|3.2.0|3.2.1|3.3.0a0|3.3.0|3.3.1|3.3.2a0|3.3.2|3.4.0a0|3.4.0a3|3.4.0b1|3.4.0b2|3.4.0|3.4.1|3.4.2|3.4.3|3.4.4|3.5.0a1|3.5.0b1|3.5.0b2|3.5.0b3|3.5.0|3.5.1|3.5.2|3.5.3|3.5.4|3.6.0a0|3.6.0a1|3.6.0a2|3.6.0a3|3.6.0a4|3.6.0a5|3.6.0a6|3.6.0a7|3.6.0a8|3.6.0a9|3.6.0a11|3.6.0a12|3.6.0b0|3.6.0|3.6.1b3|3.6.1b4|3.6.1|3.6.2a0|3.6.2a1|3.6.2a2|3.6.2|3.6.3|3.7.0b0|3.7.0b1|3.7.0|3.7.1|3.7.2|3.7.3|3.7.4|3.7.4.post0|3.8.0a7|3.8.0b0|3.8.0|3.8.1|3.8.2|3.8.3|3.8.4|3.8.5|3.8.6|3.9.0b0|3.9.0b1|3.9.0rc0|3.9.0|3.9.1|<3.9.2", "fixed_version_range": "vers:pypi/3.9.2", "introduced_by_commit_patches": [ { diff --git a/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-5.json b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-5.json index 8335da744..ae9423266 100644 --- a/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-5.json +++ b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-5.json @@ -15,7 +15,7 @@ "qualifiers": "", "subpath": "" }, - "affected_version_range": "vers:pypi/>=0|1.9a2|1.9a5|1.9a6|2.0|2.0.1|2.1.0|2.2|2.3|2.4|2.4.1|2.5|2.6|2.6.1", + "affected_version_range": "vers:pypi/1.9a2|1.9a5|1.9a6|2.0|2.0.1|2.1.0|2.2|2.3|2.4|2.4.1|2.5|2.6|2.6.1", "fixed_version_range": null, "introduced_by_commit_patches": [ { diff --git a/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-6.json b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-6.json index 8f5075fc2..28ee94ca0 100644 --- a/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-6.json +++ b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-6.json @@ -15,7 +15,7 @@ "qualifiers": "", "subpath": "" }, - "affected_version_range": "vers:pypi/>=0|0.1|0.2|0.3|0.3.1|0.4|0.4.1|0.5|0.6|0.7|0.8|0.8.1|0.8.2|0.8.3|0.8.4|0.8.5|0.8.6|0.8.7|0.8.8|0.8.9|0.8.10|1.0b1|1.0b2|1.0rc1|1.0rc2|1.0|1.1rc1|1.1|1.2rc1|1.2|1.3rc1|1.3|1.3.1|1.4rc1|1.4|1.4.1|1.4.2|1.4.3|1.4.4|1.4.5|1.4.6|1.5rc1|1.5|1.5.1|1.5.2|1.5.3|1.6rc1|1.6|1.6.1|1.6.2|1.6.3|1.7rc1|1.7|1.8rc1|1.8|1.8.1|1.8.2|1.9rc1|1.9|1.9.1|1.10rc1|1.10|1.10.1|1.11rc1|1.11|1.11.1|1.12rc1|1.12|1.12.1|1.12.2|1.12.3|1.12.4|1.12.5|1.12.6|1.13rc1|1.13|1.13.1|1.13.2|1.13.3|1.13.4|2.0b1|2.0rc1|2.0|2.0.1|2.0.2|2.1rc1|2.1rc2|2.1|2.1.1|2.1.2|2.1.3|2.2rc1|2.2rc2|2.2|2.2.1|2.2.2|2.3rc1|2.3rc2|2.3|2.4rc1|2.4|2.5rc1|2.5|2.5.1|2.5.2|2.6rc1|2.6|2.6.1|2.6.2|2.6.3|2.7rc1|2.7rc2|2.7|2.7.1|2.7.2|2.7.3|2.7.4|2.8rc1|2.8|2.8.1|2.8.2|2.9rc1|2.9|2.9.1|2.9.2|2.9.3|2.10rc1|2.10rc2|2.10|2.10.1|2.10.2|2.11rc1|2.11|2.11.1|2.11.2|2.11.3|2.11.4|2.11.5|2.11.6|2.11.7|2.11.8|2.11.9|2.12rc1|2.12|2.12.1|2.12.2|2.12.3|2.12.4|2.12.5|2.12.6|2.13rc1|2.13rc2|2.13rc3|2.13|2.13.1|2.13.2|2.13.3|2.13.4|2.13.5|2.14rc1|2.14|2.14.1|2.14.2|2.15rc1|2.15rc2|2.15|2.15.1|2.15.2|2.15.3|2.15.4|2.15.5|2.15.6|2.16rc1|2.16rc2|2.16|2.16.1|2.16.2|2.16.3|3.0rc1|3.0rc2|3.0rc3|3.0|3.0.1|3.0.2|3.0.3|4.0rc1|4.0rc2|4.0|4.0.1|4.0.2|4.0.3|4.0.4|4.1rc1|4.1|4.1.1|4.1.2|4.1.3|<4.1.4|4.2|>=4.2|4.2.1|<4.2.2", + "affected_version_range": "vers:pypi/0.1|0.2|0.3|0.3.1|0.4|0.4.1|0.5|0.6|0.7|0.8|0.8.1|0.8.2|0.8.3|0.8.4|0.8.5|0.8.6|0.8.7|0.8.8|0.8.9|0.8.10|1.0b1|1.0b2|1.0rc1|1.0rc2|1.0|1.1rc1|1.1|1.2rc1|1.2|1.3rc1|1.3|1.3.1|1.4rc1|1.4|1.4.1|1.4.2|1.4.3|1.4.4|1.4.5|1.4.6|1.5rc1|1.5|1.5.1|1.5.2|1.5.3|1.6rc1|1.6|1.6.1|1.6.2|1.6.3|1.7rc1|1.7|1.8rc1|1.8|1.8.1|1.8.2|1.9rc1|1.9|1.9.1|1.10rc1|1.10|1.10.1|1.11rc1|1.11|1.11.1|1.12rc1|1.12|1.12.1|1.12.2|1.12.3|1.12.4|1.12.5|1.12.6|1.13rc1|1.13|1.13.1|1.13.2|1.13.3|1.13.4|2.0b1|2.0rc1|2.0|2.0.1|2.0.2|2.1rc1|2.1rc2|2.1|2.1.1|2.1.2|2.1.3|2.2rc1|2.2rc2|2.2|2.2.1|2.2.2|2.3rc1|2.3rc2|2.3|2.4rc1|2.4|2.5rc1|2.5|2.5.1|2.5.2|2.6rc1|2.6|2.6.1|2.6.2|2.6.3|2.7rc1|2.7rc2|2.7|2.7.1|2.7.2|2.7.3|2.7.4|2.8rc1|2.8|2.8.1|2.8.2|2.9rc1|2.9|2.9.1|2.9.2|2.9.3|2.10rc1|2.10rc2|2.10|2.10.1|2.10.2|2.11rc1|2.11|2.11.1|2.11.2|2.11.3|2.11.4|2.11.5|2.11.6|2.11.7|2.11.8|2.11.9|2.12rc1|2.12|2.12.1|2.12.2|2.12.3|2.12.4|2.12.5|2.12.6|2.13rc1|2.13rc2|2.13rc3|2.13|2.13.1|2.13.2|2.13.3|2.13.4|2.13.5|2.14rc1|2.14|2.14.1|2.14.2|2.15rc1|2.15rc2|2.15|2.15.1|2.15.2|2.15.3|2.15.4|2.15.5|2.15.6|2.16rc1|2.16rc2|2.16|2.16.1|2.16.2|2.16.3|3.0rc1|3.0rc2|3.0rc3|3.0|3.0.1|3.0.2|3.0.3|4.0rc1|4.0rc2|4.0|4.0.1|4.0.2|4.0.3|4.0.4|4.1rc1|4.1|4.1.1|4.1.2|4.1.3|<4.1.4|4.2|>=4.2|4.2.1|<4.2.2", "fixed_version_range": "vers:pypi/4.1.4|4.2.2", "introduced_by_commit_patches": [ { diff --git a/vulnerabilities/tests/test_osv_v2.py b/vulnerabilities/tests/test_osv_v2.py index da33b1b82..b3f306aa4 100644 --- a/vulnerabilities/tests/test_osv_v2.py +++ b/vulnerabilities/tests/test_osv_v2.py @@ -35,7 +35,7 @@ def test_to_advisories_github2(self): mock_response = json.load(f) expected_file = os.path.join(TEST_DATA, "github/github-expected-2.json") imported_data = parse_advisory_data_v3( - mock_response, "packagist", advisory_url="https://test.com", advisory_text="" + mock_response, "composer", advisory_url="https://test.com", advisory_text="" ) result = imported_data.to_dict() util_tests.check_results_against_json(result, expected_file) From ab084af4f78a8ebb3638c18f147c6994cc39d516 Mon Sep 17 00:00:00 2001 From: ziad hany Date: Wed, 24 Dec 2025 09:05:45 +0200 Subject: [PATCH 5/6] Update OSV migration file Signed-off-by: ziad hany --- ...nts.py => 0107_alter_advisoryseverity_scoring_elements.py} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename vulnerabilities/migrations/{0106_alter_advisoryseverity_scoring_elements.py => 0107_alter_advisoryseverity_scoring_elements.py} (81%) diff --git a/vulnerabilities/migrations/0106_alter_advisoryseverity_scoring_elements.py b/vulnerabilities/migrations/0107_alter_advisoryseverity_scoring_elements.py similarity index 81% rename from vulnerabilities/migrations/0106_alter_advisoryseverity_scoring_elements.py rename to vulnerabilities/migrations/0107_alter_advisoryseverity_scoring_elements.py index 597601f9c..7931ae229 100644 --- a/vulnerabilities/migrations/0106_alter_advisoryseverity_scoring_elements.py +++ b/vulnerabilities/migrations/0107_alter_advisoryseverity_scoring_elements.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.25 on 2025-12-23 17:38 +# Generated by Django 4.2.25 on 2025-12-24 07:04 from django.db import migrations, models @@ -6,7 +6,7 @@ class Migration(migrations.Migration): dependencies = [ - ("vulnerabilities", "0105_packagecommitpatch_patch_and_more"), + ("vulnerabilities", "0106_alter_advisoryreference_url_and_more"), ] operations = [ From 29003da0e8bcedbfc82855d3271f9fd4eee211ec Mon Sep 17 00:00:00 2001 From: ziad hany Date: Wed, 24 Dec 2025 12:01:54 +0200 Subject: [PATCH 6/6] Update OSV to simplify the affected/fixed package constraints Signed-off-by: ziad hany --- vulnerabilities/importers/osv_v2.py | 9 +++++++-- .../tests/test_data/osv_test/pypa/pypa-expected-2.json | 2 +- .../tests/test_data/osv_test/pypa/pypa-expected-3.json | 2 +- .../tests/test_data/osv_test/pypa/pypa-expected-6.json | 2 +- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/vulnerabilities/importers/osv_v2.py b/vulnerabilities/importers/osv_v2.py index 475bf9c02..f4bca8b84 100644 --- a/vulnerabilities/importers/osv_v2.py +++ b/vulnerabilities/importers/osv_v2.py @@ -18,6 +18,7 @@ from cvss.exceptions import CVSS4MalformedError from packageurl import PackageURL from univers.version_constraint import VersionConstraint +from univers.version_constraint import simplify_constraints from univers.version_range import RANGE_CLASS_BY_SCHEMES from univers.versions import InvalidVersion from univers.versions import SemverVersion @@ -142,14 +143,18 @@ def parse_advisory_data_v3( affected_version_range = None if affected_constraints: try: - affected_version_range = version_range_class(constraints=affected_constraints) + affected_version_range = version_range_class( + constraints=simplify_constraints(affected_constraints) + ) except Exception as e: logger.error(f"Failed to build VersionRange for {advisory_id}: {e}") fixed_version_range = None if fixed_constraints: try: - fixed_version_range = version_range_class(constraints=fixed_constraints) + fixed_version_range = version_range_class( + constraints=simplify_constraints(fixed_constraints) + ) except Exception as e: logger.error(f"Failed to build VersionRange for {advisory_id}: {e}") diff --git a/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-2.json b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-2.json index 9c9f26080..7c6df5b2f 100644 --- a/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-2.json +++ b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-2.json @@ -14,7 +14,7 @@ "qualifiers": "", "subpath": "" }, - "affected_version_range": "vers:pypi/0.0.1|0.0.2|0.0.3|0.1.0|0.2.0|0.2.1|0.3.0|0.3.1|0.3.2|0.4.0|0.4.1|0.4.2|0.4.3|0.5.0|0.5.1|0.5.2|0.5.3|0.5.4|0.6.0|0.7.0|1.0.0|1.0.1|1.1.0|1.1.1|1.1.2|1.1.3|1.1.4|1.1.5|1.2.2|1.3.3|1.4.1|1.5.1|1.6.0|1.7.0|2.0.0|2.0.1|2.0.2|2.0.3|2.0.4|2.0.5|2.1.0|2.2.0a0|2.2.0|2.2.1|2.2.2|2.2.3|<2.3.0", + "affected_version_range": "vers:pypi/0.0.1|0.0.2|0.0.3|0.1.0|0.2.0|0.2.1|0.3.0|0.3.1|0.3.2|0.4.0|0.4.1|0.4.2|0.4.3|0.5.0|0.5.1|0.5.2|0.5.3|0.5.4|0.6.0|0.7.0|1.0.0|1.0.1|1.1.0|1.1.1|1.1.2|1.1.3|1.1.4|1.1.5|1.2.2|1.3.3|1.4.1|1.5.1|1.6.0|1.7.0|2.0.0|2.0.1|2.0.2|2.0.3|2.0.4|2.0.5|2.1.0|2.2.0a0|2.2.0|2.2.1|2.2.2|<2.3.0", "fixed_version_range": "vers:pypi/2.3.0", "introduced_by_commit_patches": [ { diff --git a/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-3.json b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-3.json index c7be9d5ad..fb5aa112a 100644 --- a/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-3.json +++ b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-3.json @@ -15,7 +15,7 @@ "qualifiers": "", "subpath": "" }, - "affected_version_range": "vers:pypi/0.1|0.2|0.3|0.4|0.4.1|0.4.2|0.4.3|0.4.4|0.5.0|0.6.0|0.6.1|0.6.2|0.6.3|0.6.4|0.6.5|0.7.0|0.7.1|0.7.2|0.7.3|0.8.0|0.8.1|0.8.2|0.8.3|0.8.4|0.9.0|0.9.1|0.9.2|0.9.3|0.10.0|0.10.1|0.10.2|0.11.0|0.12.0|0.13.0|0.13.1|0.14.0|0.14.1|0.14.2|0.14.3|0.14.4|0.15.0|0.15.1|0.15.2|0.15.3|0.16.0|0.16.1|0.16.2|0.16.3|0.16.4|0.16.5|0.16.6|0.17.0|0.17.1|0.17.2|0.17.3|0.17.4|0.18.0|0.18.1|0.18.2|0.18.3|0.18.4|0.19.0|0.20.0|0.20.1|0.20.2|0.21.0|0.21.1|0.21.2|0.21.4|0.21.5|0.21.6|0.22.0a0|0.22.0b0|0.22.0b1|0.22.0b2|0.22.0b3|0.22.0b4|0.22.0b5|0.22.0b6|0.22.0|0.22.1|0.22.2|0.22.3|0.22.4|0.22.5|1.0.0|1.0.1|1.0.2|1.0.3|1.0.5|1.1.0|1.1.1|1.1.2|1.1.3|1.1.4|1.1.5|1.1.6|1.2.0|1.3.0|1.3.1|1.3.2|1.3.3|1.3.4|1.3.5|2.0.0rc1|2.0.0|2.0.1|2.0.2|2.0.3|2.0.4|2.0.5|2.0.6|2.0.7|2.1.0|2.2.0|2.2.1|2.2.2|2.2.3|2.2.4|2.2.5|2.3.0a1|2.3.0a2|2.3.0a3|2.3.0a4|2.3.0|2.3.1a1|2.3.1|2.3.2b2|2.3.2b3|2.3.2|2.3.3|2.3.4|2.3.5|2.3.6|2.3.7|2.3.8|2.3.9|2.3.10|3.0.0b0|3.0.0b1|3.0.0b2|3.0.0b3|3.0.0b4|3.0.0|3.0.1|3.0.2|3.0.3|3.0.4|3.0.5|3.0.6|3.0.7|3.0.8|3.0.9|3.1.0|3.1.1|3.1.2|3.1.3|3.2.0|3.2.1|3.3.0a0|3.3.0|3.3.1|3.3.2a0|3.3.2|3.4.0a0|3.4.0a3|3.4.0b1|3.4.0b2|3.4.0|3.4.1|3.4.2|3.4.3|3.4.4|3.5.0a1|3.5.0b1|3.5.0b2|3.5.0b3|3.5.0|3.5.1|3.5.2|3.5.3|3.5.4|3.6.0a0|3.6.0a1|3.6.0a2|3.6.0a3|3.6.0a4|3.6.0a5|3.6.0a6|3.6.0a7|3.6.0a8|3.6.0a9|3.6.0a11|3.6.0a12|3.6.0b0|3.6.0|3.6.1b3|3.6.1b4|3.6.1|3.6.2a0|3.6.2a1|3.6.2a2|3.6.2|3.6.3|3.7.0b0|3.7.0b1|3.7.0|3.7.1|3.7.2|3.7.3|3.7.4|3.7.4.post0|3.8.0a7|3.8.0b0|3.8.0|3.8.1|3.8.2|3.8.3|3.8.4|3.8.5|3.8.6|3.9.0b0|3.9.0b1|3.9.0rc0|3.9.0|3.9.1|<3.9.2", + "affected_version_range": "vers:pypi/0.1|0.2|0.3|0.4|0.4.1|0.4.2|0.4.3|0.4.4|0.5.0|0.6.0|0.6.1|0.6.2|0.6.3|0.6.4|0.6.5|0.7.0|0.7.1|0.7.2|0.7.3|0.8.0|0.8.1|0.8.2|0.8.3|0.8.4|0.9.0|0.9.1|0.9.2|0.9.3|0.10.0|0.10.1|0.10.2|0.11.0|0.12.0|0.13.0|0.13.1|0.14.0|0.14.1|0.14.2|0.14.3|0.14.4|0.15.0|0.15.1|0.15.2|0.15.3|0.16.0|0.16.1|0.16.2|0.16.3|0.16.4|0.16.5|0.16.6|0.17.0|0.17.1|0.17.2|0.17.3|0.17.4|0.18.0|0.18.1|0.18.2|0.18.3|0.18.4|0.19.0|0.20.0|0.20.1|0.20.2|0.21.0|0.21.1|0.21.2|0.21.4|0.21.5|0.21.6|0.22.0a0|0.22.0b0|0.22.0b1|0.22.0b2|0.22.0b3|0.22.0b4|0.22.0b5|0.22.0b6|0.22.0|0.22.1|0.22.2|0.22.3|0.22.4|0.22.5|1.0.0|1.0.1|1.0.2|1.0.3|1.0.5|1.1.0|1.1.1|1.1.2|1.1.3|1.1.4|1.1.5|1.1.6|1.2.0|1.3.0|1.3.1|1.3.2|1.3.3|1.3.4|1.3.5|2.0.0rc1|2.0.0|2.0.1|2.0.2|2.0.3|2.0.4|2.0.5|2.0.6|2.0.7|2.1.0|2.2.0|2.2.1|2.2.2|2.2.3|2.2.4|2.2.5|2.3.0a1|2.3.0a2|2.3.0a3|2.3.0a4|2.3.0|2.3.1a1|2.3.1|2.3.2b2|2.3.2b3|2.3.2|2.3.3|2.3.4|2.3.5|2.3.6|2.3.7|2.3.8|2.3.9|2.3.10|3.0.0b0|3.0.0b1|3.0.0b2|3.0.0b3|3.0.0b4|3.0.0|3.0.1|3.0.2|3.0.3|3.0.4|3.0.5|3.0.6|3.0.7|3.0.8|3.0.9|3.1.0|3.1.1|3.1.2|3.1.3|3.2.0|3.2.1|3.3.0a0|3.3.0|3.3.1|3.3.2a0|3.3.2|3.4.0a0|3.4.0a3|3.4.0b1|3.4.0b2|3.4.0|3.4.1|3.4.2|3.4.3|3.4.4|3.5.0a1|3.5.0b1|3.5.0b2|3.5.0b3|3.5.0|3.5.1|3.5.2|3.5.3|3.5.4|3.6.0a0|3.6.0a1|3.6.0a2|3.6.0a3|3.6.0a4|3.6.0a5|3.6.0a6|3.6.0a7|3.6.0a8|3.6.0a9|3.6.0a11|3.6.0a12|3.6.0b0|3.6.0|3.6.1b3|3.6.1b4|3.6.1|3.6.2a0|3.6.2a1|3.6.2a2|3.6.2|3.6.3|3.7.0b0|3.7.0b1|3.7.0|3.7.1|3.7.2|3.7.3|3.7.4|3.7.4.post0|3.8.0a7|3.8.0b0|3.8.0|3.8.1|3.8.2|3.8.3|3.8.4|3.8.5|3.8.6|3.9.0b0|3.9.0b1|3.9.0rc0|3.9.0|<3.9.2", "fixed_version_range": "vers:pypi/3.9.2", "introduced_by_commit_patches": [ { diff --git a/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-6.json b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-6.json index 28ee94ca0..2294de62e 100644 --- a/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-6.json +++ b/vulnerabilities/tests/test_data/osv_test/pypa/pypa-expected-6.json @@ -15,7 +15,7 @@ "qualifiers": "", "subpath": "" }, - "affected_version_range": "vers:pypi/0.1|0.2|0.3|0.3.1|0.4|0.4.1|0.5|0.6|0.7|0.8|0.8.1|0.8.2|0.8.3|0.8.4|0.8.5|0.8.6|0.8.7|0.8.8|0.8.9|0.8.10|1.0b1|1.0b2|1.0rc1|1.0rc2|1.0|1.1rc1|1.1|1.2rc1|1.2|1.3rc1|1.3|1.3.1|1.4rc1|1.4|1.4.1|1.4.2|1.4.3|1.4.4|1.4.5|1.4.6|1.5rc1|1.5|1.5.1|1.5.2|1.5.3|1.6rc1|1.6|1.6.1|1.6.2|1.6.3|1.7rc1|1.7|1.8rc1|1.8|1.8.1|1.8.2|1.9rc1|1.9|1.9.1|1.10rc1|1.10|1.10.1|1.11rc1|1.11|1.11.1|1.12rc1|1.12|1.12.1|1.12.2|1.12.3|1.12.4|1.12.5|1.12.6|1.13rc1|1.13|1.13.1|1.13.2|1.13.3|1.13.4|2.0b1|2.0rc1|2.0|2.0.1|2.0.2|2.1rc1|2.1rc2|2.1|2.1.1|2.1.2|2.1.3|2.2rc1|2.2rc2|2.2|2.2.1|2.2.2|2.3rc1|2.3rc2|2.3|2.4rc1|2.4|2.5rc1|2.5|2.5.1|2.5.2|2.6rc1|2.6|2.6.1|2.6.2|2.6.3|2.7rc1|2.7rc2|2.7|2.7.1|2.7.2|2.7.3|2.7.4|2.8rc1|2.8|2.8.1|2.8.2|2.9rc1|2.9|2.9.1|2.9.2|2.9.3|2.10rc1|2.10rc2|2.10|2.10.1|2.10.2|2.11rc1|2.11|2.11.1|2.11.2|2.11.3|2.11.4|2.11.5|2.11.6|2.11.7|2.11.8|2.11.9|2.12rc1|2.12|2.12.1|2.12.2|2.12.3|2.12.4|2.12.5|2.12.6|2.13rc1|2.13rc2|2.13rc3|2.13|2.13.1|2.13.2|2.13.3|2.13.4|2.13.5|2.14rc1|2.14|2.14.1|2.14.2|2.15rc1|2.15rc2|2.15|2.15.1|2.15.2|2.15.3|2.15.4|2.15.5|2.15.6|2.16rc1|2.16rc2|2.16|2.16.1|2.16.2|2.16.3|3.0rc1|3.0rc2|3.0rc3|3.0|3.0.1|3.0.2|3.0.3|4.0rc1|4.0rc2|4.0|4.0.1|4.0.2|4.0.3|4.0.4|4.1rc1|4.1|4.1.1|4.1.2|4.1.3|<4.1.4|4.2|>=4.2|4.2.1|<4.2.2", + "affected_version_range": "vers:pypi/0.1|0.2|0.3|0.3.1|0.4|0.4.1|0.5|0.6|0.7|0.8|0.8.1|0.8.2|0.8.3|0.8.4|0.8.5|0.8.6|0.8.7|0.8.8|0.8.9|0.8.10|1.0b1|1.0b2|1.0rc1|1.0rc2|1.0|1.1rc1|1.1|1.2rc1|1.2|1.3rc1|1.3|1.3.1|1.4rc1|1.4|1.4.1|1.4.2|1.4.3|1.4.4|1.4.5|1.4.6|1.5rc1|1.5|1.5.1|1.5.2|1.5.3|1.6rc1|1.6|1.6.1|1.6.2|1.6.3|1.7rc1|1.7|1.8rc1|1.8|1.8.1|1.8.2|1.9rc1|1.9|1.9.1|1.10rc1|1.10|1.10.1|1.11rc1|1.11|1.11.1|1.12rc1|1.12|1.12.1|1.12.2|1.12.3|1.12.4|1.12.5|1.12.6|1.13rc1|1.13|1.13.1|1.13.2|1.13.3|1.13.4|2.0b1|2.0rc1|2.0|2.0.1|2.0.2|2.1rc1|2.1rc2|2.1|2.1.1|2.1.2|2.1.3|2.2rc1|2.2rc2|2.2|2.2.1|2.2.2|2.3rc1|2.3rc2|2.3|2.4rc1|2.4|2.5rc1|2.5|2.5.1|2.5.2|2.6rc1|2.6|2.6.1|2.6.2|2.6.3|2.7rc1|2.7rc2|2.7|2.7.1|2.7.2|2.7.3|2.7.4|2.8rc1|2.8|2.8.1|2.8.2|2.9rc1|2.9|2.9.1|2.9.2|2.9.3|2.10rc1|2.10rc2|2.10|2.10.1|2.10.2|2.11rc1|2.11|2.11.1|2.11.2|2.11.3|2.11.4|2.11.5|2.11.6|2.11.7|2.11.8|2.11.9|2.12rc1|2.12|2.12.1|2.12.2|2.12.3|2.12.4|2.12.5|2.12.6|2.13rc1|2.13rc2|2.13rc3|2.13|2.13.1|2.13.2|2.13.3|2.13.4|2.13.5|2.14rc1|2.14|2.14.1|2.14.2|2.15rc1|2.15rc2|2.15|2.15.1|2.15.2|2.15.3|2.15.4|2.15.5|2.15.6|2.16rc1|2.16rc2|2.16|2.16.1|2.16.2|2.16.3|3.0rc1|3.0rc2|3.0rc3|3.0|3.0.1|3.0.2|3.0.3|4.0rc1|4.0rc2|4.0|4.0.1|4.0.2|4.0.3|4.0.4|4.1rc1|4.1|4.1.1|4.1.2|4.1.3|<4.1.4|4.2|>=4.2", "fixed_version_range": "vers:pypi/4.1.4|4.2.2", "introduced_by_commit_patches": [ {