diff --git a/vulnerabilities/importers/github.py b/vulnerabilities/importers/github.py index c816d3faa..8ef1b3a9c 100644 --- a/vulnerabilities/importers/github.py +++ b/vulnerabilities/importers/github.py @@ -11,6 +11,7 @@ from typing import Iterable from typing import Optional +from cwe2.database import Database from dateutil import parser as dateparser from packageurl import PackageURL from univers.version_range import RANGE_CLASS_BY_SCHEMES @@ -24,11 +25,11 @@ from vulnerabilities.importer import Reference from vulnerabilities.importer import VulnerabilitySeverity from vulnerabilities.utils import dedupe +from vulnerabilities.utils import get_cwe_id from vulnerabilities.utils import get_item logger = logging.getLogger(__name__) - PACKAGE_TYPE_BY_GITHUB_ECOSYSTEM = { "MAVEN": "maven", "NUGET": "nuget", @@ -63,6 +64,11 @@ url } severity + cwes(first: 10){ + nodes { + cweId + } + } publishedAt } firstPatchedVersion{ @@ -227,10 +233,34 @@ def process_response(resp: dict, package_type: str) -> Iterable[AdvisoryData]: else: logger.error(f"Unknown identifier type {identifier_type!r} and value {value!r}") + weaknesses = get_cwes_from_github_advisory(advisory) + yield AdvisoryData( aliases=sorted(dedupe(aliases)), summary=summary, references=references, affected_packages=affected_packages, date_published=date_published, + weaknesses=weaknesses, ) + + +def get_cwes_from_github_advisory(advisory) -> [int]: + """ + Return the cwe-id list from advisory ex: [ 522 ] + by extracting the cwe_list from advisory ex: [{'cweId': 'CWE-522'}] + then remove the CWE- from string and convert it to integer 522 and Check if the CWE in CWE-Database + """ + weaknesses = [] + db = Database() + cwe_list = get_item(advisory, "cwes", "nodes") or [] + for cwe_item in cwe_list: + cwe_string = get_item(cwe_item, "cweId") + if cwe_string: + cwe_id = get_cwe_id(cwe_string) + try: + db.get(cwe_id) + weaknesses.append(cwe_id) + except Exception: + logger.error("Invalid CWE id") + return weaknesses diff --git a/vulnerabilities/importers/gitlab.py b/vulnerabilities/importers/gitlab.py index 4d8f7d5f2..561b1a7d9 100644 --- a/vulnerabilities/importers/gitlab.py +++ b/vulnerabilities/importers/gitlab.py @@ -28,10 +28,10 @@ from vulnerabilities.importer import Importer from vulnerabilities.importer import Reference from vulnerabilities.utils import build_description +from vulnerabilities.utils import get_cwe_id logger = logging.getLogger(__name__) - PURL_TYPE_BY_GITLAB_SCHEME = { "conan": "conan", "gem": "gem", @@ -44,7 +44,6 @@ "pypi": "pypi", } - GITLAB_SCHEME_BY_PURL_TYPE = {v: k for k, v in PURL_TYPE_BY_GITLAB_SCHEME.items()} @@ -186,6 +185,10 @@ def parse_gitlab_advisory(file): summary = build_description(gitlab_advisory.get("title"), gitlab_advisory.get("description")) urls = gitlab_advisory.get("urls") references = [Reference.from_url(u) for u in urls] + + cwe_ids = gitlab_advisory.get("cwe_ids") or [] + cwe_list = list(map(get_cwe_id, cwe_ids)) + date_published = dateparser.parse(gitlab_advisory.get("pubdate")) date_published = date_published.replace(tzinfo=pytz.UTC) package_slug = gitlab_advisory.get("package_slug") @@ -251,4 +254,5 @@ def parse_gitlab_advisory(file): references=references, date_published=date_published, affected_packages=affected_packages, + weaknesses=cwe_list, ) diff --git a/vulnerabilities/importers/osv.py b/vulnerabilities/importers/osv.py index c4ee58685..cb06b2162 100644 --- a/vulnerabilities/importers/osv.py +++ b/vulnerabilities/importers/osv.py @@ -27,6 +27,7 @@ from vulnerabilities.severity_systems import SCORING_SYSTEMS from vulnerabilities.utils import build_description from vulnerabilities.utils import dedupe +from vulnerabilities.utils import get_cwe_id logger = logging.getLogger(__name__) @@ -74,6 +75,9 @@ def parse_advisory_data(raw_data: dict, supported_ecosystem) -> Optional[Advisor fixed_version=version, ) ) + database_specific = raw_data.get("database_specific") or {} + cwe_ids = database_specific.get("cwe_ids") or [] + weaknesses = list(map(get_cwe_id, cwe_ids)) return AdvisoryData( aliases=aliases, @@ -81,6 +85,7 @@ def parse_advisory_data(raw_data: dict, supported_ecosystem) -> Optional[Advisor references=references, affected_packages=affected_packages, date_published=date_published, + weaknesses=weaknesses, ) diff --git a/vulnerabilities/importers/redhat.py b/vulnerabilities/importers/redhat.py index e24480ddd..4e14a7f86 100644 --- a/vulnerabilities/importers/redhat.py +++ b/vulnerabilities/importers/redhat.py @@ -8,6 +8,7 @@ # import logging +import re from typing import Dict from typing import Iterable from typing import List @@ -23,6 +24,7 @@ from vulnerabilities.importer import Reference from vulnerabilities.importer import VulnerabilitySeverity from vulnerabilities.rpm_utils import rpm_to_purl +from vulnerabilities.utils import get_cwe_id from vulnerabilities.utils import get_item from vulnerabilities.utils import requests_with_5xx_retry @@ -61,7 +63,6 @@ def get_data_from_url(url): class RedhatImporter(Importer): - spdx_license_expression = "CC-BY-4.0" license_url = "https://access.redhat.com/documentation/en-us/red_hat_security_data_api/1.0/html/red_hat_security_data_api/legal-notice" @@ -135,6 +136,11 @@ def to_advisory(advisory_data): scoring_elements=cvssv3_vector, ) ) + cwe_list = [] + # cwe_string : CWE-409","CWE-121->CWE-787","(CWE-401|CWE-404)","(CWE-190|CWE-911)->CWE-416" + cwe_string = advisory_data.get("CWE") + if cwe_string: + cwe_list = list(map(get_cwe_id, re.findall("CWE-[0-9]+", cwe_string))) aliases = [] alias = advisory_data.get("CVE") @@ -148,4 +154,5 @@ def to_advisory(advisory_data): summary=advisory_data.get("bugzilla_description") or "", affected_packages=affected_packages, references=references, + weaknesses=cwe_list, ) diff --git a/vulnerabilities/improvers/default.py b/vulnerabilities/improvers/default.py index 3e2f1913f..1b67eee5c 100644 --- a/vulnerabilities/improvers/default.py +++ b/vulnerabilities/improvers/default.py @@ -64,6 +64,7 @@ def get_inferences(self, advisory_data: AdvisoryData) -> Iterable[Inference]: affected_purls=affected_purls, fixed_purl=None, references=advisory_data.references, + weaknesses=advisory_data.weaknesses, ) else: for fixed_purl in fixed_purls or []: @@ -74,6 +75,7 @@ def get_inferences(self, advisory_data: AdvisoryData) -> Iterable[Inference]: affected_purls=affected_purls, fixed_purl=fixed_purl, references=advisory_data.references, + weaknesses=advisory_data.weaknesses, ) else: diff --git a/vulnerabilities/tests/test_data/gitlab/composer-expected.json b/vulnerabilities/tests/test_data/gitlab/composer-expected.json index 7160cc122..8dc515d70 100644 --- a/vulnerabilities/tests/test_data/gitlab/composer-expected.json +++ b/vulnerabilities/tests/test_data/gitlab/composer-expected.json @@ -25,5 +25,5 @@ } ], "date_published": "2018-03-15T00:00:00+00:00", - "weaknesses": [] + "weaknesses": [1035,937] } \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/gitlab/composer-improver-expected.json b/vulnerabilities/tests/test_data/gitlab/composer-improver-expected.json index 33b26cbef..b5a097cd6 100644 --- a/vulnerabilities/tests/test_data/gitlab/composer-improver-expected.json +++ b/vulnerabilities/tests/test_data/gitlab/composer-improver-expected.json @@ -22,6 +22,6 @@ "severities": [] } ], - "weaknesses": [] + "weaknesses": [1035,937] } ] \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/gitlab/golang-expected.json b/vulnerabilities/tests/test_data/gitlab/golang-expected.json index b3994a760..492eb1b9a 100644 --- a/vulnerabilities/tests/test_data/gitlab/golang-expected.json +++ b/vulnerabilities/tests/test_data/gitlab/golang-expected.json @@ -31,5 +31,5 @@ } ], "date_published": "2021-05-20T00:00:00+00:00", - "weaknesses": [] + "weaknesses": [1035,937] } \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/gitlab/golang-improver-expected.json b/vulnerabilities/tests/test_data/gitlab/golang-improver-expected.json index 20bc6462d..6a5401ca3 100644 --- a/vulnerabilities/tests/test_data/gitlab/golang-improver-expected.json +++ b/vulnerabilities/tests/test_data/gitlab/golang-improver-expected.json @@ -37,7 +37,7 @@ "severities": [] } ], - "weaknesses": [] + "weaknesses": [1035,937] }, { "vulnerability_id": null, @@ -68,6 +68,6 @@ "severities": [] } ], - "weaknesses": [] + "weaknesses": [1035,937] } ] \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/gitlab/maven-expected.json b/vulnerabilities/tests/test_data/gitlab/maven-expected.json index 658f0757f..b42d85d6e 100644 --- a/vulnerabilities/tests/test_data/gitlab/maven-expected.json +++ b/vulnerabilities/tests/test_data/gitlab/maven-expected.json @@ -46,5 +46,5 @@ } ], "date_published": "2021-11-15T00:00:00+00:00", - "weaknesses": [] + "weaknesses": [1035,937,94] } \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/gitlab/maven-improver-expected.json b/vulnerabilities/tests/test_data/gitlab/maven-improver-expected.json index 206ec5c7b..6d4a4d8e0 100644 --- a/vulnerabilities/tests/test_data/gitlab/maven-improver-expected.json +++ b/vulnerabilities/tests/test_data/gitlab/maven-improver-expected.json @@ -100,7 +100,7 @@ "severities": [] } ], - "weaknesses": [] + "weaknesses": [1035,937,94] }, { "vulnerability_id": null, @@ -146,6 +146,6 @@ "severities": [] } ], - "weaknesses": [] + "weaknesses": [1035,937,94] } ] \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/gitlab/npm-expected.json b/vulnerabilities/tests/test_data/gitlab/npm-expected.json index d6eeac5bc..6612c1172 100644 --- a/vulnerabilities/tests/test_data/gitlab/npm-expected.json +++ b/vulnerabilities/tests/test_data/gitlab/npm-expected.json @@ -36,5 +36,5 @@ } ], "date_published": "2020-06-05T00:00:00+00:00", - "weaknesses": [] + "weaknesses": [1035,937] } \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/gitlab/npm-improver-expected.json b/vulnerabilities/tests/test_data/gitlab/npm-improver-expected.json index 8f849befd..2ac0cdba8 100644 --- a/vulnerabilities/tests/test_data/gitlab/npm-improver-expected.json +++ b/vulnerabilities/tests/test_data/gitlab/npm-improver-expected.json @@ -50,7 +50,7 @@ "severities": [] } ], - "weaknesses": [] + "weaknesses": [1035,937] }, { "vulnerability_id": null, @@ -86,6 +86,6 @@ "severities": [] } ], - "weaknesses": [] + "weaknesses": [1035,937] } ] \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/gitlab/nuget-expected.json b/vulnerabilities/tests/test_data/gitlab/nuget-expected.json index b226794c9..de76a9289 100644 --- a/vulnerabilities/tests/test_data/gitlab/nuget-expected.json +++ b/vulnerabilities/tests/test_data/gitlab/nuget-expected.json @@ -31,5 +31,5 @@ } ], "date_published": "2022-01-08T00:00:00+00:00", - "weaknesses": [] + "weaknesses": [1035,770,937] } \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/gitlab/nuget-improver-expected.json b/vulnerabilities/tests/test_data/gitlab/nuget-improver-expected.json index 914df9bcd..40e4850ca 100644 --- a/vulnerabilities/tests/test_data/gitlab/nuget-improver-expected.json +++ b/vulnerabilities/tests/test_data/gitlab/nuget-improver-expected.json @@ -37,7 +37,7 @@ "severities": [] } ], - "weaknesses": [] + "weaknesses": [1035,770,937] }, { "vulnerability_id": null, @@ -68,6 +68,6 @@ "severities": [] } ], - "weaknesses": [] + "weaknesses": [1035,770,937] } ] \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/gitlab/pypi-expected.json b/vulnerabilities/tests/test_data/gitlab/pypi-expected.json index 55f88215f..47b31e8f5 100644 --- a/vulnerabilities/tests/test_data/gitlab/pypi-expected.json +++ b/vulnerabilities/tests/test_data/gitlab/pypi-expected.json @@ -30,5 +30,5 @@ } ], "date_published": "2019-07-17T00:00:00+00:00", - "weaknesses": [] + "weaknesses": [1035, 937] } \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/gitlab/pypi-improver-expected.json b/vulnerabilities/tests/test_data/gitlab/pypi-improver-expected.json index ee1942f44..aa4f03b33 100644 --- a/vulnerabilities/tests/test_data/gitlab/pypi-improver-expected.json +++ b/vulnerabilities/tests/test_data/gitlab/pypi-improver-expected.json @@ -44,7 +44,7 @@ "severities": [] } ], - "weaknesses": [] + "weaknesses": [1035, 937] }, { "vulnerability_id": null, @@ -74,6 +74,6 @@ "severities": [] } ], - "weaknesses": [] + "weaknesses": [1035, 937] } ] \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/pysec/pysec-advisories_with_cwe-expected.json b/vulnerabilities/tests/test_data/pysec/pysec-advisories_with_cwe-expected.json new file mode 100644 index 000000000..7bf695d39 --- /dev/null +++ b/vulnerabilities/tests/test_data/pysec/pysec-advisories_with_cwe-expected.json @@ -0,0 +1,124 @@ +{ + "aliases": [ + "CVE-2022-24840", + "GHSA-4w8f-hjm9-xwgf" + ], + "summary": "Path Traversal in django-s3file\n### Impact\n\nIt was possible to traverse the entire AWS S3 bucket and in most cases to access or delete files.\nThe issue was discovered by the maintainer. There were no reports of the vulnerability\nbeing known to or exploited by a third party, before the release of the patch.\n\nIf the `AWS_LOCATION` setting was set, traversal was limited to that location only.\nIf all your files handling views (like form views) require authentication or special permission, the thread is limited to privileged users.\n\n### Patches\n\nThe vulnerability has been fixed in version 5.5.1 and above.\n\n### Workarounds\n\nThere is no feasible workaround. We must urge all users to immediately updated to a patched version.\n\n### Detailed attack vector description\n\nAn attacker may use a request with malicious form data to traverse the entire AWS S3 bucket and perform destructive operations.\n\nAn attack could look as follows:\n```bash\ncurl -X POST -F \"s3file=file\" -F \"file=/priviliged/location/secrets.txt\" https://www.example.com/any/path/will/work/\n```\n\nThis will result in a request with files set and opened:\n\n```python\n>>> request.FILES.getlist(\"file\")\n[File(\"/priviliged/location/secrets.txt\")]\n```\n\nSince this behavior is injected via a middleware, any view can be called this way and will carry any files defined by the attacker.\n\nVia the `s3file` form field, any input name can be specified, including multiple inputs. For each input, multiple files can be freely\npicked of the S3 bucket.\n\n#### Scenarios and their practicality\n\nThere are four scenarios that would be considered practical in most setups:\n\n1. Illegal file injection,\n2. file deletion,\n3. file retrieval & tree traversal.\n4. code injection & remote code execution.\n\n##### File deletion\n\nAn attacker knows the location of a privileged file, like a static asset. Next, the file is injected into a form view. The upload to function will move the file to a new location. This is effectively deleting the file, since the previous references to it are invalid, and will cause S3 to return a 404. Furthermore, the new location is unknown to the site operator.\n\n##### File retrieval & tree traversal\n\nAn attacker knows the URL of a secret file and injects it into a form view. The view will move the file to a public location, making it accessible to the attacker. Since most form views will not be rate limited, this could also be used to guess files and traverse the file tree.\n\n##### Illegal file injection\n\nAn attacker uses any form to upload a file to the temporary upload location. Next, the attacker injects that file into a request, does not validate the contents or is not equipped to handle the mime type. The latter could be used as a potential DOS vector.\n\nIn practice, this is not a practical risk in most hardened setup. Files should always be sanitized before processing, since files can be included in a request even without this security issues.\n\n### For more information\nIf you have any questions or comments about this advisory:\n* Open an issue on [GitHub](https://github.com/codingjoe/django-s3file/issues)\n* Email us at [johannes@maron.family](mailto:johannes@maron.family)", + "affected_packages": [ + { + "package": { + "type": "pypi", + "namespace": null, + "name": "django-s3file", + "version": null, + "qualifiers": null, + "subpath": null + }, + "affected_version_range": null, + "fixed_version": "5.5.1" + } + ], + "references": [ + { + "reference_id": "", + "url": "https://github.com/codingjoe/django-s3file/security/advisories/GHSA-4w8f-hjm9-xwgf", + "severities": [ + { + "system": "cvssv3.1", + "value": "9.1", + "scoring_elements": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N" + }, + { + "system": "generic_textual", + "value": "CRITICAL", + "scoring_elements": "" + } + ] + }, + { + "reference_id": "", + "url": "https://nvd.nist.gov/vuln/detail/CVE-2022-24840", + "severities": [ + { + "system": "cvssv3.1", + "value": "9.1", + "scoring_elements": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N" + }, + { + "system": "generic_textual", + "value": "CRITICAL", + "scoring_elements": "" + } + ] + }, + { + "reference_id": "", + "url": "https://github.com/codingjoe/django-s3file/commit/68ccd2c621a40eb66fdd6af2be9d5fcc9c373318", + "severities": [ + { + "system": "cvssv3.1", + "value": "9.1", + "scoring_elements": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N" + }, + { + "system": "generic_textual", + "value": "CRITICAL", + "scoring_elements": "" + } + ] + }, + { + "reference_id": "", + "url": "https://github.com/codingjoe/django-s3file", + "severities": [ + { + "system": "cvssv3.1", + "value": "9.1", + "scoring_elements": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N" + }, + { + "system": "generic_textual", + "value": "CRITICAL", + "scoring_elements": "" + } + ] + }, + { + "reference_id": "", + "url": "https://github.com/codingjoe/django-s3file/releases/tag/5.5.1", + "severities": [ + { + "system": "cvssv3.1", + "value": "9.1", + "scoring_elements": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N" + }, + { + "system": "generic_textual", + "value": "CRITICAL", + "scoring_elements": "" + } + ] + }, + { + "reference_id": "", + "url": "https://github.com/pypa/advisory-database/tree/main/vulns/django-s3file/PYSEC-2022-208.yaml", + "severities": [ + { + "system": "cvssv3.1", + "value": "9.1", + "scoring_elements": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N" + }, + { + "system": "generic_textual", + "value": "CRITICAL", + "scoring_elements": "" + } + ] + } + ], + "date_published": "2022-06-06T21:24:24+00:00", + "weaknesses": [ + 22, + 96 + ] +} \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/pysec/pysec-advisory_with_cwe.json b/vulnerabilities/tests/test_data/pysec/pysec-advisory_with_cwe.json new file mode 100644 index 000000000..fd2e8a6d2 --- /dev/null +++ b/vulnerabilities/tests/test_data/pysec/pysec-advisory_with_cwe.json @@ -0,0 +1,82 @@ +{ + "schema_version": "1.4.0", + "id": "GHSA-4w8f-hjm9-xwgf", + "modified": "2022-06-06T21:24:24Z", + "published": "2022-06-06T21:24:24Z", + "aliases": [ + "CVE-2022-24840" + ], + "summary": "Path Traversal in django-s3file", + "details": "### Impact\n\nIt was possible to traverse the entire AWS S3 bucket and in most cases to access or delete files.\nThe issue was discovered by the maintainer. There were no reports of the vulnerability\nbeing known to or exploited by a third party, before the release of the patch.\n\nIf the `AWS_LOCATION` setting was set, traversal was limited to that location only.\nIf all your files handling views (like form views) require authentication or special permission, the thread is limited to privileged users.\n\n### Patches\n\nThe vulnerability has been fixed in version 5.5.1 and above.\n\n### Workarounds\n\nThere is no feasible workaround. We must urge all users to immediately updated to a patched version.\n\n### Detailed attack vector description\n\nAn attacker may use a request with malicious form data to traverse the entire AWS S3 bucket and perform destructive operations.\n\nAn attack could look as follows:\n```bash\ncurl -X POST -F \"s3file=file\" -F \"file=/priviliged/location/secrets.txt\" https://www.example.com/any/path/will/work/\n```\n\nThis will result in a request with files set and opened:\n\n```python\n>>> request.FILES.getlist(\"file\")\n[File(\"/priviliged/location/secrets.txt\")]\n```\n\nSince this behavior is injected via a middleware, any view can be called this way and will carry any files defined by the attacker.\n\nVia the `s3file` form field, any input name can be specified, including multiple inputs. For each input, multiple files can be freely\npicked of the S3 bucket.\n\n#### Scenarios and their practicality\n\nThere are four scenarios that would be considered practical in most setups:\n\n1. Illegal file injection,\n2. file deletion,\n3. file retrieval & tree traversal.\n4. code injection & remote code execution.\n\n##### File deletion\n\nAn attacker knows the location of a privileged file, like a static asset. Next, the file is injected into a form view. The upload to function will move the file to a new location. This is effectively deleting the file, since the previous references to it are invalid, and will cause S3 to return a 404. Furthermore, the new location is unknown to the site operator.\n\n##### File retrieval & tree traversal\n\nAn attacker knows the URL of a secret file and injects it into a form view. The view will move the file to a public location, making it accessible to the attacker. Since most form views will not be rate limited, this could also be used to guess files and traverse the file tree.\n\n##### Illegal file injection\n\nAn attacker uses any form to upload a file to the temporary upload location. Next, the attacker injects that file into a request, does not validate the contents or is not equipped to handle the mime type. The latter could be used as a potential DOS vector.\n\nIn practice, this is not a practical risk in most hardened setup. Files should always be sanitized before processing, since files can be included in a request even without this security issues.\n\n### For more information\nIf you have any questions or comments about this advisory:\n* Open an issue on [GitHub](https://github.com/codingjoe/django-s3file/issues)\n* Email us at [johannes@maron.family](mailto:johannes@maron.family)\n", + "severity": [ + { + "type": "CVSS_V3", + "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N" + } + ], + "affected": [ + { + "package": { + "ecosystem": "PyPI", + "name": "django-s3file" + }, + "ecosystem_specific": { + "affected_functions": [ + "s3file.forms.S3FileInputMixin", + "s3file.forms.S3FileInputMixin.build_attrs", + "s3file.middleware.S3FileMiddleware.__call__", + "s3file.middleware.S3FileMiddleware.get_files_from_storage" + ] + }, + "ranges": [ + { + "type": "ECOSYSTEM", + "events": [ + { + "introduced": "0" + }, + { + "fixed": "5.5.1" + } + ] + } + ] + } + ], + "references": [ + { + "type": "WEB", + "url": "https://github.com/codingjoe/django-s3file/security/advisories/GHSA-4w8f-hjm9-xwgf" + }, + { + "type": "ADVISORY", + "url": "https://nvd.nist.gov/vuln/detail/CVE-2022-24840" + }, + { + "type": "WEB", + "url": "https://github.com/codingjoe/django-s3file/commit/68ccd2c621a40eb66fdd6af2be9d5fcc9c373318" + }, + { + "type": "PACKAGE", + "url": "https://github.com/codingjoe/django-s3file" + }, + { + "type": "WEB", + "url": "https://github.com/codingjoe/django-s3file/releases/tag/5.5.1" + }, + { + "type": "WEB", + "url": "https://github.com/pypa/advisory-database/tree/main/vulns/django-s3file/PYSEC-2022-208.yaml" + } + ], + "database_specific": { + "cwe_ids": [ + "CWE-22", + "CWE-96" + ], + "severity": "CRITICAL", + "github_reviewed": true, + "github_reviewed_at": "2022-06-06T21:24:24Z", + "nvd_published_at": "2022-06-09T04:15:00Z" + } +} \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/redhat/redhat-expected.json b/vulnerabilities/tests/test_data/redhat/redhat-expected.json index dbaa18636..3e91555de 100644 --- a/vulnerabilities/tests/test_data/redhat/redhat-expected.json +++ b/vulnerabilities/tests/test_data/redhat/redhat-expected.json @@ -221,6 +221,6 @@ } ], "date_published": null, - "weaknesses": [] + "weaknesses": [400] } ] \ No newline at end of file diff --git a/vulnerabilities/tests/test_github.py b/vulnerabilities/tests/test_github.py index b0c2491ed..0f2e634d5 100644 --- a/vulnerabilities/tests/test_github.py +++ b/vulnerabilities/tests/test_github.py @@ -24,6 +24,7 @@ from vulnerabilities.importer import Reference from vulnerabilities.importer import VulnerabilitySeverity from vulnerabilities.importers.github import GitHubAPIImporter +from vulnerabilities.importers.github import get_cwes_from_github_advisory from vulnerabilities.importers.github import process_response from vulnerabilities.improvers.valid_versions import GitHubBasicImprover from vulnerabilities.tests.util_tests import VULNERABLECODE_REGEN_TEST_FIXTURES as REGEN @@ -311,3 +312,24 @@ def test_get_package_versions(mock_response): assert PackageURL(type="gem", name="foo") in improver.versions_fetcher_by_purl assert PackageURL(type="pypi", name="django") in improver.versions_fetcher_by_purl assert PackageURL(type="pypi", name="foo") in improver.versions_fetcher_by_purl + + +def test_get_cwes_from_github_advisory(): + assert get_cwes_from_github_advisory( + {"cwes": {"nodes": [{"cweId": "CWE-502"}, {"cweId": "CWE-770"}]}} + ) == [502, 770] + assert get_cwes_from_github_advisory( + { + "cwes": { + "nodes": [ + {"cweId": "CWE-173"}, + {"cweId": "CWE-200"}, + {"cweId": "CWE-378"}, + {"cweId": "CWE-732"}, + ] + } + } + ) == [173, 200, 378, 732] + assert get_cwes_from_github_advisory( + {"cwes": {"nodes": [{"cweId": "CWE-11111111111"}, {"cweId": "CWE-200"}]}} # invalid cwe-id + ) == [200] diff --git a/vulnerabilities/tests/test_pysec.py b/vulnerabilities/tests/test_pysec.py index f5d8107ac..efdcafe55 100644 --- a/vulnerabilities/tests/test_pysec.py +++ b/vulnerabilities/tests/test_pysec.py @@ -43,3 +43,16 @@ def test_to_advisories_without_summary(self): expected_file=expected_file, regen=REGEN, ) + + def test_to_advisories_with_cwe(self): + with open(os.path.join(TEST_DATA, "pysec-advisory_with_cwe.json")) as f: + mock_response = json.load(f) + + results = parse_advisory_data(mock_response, "pypi").to_dict() + + expected_file = os.path.join(TEST_DATA, "pysec-advisories_with_cwe-expected.json") + check_results_against_json( + results=results, + expected_file=expected_file, + regen=REGEN, + )