From 2d46140adeb22053d6605992c492c1f80deb3187 Mon Sep 17 00:00:00 2001 From: DefectDojo release bot Date: Mon, 30 Mar 2026 15:31:40 +0000 Subject: [PATCH 01/15] Update versions in application files --- components/package.json | 2 +- helm/defectdojo/Chart.yaml | 8 ++++---- helm/defectdojo/README.md | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/components/package.json b/components/package.json index b2fba0f3434..6b3989ffc93 100644 --- a/components/package.json +++ b/components/package.json @@ -1,6 +1,6 @@ { "name": "defectdojo", - "version": "2.56.4", + "version": "2.57.0-dev", "license" : "BSD-3-Clause", "private": true, "dependencies": { diff --git a/helm/defectdojo/Chart.yaml b/helm/defectdojo/Chart.yaml index 124076437fa..1c4b4f17620 100644 --- a/helm/defectdojo/Chart.yaml +++ b/helm/defectdojo/Chart.yaml @@ -1,8 +1,8 @@ apiVersion: v2 -appVersion: "2.56.4" +appVersion: "2.57.0-dev" description: A Helm chart for Kubernetes to install DefectDojo name: defectdojo -version: 1.9.20 +version: 1.9.21-dev icon: https://defectdojo.com/hubfs/DefectDojo_favicon.png maintainers: - name: madchap @@ -33,5 +33,5 @@ dependencies: # - kind: security # description: Critical bug annotations: - artifacthub.io/prerelease: "false" - artifacthub.io/changes: "- kind: changed\n description: Bump DefectDojo to 2.56.4\n" + artifacthub.io/prerelease: "true" + artifacthub.io/changes: "" diff --git a/helm/defectdojo/README.md b/helm/defectdojo/README.md index bbfee360b77..dafb3d4798b 100644 --- a/helm/defectdojo/README.md +++ b/helm/defectdojo/README.md @@ -511,7 +511,7 @@ The HELM schema will be generated for you. # General information about chart values -![Version: 1.9.20](https://img.shields.io/badge/Version-1.9.20-informational?style=flat-square) ![AppVersion: 2.56.4](https://img.shields.io/badge/AppVersion-2.56.4-informational?style=flat-square) +![Version: 1.9.21-dev](https://img.shields.io/badge/Version-1.9.21--dev-informational?style=flat-square) ![AppVersion: 2.57.0-dev](https://img.shields.io/badge/AppVersion-2.57.0--dev-informational?style=flat-square) A Helm chart for Kubernetes to install DefectDojo From 1f907ce3410f47f7cf58bd20623a2b51a32689e0 Mon Sep 17 00:00:00 2001 From: dogboat Date: Wed, 1 Apr 2026 13:25:15 -0400 Subject: [PATCH 02/15] Migration endpoints to locations fix (#14625) * update migrate_endpoints_to_locations mgmt command to work when v3/locations enabled * include progress report on endpoint to location migration * linter fixes --- .../migrate_endpoints_to_locations.py | 38 +++++++++++++++---- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/dojo/management/commands/migrate_endpoints_to_locations.py b/dojo/management/commands/migrate_endpoints_to_locations.py index d30fa121d3b..25c739abb0a 100644 --- a/dojo/management/commands/migrate_endpoints_to_locations.py +++ b/dojo/management/commands/migrate_endpoints_to_locations.py @@ -11,6 +11,9 @@ logger = logging.getLogger(__name__) +# Chunk size for DB cursor and progress report +CHUNK_SIZE = 1000 + class Command(BaseCommand): @@ -88,10 +91,31 @@ def _associate_location_with_findings(self, endpoint: Endpoint, location: Locati location.associate_with_product(product) def handle(self, *args, **options): - # Start off with the endpoint objects - it should everything we need - for endpoint in Endpoint.objects.all().iterator(): - # Get the URL object first - location = self._endpoint_to_url(endpoint) - # Associate the URL with the findings associated with the Findings - # the association to a finding will also apply to a product automatically - self._associate_location_with_findings(endpoint, location) + # Allow endpoints to work with V3/Locations enabled + with Endpoint.allow_endpoint_init(): + # Progress counter + i = 0 + # Start off with the endpoint objects - it should contain everything we need + queryset = Endpoint.objects.all() + # Grab the total count so we can communicate progress + endpoint_count = queryset.count() + + # Process each endpoint + for i, endpoint in enumerate(queryset.iterator(chunk_size=CHUNK_SIZE), 1): + # Progress report every chunk + if not i % CHUNK_SIZE: + self.stdout.write( + self.style.SUCCESS( + f"Migrated {i}/{endpoint_count} endpoints...", + ), + ) + # Get the URL object first + location = self._endpoint_to_url(endpoint) + # Associate the URL with the findings associated with the Findings + # the association to a finding will also apply to a product automatically + self._associate_location_with_findings(endpoint, location) + self.stdout.write( + self.style.SUCCESS( + f"Migrated {i} total endpoints.", + ), + ) From 855f6dfa42ff41cf5b9d98fd6d32cdc8360b2f5d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2026 12:51:59 -0600 Subject: [PATCH 03/15] chore(deps): bump yaml from 2.8.2 to 2.8.3 in /docs (#14599) Bumps [yaml](https://github.com/eemeli/yaml) from 2.8.2 to 2.8.3. - [Release notes](https://github.com/eemeli/yaml/releases) - [Commits](https://github.com/eemeli/yaml/compare/v2.8.2...v2.8.3) --- updated-dependencies: - dependency-name: yaml dependency-version: 2.8.3 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/package-lock.json b/docs/package-lock.json index 2c86e0d3d7c..8e52c480d21 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -4618,9 +4618,9 @@ "license": "ISC" }, "node_modules/yaml": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", - "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", + "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", "license": "ISC", "bin": { "yaml": "bin.mjs" From db3b748e7759bd0e592b901a466c95dd3ae6a458 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2026 12:52:24 -0600 Subject: [PATCH 04/15] chore(deps): bump brace-expansion in /docs (#14600) Bumps and [brace-expansion](https://github.com/juliangruber/brace-expansion). These dependencies needed to be updated together. Updates `brace-expansion` from 1.1.12 to 1.1.13 - [Release notes](https://github.com/juliangruber/brace-expansion/releases) - [Commits](https://github.com/juliangruber/brace-expansion/compare/v1.1.12...v1.1.13) Updates `brace-expansion` from 5.0.3 to 5.0.5 - [Release notes](https://github.com/juliangruber/brace-expansion/releases) - [Commits](https://github.com/juliangruber/brace-expansion/compare/v1.1.12...v1.1.13) --- updated-dependencies: - dependency-name: brace-expansion dependency-version: 1.1.13 dependency-type: indirect - dependency-name: brace-expansion dependency-version: 5.0.5 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs/package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/package-lock.json b/docs/package-lock.json index 8e52c480d21..39caf2b63d8 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -2632,9 +2632,9 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", + "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -3939,9 +3939,9 @@ } }, "node_modules/purgecss/node_modules/brace-expansion": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", - "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" From 4a3ee14d41ee48efcdfea0a988e723989313c64d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2026 12:52:54 -0600 Subject: [PATCH 05/15] chore(deps): bump cryptography from 46.0.5 to 46.0.6 (#14602) Bumps [cryptography](https://github.com/pyca/cryptography) from 46.0.5 to 46.0.6. - [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pyca/cryptography/compare/46.0.5...46.0.6) --- updated-dependencies: - dependency-name: cryptography dependency-version: 46.0.6 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index aad591eda5f..0bf1275eb6c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -31,7 +31,7 @@ Markdown==3.10.2 openpyxl==3.1.5 Pillow==12.1.1 # required by django-imagekit psycopg[c]==3.3.3 -cryptography==46.0.5 +cryptography==46.0.6 python-dateutil==2.9.0.post0 redis==7.2.0 requests==2.33.0 From c1f254381295997ddc5923734b4a8a2d623d0887 Mon Sep 17 00:00:00 2001 From: Valentijn Scholten Date: Wed, 1 Apr 2026 22:20:48 +0200 Subject: [PATCH 06/15] fix(reimport): do not update finding tags on reimport for matched findings Tags from the report were being appended to matched findings via tags.add(), causing tags to accumulate across reimports instead of being left unchanged. This aligns tag handling with how other finding fields are treated on reimport. Closes #14606 --- dojo/importers/default_reimporter.py | 32 +++++++++++++++++----------- unittests/test_tags.py | 6 +++--- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/dojo/importers/default_reimporter.py b/dojo/importers/default_reimporter.py index 2828b8cec30..2a24afe8981 100644 --- a/dojo/importers/default_reimporter.py +++ b/dojo/importers/default_reimporter.py @@ -409,6 +409,7 @@ def process_findings( finding = self.finding_post_processing( finding, unsaved_finding, + is_matched_finding=bool(matched_findings), ) # all data is already saved on the finding, we only need to trigger post processing in batches push_to_jira = self.push_to_jira and ((not self.findings_groups_enabled or not self.group_by) or not finding_will_be_grouped) @@ -926,6 +927,8 @@ def finding_post_processing( self, finding: Finding, finding_from_report: Finding, + *, + is_matched_finding: bool = False, ) -> Finding: """ Save all associated objects to the finding after it has been saved @@ -940,19 +943,22 @@ def finding_post_processing( self.endpoint_manager.chunk_endpoints_and_disperse(finding, finding_from_report.unsaved_endpoints) if len(self.endpoints_to_add) > 0: self.endpoint_manager.chunk_endpoints_and_disperse(finding, self.endpoints_to_add) - # Parsers shouldn't use the tags field, and use unsaved_tags instead. - # Merge any tags set by parser into unsaved_tags - tags_from_parser = finding_from_report.tags if isinstance(finding_from_report.tags, list) else [] - unsaved_tags_from_parser = finding_from_report.unsaved_tags if isinstance(finding_from_report.unsaved_tags, list) else [] - merged_tags = unsaved_tags_from_parser + tags_from_parser - if merged_tags: - finding_from_report.unsaved_tags = merged_tags - if finding_from_report.unsaved_tags: - cleaned_tags = clean_tags(finding_from_report.unsaved_tags) - if isinstance(cleaned_tags, list): - finding.tags.add(*cleaned_tags) - elif isinstance(cleaned_tags, str): - finding.tags.add(cleaned_tags) + # For matched/existing findings, do not update tags from the report, + # consistent with how other fields are handled on reimport. + if not is_matched_finding: + # Parsers shouldn't use the tags field, and use unsaved_tags instead. + # Merge any tags set by parser into unsaved_tags + tags_from_parser = finding_from_report.tags if isinstance(finding_from_report.tags, list) else [] + unsaved_tags_from_parser = finding_from_report.unsaved_tags if isinstance(finding_from_report.unsaved_tags, list) else [] + merged_tags = unsaved_tags_from_parser + tags_from_parser + if merged_tags: + finding_from_report.unsaved_tags = merged_tags + if finding_from_report.unsaved_tags: + cleaned_tags = clean_tags(finding_from_report.unsaved_tags) + if isinstance(cleaned_tags, list): + finding.tags.add(*cleaned_tags) + elif isinstance(cleaned_tags, str): + finding.tags.add(cleaned_tags) # Process any files if finding_from_report.unsaved_files: finding.unsaved_files = finding_from_report.unsaved_files diff --git a/unittests/test_tags.py b/unittests/test_tags.py index f29ea69f6ae..b9077e1daab 100644 --- a/unittests/test_tags.py +++ b/unittests/test_tags.py @@ -369,12 +369,12 @@ def assert_tags_in_findings(findings: list[dict], expected_finding_count: int, d findings = response["results"] # Make sure we have what we are looking for assert_tags_in_findings(findings, 2, ["security", "network"]) - # Reimport with a different report that has more tags + # Reimport with a different report that has more tags — matched findings should retain their original tags self.reimport_scan_with_params(test_id, self.generic_sample_with_more_tags_filename, scan_type="Generic Findings Import") response = self.get_test_findings_api(test_id) findings = response["results"] - # Make sure we have what we are looking for - assert_tags_in_findings(findings, 2, ["security", "network", "hardened"]) + # Tags from the report are not applied to matched findings on reimport, consistent with other fields + assert_tags_in_findings(findings, 2, ["security", "network"]) @versioned_fixtures From c374cfa8d8b7b0cae1cc3e5d01e379fe6170c008 Mon Sep 17 00:00:00 2001 From: Valentijn Scholten Date: Thu, 2 Apr 2026 21:00:54 +0200 Subject: [PATCH 07/15] fix: clear all M2M through tables (forward and reverse) before deletion Both bulk_clear_finding_m2m and cascade_delete_related_objects only cleared forward M2M tables (model._meta.many_to_many). Reverse M2M fields defined on other models (Finding_Group.findings, Risk_Acceptance.accepted_findings, EnhancedRiskAcceptance.affected_engagements) were missed, causing FK violations during bulk deletion. Use get_fields() which returns both forward ManyToManyField (via field.remote_field.through) and reverse ManyToManyRel (via field.through) to discover all through tables. Add test covering Finding_Group and Risk_Acceptance reverse M2M cleanup. --- dojo/finding/helper.py | 15 +++-- dojo/utils_cascade_delete.py | 47 +++++++------- .../test_prepare_duplicates_for_delete.py | 63 ++++++++++++++++++- 3 files changed, 99 insertions(+), 26 deletions(-) diff --git a/dojo/finding/helper.py b/dojo/finding/helper.py index 18ddeba98e2..6c89c15b20c 100644 --- a/dojo/finding/helper.py +++ b/dojo/finding/helper.py @@ -726,11 +726,18 @@ def bulk_clear_finding_m2m(finding_qs): # Remove tags with proper count maintenance bulk_remove_all_tags(Finding, finding_ids) - # Auto-discover and delete remaining (non-tag) M2M through tables - for m2m_field in Finding._meta.many_to_many: - if hasattr(m2m_field, "tag_options"): + # Auto-discover and delete M2M through tables — both forward (Finding._meta.many_to_many) + # and reverse (other models with ManyToManyField pointing to Finding, e.g. Finding_Group.findings). + # Forward M2M fields use field.remote_field.through, reverse use field.through. + m2m_through_models = set() + for field_info in Finding._meta.get_fields(): + if hasattr(field_info, "tag_options"): continue - through_model = m2m_field.remote_field.through + through = getattr(field_info, "through", None) or getattr(getattr(field_info, "remote_field", None), "through", None) + if through is not None: + m2m_through_models.add(through) + + for through_model in m2m_through_models: # Find the FK column that points to Finding fk_column = None for field in through_model._meta.get_fields(): diff --git a/dojo/utils_cascade_delete.py b/dojo/utils_cascade_delete.py index b8c0ee4af66..044c45a539e 100644 --- a/dojo/utils_cascade_delete.py +++ b/dojo/utils_cascade_delete.py @@ -159,27 +159,32 @@ def cascade_delete_related_objects(from_model, instance_pk_query, skip_relations bulk_remove_all_tags(from_model, instance_pk_query) - for m2m_field in from_model._meta.many_to_many: - # Skip tag fields — handled by bulk_remove_all_tags above - if hasattr(m2m_field, "tag_options"): - continue - # Skip if caller already cleaned M2M for this model - if from_model in skip_m2m_for: - continue - through_model = m2m_field.remote_field.through - fk_column = None - for field in through_model._meta.get_fields(): - if hasattr(field, "related_model") and field.related_model is from_model: - fk_column = field.column - break - if fk_column: - filterspec_m2m = {f"{fk_column}__in": models.Subquery(instance_pk_query)} - m2m_count = execute_delete_sql(through_model.objects.filter(**filterspec_m2m)) - if m2m_count: - logger.debug( - "cascade_delete: cleared %d rows from M2M %s", - m2m_count, through_model._meta.db_table, - ) + # Clear all M2M through tables — both forward (from_model._meta.many_to_many) + # and reverse (other models with ManyToManyField pointing to from_model). + # Forward M2M fields use field.remote_field.through, reverse use field.through. + if from_model not in skip_m2m_for: + m2m_through_models = set() + for field_info in from_model._meta.get_fields(): + if hasattr(field_info, "tag_options"): + continue + through = getattr(field_info, "through", None) or getattr(getattr(field_info, "remote_field", None), "through", None) + if through is not None: + m2m_through_models.add(through) + + for through_model in m2m_through_models: + fk_column = None + for field in through_model._meta.get_fields(): + if hasattr(field, "related_model") and field.related_model is from_model: + fk_column = field.column + break + if fk_column: + filterspec_m2m = {f"{fk_column}__in": models.Subquery(instance_pk_query)} + m2m_count = execute_delete_sql(through_model.objects.filter(**filterspec_m2m)) + if m2m_count: + logger.debug( + "cascade_delete: cleared %d rows from M2M %s", + m2m_count, through_model._meta.db_table, + ) # At level 0, do NOT delete root records — the caller handles that # (e.g. via ORM obj.delete() to fire Django signals). diff --git a/unittests/test_prepare_duplicates_for_delete.py b/unittests/test_prepare_duplicates_for_delete.py index de786c50ad6..3630f287fdf 100644 --- a/unittests/test_prepare_duplicates_for_delete.py +++ b/unittests/test_prepare_duplicates_for_delete.py @@ -13,7 +13,19 @@ from django.utils import timezone from dojo.finding.helper import prepare_duplicates_for_delete -from dojo.models import Engagement, Finding, Product, Product_Type, Test, Test_Type, User, UserContactInfo +from dojo.models import ( + Dojo_User, + Engagement, + Finding, + Finding_Group, + Product, + Product_Type, + Risk_Acceptance, + Test, + Test_Type, + User, + UserContactInfo, +) from .dojo_test_case import DojoTestCase @@ -409,3 +421,52 @@ def test_delete_product_with_tags(self): self.assertEqual(product_shared_tag.count, 0) finding_shared_tag.refresh_from_db() self.assertEqual(finding_shared_tag.count, 0) + + def test_delete_product_with_reverse_m2m_relations(self): + """ + Deleting a product with findings that have reverse M2M relations succeeds. + + Reverse M2M through tables (M2M fields on other models pointing to Finding) + must be cleared before findings are deleted. This tests: + - Finding_Group.findings (dojo_finding_group_findings) + - Risk_Acceptance.accepted_findings (dojo_risk_acceptance_accepted_findings) + """ + from dojo.utils import async_delete # noqa: PLC0415 + + finding_a = self._create_finding(self.test1, "Grouped Finding A") + finding_b = self._create_finding(self.test1, "Grouped Finding B") + finding_c = self._create_finding(self.test1, "Risk Accepted Finding") + + # Finding_Group with findings + creator = Dojo_User.objects.first() or Dojo_User.objects.create(username="testcreator") + group = Finding_Group.objects.create( + name="Test Group", + test=self.test1, + creator=creator, + ) + group.findings.add(finding_a, finding_b) + + # Risk_Acceptance with accepted findings + ra = Risk_Acceptance.objects.create( + name="Test RA", + owner=self.testuser, + ) + ra.accepted_findings.add(finding_c) + # Link to engagement so we can verify it survives + self.engagement1.risk_acceptance.add(ra) + + product_id = self.product.id + group_id = group.id + ra_id = ra.id + + with impersonate(self.testuser): + async_del = async_delete() + async_del.delete(self.product) + + self.assertFalse(Product.objects.filter(id=product_id).exists()) + self.assertFalse(Finding_Group.objects.filter(id=group_id).exists()) + self.assertFalse(Finding.objects.filter(id__in=[finding_a.id, finding_b.id, finding_c.id]).exists()) + # Risk_Acceptance itself survives (no FK to product/engagement), + # but its accepted_findings M2M entries should be gone + self.assertTrue(Risk_Acceptance.objects.filter(id=ra_id).exists()) + self.assertEqual(Risk_Acceptance.objects.get(id=ra_id).accepted_findings.count(), 0) From b127bb12c9605c62de14472c1255a8715bda1f24 Mon Sep 17 00:00:00 2001 From: dogboat Date: Fri, 3 Apr 2026 15:40:15 -0400 Subject: [PATCH 08/15] =?UTF-8?q?when=20deleting=20a=20URL=20via=20API,=20?= =?UTF-8?q?perform=5Fdelete=20should=20call=20delete=20on=20the=E2=80=A6?= =?UTF-8?q?=20(#14612)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * when deleting a URL via API, perform_delete should call delete on the abstractlocation instance (cascades down) * add tests for it --- dojo/url/api/views.py | 3 +++ unittests/test_rest_framework.py | 13 +++++++++++++ 2 files changed, 16 insertions(+) diff --git a/dojo/url/api/views.py b/dojo/url/api/views.py index 816e30b60a5..caebd867bec 100644 --- a/dojo/url/api/views.py +++ b/dojo/url/api/views.py @@ -36,3 +36,6 @@ def get_queryset(self) -> QuerySet[URL]: return URL.objects.annotate( active_findings=Coalesce(active_finding_subquery, Value(0)), ) + + def perform_destroy(self, instance): + instance.location.delete() diff --git a/unittests/test_rest_framework.py b/unittests/test_rest_framework.py index cd76daa0627..fc8f2e588f8 100644 --- a/unittests/test_rest_framework.py +++ b/unittests/test_rest_framework.py @@ -1612,6 +1612,19 @@ def test_update_object_not_authorized(self): response = self.client.put(relative_url, self.payload) self.assertEqual(403, response.status_code, response.content[:1000]) + def test_delete_removes_location(self): + """Verify that deleting a URL via the API also deletes the associated Location.""" + url_obj = URL.objects.get(pk=self.delete_id) + location_id = url_obj.location_id + self.assertTrue(Location.objects.filter(pk=location_id).exists()) + + relative_url = f"{self.url}{location_id}/" + response = self.client.delete(relative_url) + self.assertEqual(204, response.status_code, response.content[:1000]) + + self.assertFalse(Location.objects.filter(pk=location_id).exists()) + self.assertFalse(URL.objects.filter(pk=self.delete_id).exists()) + @versioned_fixtures class EngagementTest(BaseClass.RelatedObjectsTest, BaseClass.BaseClassTest): From da8f0e76789f150bca06ff162ac65ef009664dde Mon Sep 17 00:00:00 2001 From: Paul Osinski <42211303+paulOsinski@users.noreply.github.com> Date: Fri, 3 Apr 2026 15:46:23 -0400 Subject: [PATCH 09/15] [docs] changelog, maintenance (#14614) * update pro changelog * update graphics colors for dark mode * split jira guide into os/pro context --- .../images/Product_Hierarchy_Overview.png | Bin 39327 -> 40042 bytes .../images/Product_Hierarchy_Overview_2.png | Bin 33046 -> 32593 bytes .../about/OS__new_user_checklist.md | 2 +- docs/content/get_started/about/faq.md | 4 +- .../jira/{jira_guide.md => OS__jira_guide.md} | 166 ++---- .../issue_tracking/jira/PRO__jira_guide.md | 562 ++++++++++++++++++ .../jira/troubleshooting_jira.md | 6 +- docs/content/releases/pro/changelog.md | 24 + 8 files changed, 626 insertions(+), 138 deletions(-) rename docs/content/issue_tracking/jira/{jira_guide.md => OS__jira_guide.md} (72%) create mode 100644 docs/content/issue_tracking/jira/PRO__jira_guide.md diff --git a/docs/assets/images/Product_Hierarchy_Overview.png b/docs/assets/images/Product_Hierarchy_Overview.png index a0502462f98636d6e7b3ad073acd03a726a8ae16..3a6b683a3281bed28f5ddca814924d03d8832d5f 100644 GIT binary patch literal 40042 zcmeFY*IQH17dINZsEAYrq^Pt|rFRfTfzTu%B~+yodhb<51*xHjq7aZ05JCvONbd+3 zN~qEay@z`E{?2)xbNl`Q@7(RVn7wCa&8)pX<;xpwRjS*}w*deEmAaY=7yuv{1OSNS zZ;{{h&F8TqU9YrHQvgvPck z9`GH$Fu5&AKTg~+^R=E#UF{ZU4cD%M-SM_9%IQVehZ*(RxdQoruBKQHJplRgt}! z9>=`|$`V^Lgeh%JVZns#K;q|SAwvW~T zDNvI3#Y-LHwR{+aT!~>GPsQ=1x1A9*e6bd(bI_GPaJVrmCA~6S6b-n-LhPchPmY7{ zo6E&0qo|H*QNELxs>doM4;Ocw1<9hh>_fK5I(B3-YwavC@1-$10a;yBRa>?8$V_6t z++aWHNL!YTneQYKL+}LDUph24B(v=IfAc1>M^dOw{Wug)Qka>=-=kDRNZE2+;QBln z2YNfkoX(l0Ph**F8*-X4XzMDhFA*<~!hp3-B*l?{!#^Suw1TjrY*TRH@e?u|HL*$E zdTy=Cp;LT031BuX=l#5<3QQzhf!13#etq)ThjXJUfA}~u6hBj|N)b!)t2S7qUU(`O z=^r4u`;RDOXwtO$;M{Za*Oq_rc=d(>?PRz1o}fx zIp|cr&D!8+iEs0BUk!_NC&zKmrGA>NN-oroZ)0#R{d~?Ql7~l zL8>d1{00JAcg$=2XqvUMW4>HpMc+gLXPZ<^*_XEpZ=u1H)2ZJ{<%oi)EI*Xe5+WM+OjQH`c>*O7JfqA@hE{ncEm3_j@#Lh*9{R4jx{mIESo0r7* z4(m_tKYvKh=}i)olx3^cEAid#i+j|n6#Zbar+)jz z2P8CIM$C{8G3e$?_~;Z)1eYDz?iV>cAxRhHpi+9+(@d7XY}kC=!}!p?Yk=E#<>A@+ z$uyN*=t2a8c$d@EhYE|J1^mEw@pypgFtNnCKEUAnn~r<>|Nv)JzX5$U_&Bw8>=Q zO8wuRmN280CPqPhxP`|L_%&9licvRqwJ9g$dmw3 zz=3Te4Lo0pPO0=?CUP`PR=aPf@h8 zchW14E}$Z7wT>btX1S5nG7r3A%547B>hBN`;gc^ak2@kqo8~+y8dS%?bf}t3wrVf^I3qW{k)qBE4+W;-A5Qc|(8<0R9JJ_!h)E z4AIbyv>QOw;GkB3AoBUpeYWi#U^&^d{zEr8_Ds@wS6AFm^c8)}!OFG*sAz8HCLOd$ zt!!t4ihO6Xldci_Q}tRL>p`XwwRSM@=)mO`_pryAHuRD;tP2KyIWVzPKEQcITP15Y z2GIfR)`0nrr;Zzrnmo?7_{Cf^&b>%0Aovp)*rHbOoH^_Sa7eoQQDz~YW3eI`oP@^8 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 literal 39327 zcmeFZWn9!<*FS2~rHC|$C?MTA0|E*vCDL62(hSW|N(>Du4Z|Rybf>iB(A_-@9nvts z0O#j*-Piqpo^$^9dH(OtoAZVj^IF%o1rH?}zIM^RQ zEcs;G92NJNAcUUq<(CXo+`HfLLc%iqiD{R19ULax4L_glO4P+{_vyDhU3OXXkQz9Y zeBUHcU0t_OgPu<{O{nzAIOl1(2m+*G-rf&u792+>#ZETEber5@P7I7?Etrr!Mv#NLC1-mgkL-&{z{6+eI~Ih zf*)bR5T_?_itH(3I2kERpzLxrYI^-reV|B(#UasUhp}*`3j3>P#;c{Y>S1t8h8*$y z@7dBZMgf-SuZ#^~mF_gdtj9S6^9GN0n=X=@>Rjv(t)S3k=LP2!v*0LtzL|nPH*s Dmc3;S3UbTNnOf%X;*H{{{ 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

ey4#7H#R2>|YGh5|2d%T4yi{L{dj9w*)-;hr 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 z zC>L+kd9lraic(cY8#Rchx?kaE(?g18GW1+ygJWv(D32>E5f$Qo7`C{%k}z+xgm`+f z9f*$%aIZwL!VSA_5eRS1BHky-friXX`zT9)gk))Pf91q>`64_%uw` zjgBS}^~T*b1bJqR_^D(2bjlplP8ePm@T<)DC}#aZ>&sajJ0MvldPNof`|kYQ`05is z7r;}B>{}}`@3y7C=hf8^jCtjO$xLDdSJNUPA(;aiUqEf_9{=#QaGdZ82=OZoLM975 z?C!`OpmD}krn%!uGM?d&rCB{Z{96}$^a&y|k57f<_DA0Il67E&2%c0XFzjA%^jA0P zu$=)|NAt_4jfH1&IBlRjB^zJemP_^wPzFzdc0G1IPq|*mfa0 z8xD^`&zV;`836>5KM+ld_IU)=PnjKCTP4!GR`4UruPE^E1pOJR`npD|TF`lg`kCTq zb^yBKQGY-<>rX?NKvY^FO*+tX1FfrTtIN+qex(DXBQy%7h`5BW15#kQgrQ8su>J9c z5ap5uKu!ahPVUA_rKygp7~Hvz)9KFAUwV5(f68>Ru_GtOF@%lDCcgs-VqXgDM-qv$ zGxf>e#T<1F@6M@Xb}&=NGH^&*908%}w32G00k+u-C}cqW=gJC0{u@1J-&CLB5g&RO z-_H6(Zo4@Q&CI;j092+~^9Y)081UY)YGu@|wE*6;bBu&vJU!K`+cMbAT5Kk& z9#O{i9eTj(Q&O={x`|-uoO`m|cfPeylb11q%Y_qfV3vgi!wPwQ%6&B0Uj8@Ix!u03 zB~H5iadaV`p$h9{ESU`dYHdwR?z{ea0ZYr^$RHrBGwZjaM+J0{fna|Vc@E@(ay2FW zEQ|u$$1)`UptX1TW6BMG9_;xlz>yx44N=&nwN(sr!x9Y=zZ~CSS{_p(sapDSUMCws@ zZN5n$yOCXg-zy*C=5lLU1!fx*9?7z5O9aNc2gsVBhM6V_*1GEU=qC*a$Lw$3oYmkB zly%Qpy^26OqFf^#K1&`nb@Ho36P7$mnK<5pyDvGU+9Azhe&6PdBvUbmsxL_eW;qg? z0oC=%?HXvrI;ln=IBY`5417kp?4U1W)9o@F6Ldzhw2lHxvhI$t2v$G>b#V*Oe;#Tz zw!~I8yHig~i~m)?VAU^X;S|t4yxBdloytkadFYr+t_>9z=iw4O{`I`Retn7RxX7m8~fg|5U< zTmI0kq@XAr$0A9XCTM%IL(fHU9PD?F%KNuPuBsJc{yAK2%k5G}ed^(vRz6x#@a@{# zT1>1xq;#N`l(a*=aluS2xVpE8MW~* z<#V=0nzOaEG@Nu%_27Y+bUGiG01jOc8IP($kmEu%w9Zr;H1mER`~UXR60rX5&Zv+> TAJR|ML9yA}I3r3=UHakQrKb<+ diff --git a/docs/assets/images/Product_Hierarchy_Overview_2.png b/docs/assets/images/Product_Hierarchy_Overview_2.png index cb4b3b8514b88b18bae4f8ef004cdad83823e68c..20760513bbb3ae3043dc62fec5ef302217918b42 100644 GIT binary patch literal 32593 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∾KV100pN4ygD!wIgf!fx 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 diff --git a/docs/content/get_started/about/OS__new_user_checklist.md b/docs/content/get_started/about/OS__new_user_checklist.md index ebf29ec20f8..cf977048319 100644 --- a/docs/content/get_started/about/OS__new_user_checklist.md +++ b/docs/content/get_started/about/OS__new_user_checklist.md @@ -23,6 +23,6 @@ This is the essence of DefectDojo - import security data, organize it, and prese All of these features can be automated, and because DefectDojo can handle over 200 tools (at time of writing) you should be all set to create a functional security inventory of your entire organizational output. ### Open-Source Features -- Does your organization use Jira? Learn how to use our [Jira integration](/issue_tracking/jira/jira_guide/) to create Jira tickets from the data you ingest. +- Does your organization use Jira? Learn how to use our [Jira integration](/issue_tracking/jira/os__jira_guide/) to create Jira tickets from the data you ingest. - Are you expecting to share DefectDojo with many users in your organization? Check out our guides to [user management](/admin/user_management/about_perms_and_roles/) and set up role-based access control (RBAC). - Ready to dive into automation? Learn how to use the [DefectDojo API](/import_data/import_scan_files/api_pipeline_modelling/) to automatically import new data, and build a robust CI/CD pipeline. \ No newline at end of file diff --git a/docs/content/get_started/about/faq.md b/docs/content/get_started/about/faq.md index 7c6593f6c6a..ab14697cec4 100644 --- a/docs/content/get_started/about/faq.md +++ b/docs/content/get_started/about/faq.md @@ -21,7 +21,7 @@ DefectDojo is meant to be the central source of truth for your organization's se - Allowing users to identify duplicate findings across scans and tools, minimizing alert fatigue. - Enforcing SLAs on vulnerabilities, ensuring that your organization handles each Finding within an appropriate timeframe. -- Sending tickets to [Jira](/issue_tracking/jira/jira_guide/), ServiceNow or other Project Tracking software, allowing your development team to integrate issue remediation into their standard release process without requiring them to learn another project management tool. +- [Sending tickets](/issue_tracking/intro/intro/) to Jira, ServiceNow or other Project Tracking software, allowing your development team to integrate issue remediation into their standard release process without requiring them to learn another project management tool. - Integrating into automated [CI/CD pipelines](/import_data/import_scan_files/api_pipeline_modelling/) to automatically ingest report data from repositories, even down to the branch level. - Creating [reports](/metrics_reports/reports/using_the_report_builder/) on any set of vulnerabilities or software context, to quickly share scan results or status updates with stakeholders. - Establishing acceptance and mitigation workflows, supporting formal risk-management tracking. @@ -129,6 +129,6 @@ DefectDojo Pro users also have access to [executive-level Metrics dashboards](/g ### How can I integrate a project management tool with DefectDojo? -In both Pro and Open-Source editions of DefectDojo, Findings in DefectDojo can be pushed to Jira as Issues, which allows you to integrate issue remediation with your development team. We have a [complete guide to Jira](/issue_tracking/jira/jira_guide/) written which describes the process in detail. +In both Pro and Open-Source editions of DefectDojo, Findings in DefectDojo can be pushed to Jira as Issues, which allows you to integrate issue remediation with your development team. DefectDojo Pro adds support for [Additional Project Tracking Integrations](/issue_tracking/intro/intro/)**: ServiceNow, Azure DevOps, GitHub and GitLab. \ No newline at end of file diff --git a/docs/content/issue_tracking/jira/jira_guide.md b/docs/content/issue_tracking/jira/OS__jira_guide.md similarity index 72% rename from docs/content/issue_tracking/jira/jira_guide.md rename to docs/content/issue_tracking/jira/OS__jira_guide.md index 9fcd50530be..a9dca184057 100644 --- a/docs/content/issue_tracking/jira/jira_guide.md +++ b/docs/content/issue_tracking/jira/OS__jira_guide.md @@ -1,9 +1,8 @@ --- title: "📋 Jira Integration Guide" description: "Work with the Jira integration" -weight: 1 -aliases: - - /en/share_your_findings/jira_guide +weight: 2 +audience: opensource --- DefectDojo's Jira integration can be used to push Finding data to one or more Jira Spaces. By doing so, you can integrate DefectDojo into your standard development workflow. Here are some examples of how this can work: @@ -19,11 +18,11 @@ Setting Up Jira requires the following steps: ## Step 1: Connect a Jira Instance -Connecting a Jira Instance is the first step to take when setting up DefectDojo’s Jira integration. Please note Jira Service Management is currently not supported. +Connecting a Jira Instance is the first step to take when setting up DefectDojo's Jira integration. Please note Jira Service Management is currently not supported. #### Required information from Jira -Atlassian uses different ways of authentication between Jira Cloud and Jira Data Center. +Atlassian uses different methods of authentication between Jira Cloud and Jira Data Center. for **Jira Cloud**, you will need: * a Jira URL, i.e. https://yourcompany.atlassian.net/ @@ -35,7 +34,6 @@ for **Jira Data Center (or Server)**, you will need: * a Jira URL, i.e. https://jira.yourcompany.com * an account with permissions to create and update issues in your Jira instance. This can be: * A standard **username / password** combination - * A **emailaddress / Personal Access Token** combination (not supported in Defect Dojo Open-Source) Optionally, you can map: * Jira Transitions to trigger Re-Opening and Closing Findings @@ -43,45 +41,7 @@ Optionally, you can map: Multiple Jira Spaces can be handled by a single Jira Instance connection, as long as the Jira account / token used by DefectDojo has permission to create Issues in the associated Jira Space. -### Add a Jira Instance (Pro UI) - -1. If you have not already done so, navigate to the System Settings page and check the box on **Enable Jira Integration**. - -2. Navigate to the **Enterprise Settings \> Jira Instances \> + New Jira Instance** page from the DefectDojo sidebar. - -![image](images/jira-instance-beta.png) - -3. Select a **Configuration Name** for this Jira Instance to use in DefectDojo. This name is simply a label for the Instance connection in DefectDojo, and does not need to be related to any Jira data. - -4. Select the URL for your company’s Jira instance \- likely similar to `https://**yourcompany**.atlassian.net` if you’re using a Jira Cloud installation. - -5. Enter an appropriate authetication method in the Username / Password fields for Jira: - * For standard **username / password Jira authentication**, enter a Jira Username and corresponding Password in these fields. - * For authentication with a **user's API token (Jira Cloud)** enter the Username with the corresponding **API token** in the password field. - * For authentication with a Jira **Personal Access Token (aka PAT, used in Jira Data Center and Jira Server only)**, enter the PAT in the password field. Username is not used for authentication with a Jira PAT, but the field is still required in this form, so you can use a placeholder value here to identify your PAT. - -Note that the user associated with this connection have permission to create Issues and access data in your Jira instance. - -6. You will need to provide values for an Epic Name ID, Re-open Transition ID and Close Transition ID. These values can be changed later. While logged into Jira, you can access these values from the following URLs: -- **Epic Name ID**: visit `https:///rest/api/2/field` and search for Epic Name. Copy the number out of `number` and paste it here. If you do not have an Epic Name ID associated with your Space in Jira (due to using a Team-Managed Space, for example), enter 0 on this field. -- **Re-open Transition ID**: visit `https:///rest/api/latest/issue//transitions?expand-transitions.fields` to find the ID for your Jira instance. Paste it in the Reopen Transition ID field. -- **Close Transition ID**: Visit `https:///rest/api/latest/issue//transitions?expand-transitions.fields` to find the ID for your Jira instance. Paste it in the Close Transition ID field. - -7. Select the Default issue type which you want to create Issues as in Jira. The options for this are **Bug, Task, Story** and **Epic** (which are standard Jira issue types) as well as **Spike** and **Security**, which are custom issue types. If you have a different Issue Type which you want to use, please contact [support@defectdojo.com](mailto:support@defectdojo.com) for assistance. - -8. Select your Issue Template, which will determine the Issue Description when Issues are created in Jira. - -The two types are: -- **Jira\_full**, which will include all Finding information in Jira Issues -- **Jira\_limited**, which will include a smaller amount of Finding information and metadata. - -If you leave this field blank, it will default to **Jira\_full.** If you need a different kind of template, Pro users can reach out to [support@defectdojo.com](mailto:support@defectdojo.com) - -9. If you wish, enter the name of a Jira Resolution which will change the status of a Finding to Accepted or to False Positive (when the Resolution is triggered on the Issue). - -The form can be submitted from here. If you wish, you can further customize your Jira integration under Optional Fields. Clicking this button will allow you to apply generic text to Jira Issues or change the mapping of Jira Severity Mappings. - -### Add a Jira Instance (Classic UI / Open-Source) +### Add a Jira Instance 1. If you have not already done so, navigate to the System Settings page and check the box on **Enable Jira Integration**. You will need to do this before the ⚙️ **Configuration \> JIRA** option shows up on the sidebar. ​ @@ -93,13 +53,13 @@ The form can be submitted from here. If you wish, you can further customize you #### Add Jira Configuration (Express) -The Express method allows for a quicker method of linking a Space. Use the Express method if you simply want to connect a Jira Space quickly, and you aren’t dealing with a complex Jira workflow. +The Express method allows for a quicker method of linking a Space. Use the Express method if you simply want to connect a Jira Space quickly, and you aren't dealing with a complex Jira workflow. ![image](images/Connect_DefectDojo_to_Jira_2.png) 1. Select a name for this Jira Configuration to use in DefectDojo. This name is simply a label for the Instance connection in DefectDojo, and does not need to be related to any Jira data. ​ -2. Select the URL for your company’s Jira instance \- likely similar to `https://**yourcompany**.atlassian.net` if you’re using a Jira Cloud installation. +2. Select the URL for your company's Jira instance \- likely similar to `https://**yourcompany**.atlassian.net` if you're using a Jira Cloud installation. ​ 3. Enter an appropriate authetication method in the Username / Password fields for Jira: * For standard **username / password Jira authentication**, enter a Jira Username and corresponding Password in these fields. @@ -115,15 +75,15 @@ The two types are: If you leave this field blank, it will default to **Jira\_full.** -6. Select one or more Jira Resolution types which will change the status of a Finding to Accepted (when the Resolution is triggered on the Issue). If you don’t wish to use this automation, you can leave the field blank. +6. Select one or more Jira Resolution types which will change the status of a Finding to Accepted (when the Resolution is triggered on the Issue). If you don't wish to use this automation, you can leave the field blank. ​ -7. Select one or more Jira Resolution types which will change the status of a Finding to False Positive (when the Resolution is triggered on the Issue). If you don’t wish to use this automation, you can leave the field blank. +7. Select one or more Jira Resolution types which will change the status of a Finding to False Positive (when the Resolution is triggered on the Issue). If you don't wish to use this automation, you can leave the field blank. ​ 8. Decide whether you wish to send SLA Notifications as a comment on a Jira issue. ​ 9. Decide whether you wish to automatically sync Findings with Jira. If this is enabled, Jira Issues will automatically be kept in sync with the related Findings. If this is not enabled, you will need to manually push any changes made to a Finding after the Issue has been created in Jira. ​ -10. Select your Issue key. In Jira, this is the string associated with an Issue (e.g. the word **‘EXAMPLE’** in an issue called **EXAMPLE\-123**). If you don’t know your issue key, create a new Issue in the Jira Space. In the screenshot below, we can see that the issue key on our Jira Space is **DEF**. +10. Select your Issue key. In Jira, this is the string associated with an Issue (e.g. the word **'EXAMPLE'** in an issue called **EXAMPLE\-123**). If you don't know your issue key, create a new Issue in the Jira Space. In the screenshot below, we can see that the issue key on our Jira Space is **DEF**. ​ ![image](images/Connect_DefectDojo_to_Jira_3.png) ​ @@ -157,65 +117,7 @@ Comments (in Jira) and Notes (in DefectDojo) can be kept in sync. This setting c Each Product or Engagement in DefectDojo has its own settings which govern how Findings are converted to JIRA Issues. From here, you can decide the associated Jira Space and set the default behaviour for creating Issues, Epics, Labels and other JIRA metadata. -### Add Jira to a Product or Engagement (Pro UI) - -You can find this page by clicking the Gear menu on a Product or Engagement - ⚙️ and opening the Jira Space Settings page. - -![image](images/jira-project-settings.png) - -#### Jira Instance - -If you have multiple instances of Jira set up, for separate products or teams within your organization, you can indicate which Jira Space you want DefectDojo to create Issues in. Select a Space from the drop\-down menu. - -If this menu doesn't list any Jira instances, confirm that those Space are connected in your global Jira Configuration for DefectDojo \- yourcompany.defectdojo.com/jira. - -#### Project key - -This is the key of the Space that you want to use with DefectDojo. The Space Key for a given Space can be found in the URL. (This was previously referred to as a **Jira Project Key**, but as of Sepetember 2025, this is now referred to in Jira as the **Space Key**). - -![image](images/Add_a_Connected_Jira_Project_to_a_Product_3.png) - -#### Issue template - -Here you can determine how much DefectDojo metadata you want to send to Jira. Select one of two options: - -* **jira\_full**: Issues will track all of the parameters from DefectDojo \- a full Description, CVE, Severity, etc. Useful if you need complete Finding context in Jira (for example, if someone is working on this Issue who doesn't have access to DefectDojo). - -Here is an example of a **jira\_full** Issue: -​ -![image](images/Add_a_Connected_Jira_Project_to_a_Product_4.png) - -* **Jira\_limited:** Issues will only track the DefectDojo link, the Product/Engagement/Test links, the Reporter and Environment fields. All other fields are tracked in DefectDojo only. Useful if you don't require full Finding context in Jira (for example, if someone is working on this Issue who mainly works in DefectDojo, and doesn't need the full picture in JIRA as well.) - -​Here is an example of a **jira\_limited** Issue: - -![image](images/Add_a_Connected_Jira_Project_to_a_Product_5.png) - -#### Component - -If you manage your Jira Space using Components, you can assign the appropriate Component for DefectDojo here. - -**Custom fields** - -If you don’t need to use Custom Fields with DefectDojo issues, you can leave this field as ‘null’. - -However, if your Jira Space Settings **require you** to use Custom Fields on new Issues, you will need to hard-code these mappings. - -Note that DefectDojo cannot send any Issue\-specific metadata as Custom Fields, only a default value. This section should only be set up if your Jira Space **requires that these Custom Fields exist** in every Issue in your Space. - -Follow **[this guide](#custom-fields-in-jira)** to get started working with Custom Fields. - -**Jira labels** - -Select the relevant labels that you want the Issue to be created with in Jira, e.g. **DefectDojo**, **YourProductName..** - -![image](images/Add_a_Connected_Jira_Project_to_a_Product_6.png) - -#### Default assignee - -The name of the default assignee in Jira. If left blank, DefectDojo will follow the default behaviour in your Jira Space when creating Issues. - -### Add Jira to a Product or Engagement (Classic UI / Open-Source) +### Add Jira to a Product or Engagement In the Classic UI, you can find Jira settings by opening the Edit Product or Edit Engagement form. "**📝 Edit**" button under **Settings** on the page: @@ -261,7 +163,7 @@ If you manage your Jira Space using Components, you can assign the appropriate C **Custom fields** -If you don’t need to use Custom Fields with DefectDojo issues, you can leave this field as ‘null’. +If you don't need to use Custom Fields with DefectDojo issues, you can leave this field as 'null'. However, if your Jira Space Settings **require you** to use Custom Fields on new Issues, you will need to hard\-code these mappings. @@ -314,7 +216,7 @@ If enabled, Jira comments will populate on the associated Finding in DefectDojo, #### Send SLA Notifications As Comments -If enabled, any Issue which breaches DefectDojo’s Service Level Agreement rules will have comments added to the Jira issue indicating this. These comments will be posted daily until the Issue is resolved. +If enabled, any Issue which breaches DefectDojo's Service Level Agreement rules will have comments added to the Jira issue indicating this. These comments will be posted daily until the Issue is resolved. Service Level Agreements can be configured under **Configuration \> SLA Configuration** in DefectDojo and assigned to each Product. @@ -360,7 +262,7 @@ DefectDojo's Jira Webhook only accepts requests from the Jira API. Once you have one or more Issues created from DefectDojo Findings, you can test the Webhook by adding a Comment to one of those Findings. The Comment should be received by the Jira webhook as a note. -If this doesn’t work correctly, it could be due to a Firewall issue on your Jira instance blocking the Webhook. +If this doesn't work correctly, it could be due to a Firewall issue on your Jira instance blocking the Webhook. * DefectDojo's Firewall Rules include a checkbox for **Jira Cloud,** which needs to be enabled before DefectDojo can receive Webhook messages from Jira. @@ -370,7 +272,7 @@ If this doesn’t work correctly, it could be due to a Firewall issue on your Ji In order to test that the Jira integration is working properly, you can add a new blank Finding to the Product associated with Jira in DefectDojo. **Product \> Findings \> Add New Finding.** -Add whatever title severity and description you wish, and then click “Finished”. The Finding should appear as an Issue in Jira with all of the relevant metadata. +Add whatever title severity and description you wish, and then click "Finished". The Finding should appear as an Issue in Jira with all of the relevant metadata. If Jira Issues are not being created correctly, check your Notifications for error codes. @@ -382,7 +284,7 @@ In order to test the Jira webhooks, add a Note to a Finding which also exists in If the webhooks are configured correctly, you should see the Note in Jira as a Comment on the issue. -If this doesn’t work correctly, it could be due to a Firewall issue on your Jira instance blocking the Webhook. +If this doesn't work correctly, it could be due to a Firewall issue on your Jira instance blocking the Webhook. * DefectDojo's Firewall Rules include a checkbox for **Jira Cloud,** which needs to be enabled before DefectDojo can receive Webhook messages from Jira. @@ -390,7 +292,7 @@ If this doesn’t work correctly, it could be due to a Firewall issue on your Ji Jira integrations can be removed from your instance only if no related Issues have been created. If Issues have been created, there is no way to completely remove a Jira Instance from DefectDojo. -However, you can disable your Jira integration by disabling it at the Product level. From the **Edit Product** form (Classic UI) or from the **Jira Product Settings** (Pro UI) you can uncheck the "Enable Connection With Jira Space" option. This will not delete or change any existing Jira tickets created by DefectDojo, but will disable any further updates. +However, you can disable your Jira integration by disabling it at the Product level. From the **Edit Product** form you can uncheck the "Enable Connection With Jira Space" option. This will not delete or change any existing Jira tickets created by DefectDojo, but will disable any further updates. # Pushing Findings To Jira @@ -454,7 +356,7 @@ DefectDojo's built\-in Jira Issue Types (**Bug, Task, Story** and **Epic)** are Some Jira configurations require additional custom fields to be accounted for before an issue can be created. This process will allow you to account for these custom fields in your DefectDojo \-\> Jira integration, ensuring that issues are created successfully. These custom fields will be added to any API calls sent from DefectDojo to a linked Jira instance. -If you don’t already use Custom Fields in Jira, there is no need to follow this process. +If you don't already use Custom Fields in Jira, there is no need to follow this process. 1. Recording the names of your Custom Fields in Jira (**Jira UI**) 2. Determine the Key values for the new Custom Fields (Jira Field Spec Endpoint) @@ -485,46 +387,46 @@ Here is an example of a Field Spec URL: The API will return a long string of JSON, which should be formatted into readable text (using a code editor, browser extension or ). -The JSON returned from this URL will contain all of your Jira custom fields, most of which are irrelevant to DefectDojo and have values of `“Null”`. Each object in this API response corresponds to a different field in Jira. You will need to search for the objects that have `“name”` attributes which match the names of each Custom Field you created in the Jira UI, and then note the value of their “key” attribute. +The JSON returned from this URL will contain all of your Jira custom fields, most of which are irrelevant to DefectDojo and have values of `"Null"`. Each object in this API response corresponds to a different field in Jira. You will need to search for the objects that have `"name"` attributes which match the names of each Custom Field you created in the Jira UI, and then note the value of their "key" attribute. ![image](images/Using_Custom_Fields.png) -Once you’ve found the matching object in the JSON output, you can determine the “key” value \- in this case, it's `customfield_10050`. +Once you've found the matching object in the JSON output, you can determine the "key" value \- in this case, it's `customfield_10050`. Jira generates different key values for each Custom Field, but these key values do not change once created. If you create another Custom Field in the future, it will have a new key value. **Expanding our Custom Field list:** -* “DefectDojo Custom URL Field” \= customfield\_10050 -* “Another example of a Custom Field” \= customfield\_12345 +* "DefectDojo Custom URL Field" \= customfield\_10050 +* "Another example of a Custom Field" \= customfield\_12345 * ... #### Step 3 \- Finding the Custom Fields on a Jira Issue -Locate an Issue in Jira that contains the Custom Fields which you recorded in Step 2\. Copy the Issue Key for the title (should look similar to “`EXAMPLE-123`”) and navigate to the following URL: +Locate an Issue in Jira that contains the Custom Fields which you recorded in Step 2\. Copy the Issue Key for the title (should look similar to "`EXAMPLE-123`") and navigate to the following URL: `https://yourcompany-example.atlassian.net/rest/api/2/issue/EXAMPLE-123` This will return another string of JSON. -As before, API output will contain lots of `customfield_##` object parameters with `null` values \- these are custom fields that Jira adds by default, which aren’t relevant to this issue. It will also contain `customfield_##` values that match the Custom Field Key values that you found in the previous step. Unlike with the Field Spec output, you won’t see names identifying any of these custom fields, which is why you needed to record the key values in Step 2\. +As before, API output will contain lots of `customfield_##` object parameters with `null` values \- these are custom fields that Jira adds by default, which aren't relevant to this issue. It will also contain `customfield_##` values that match the Custom Field Key values that you found in the previous step. Unlike with the Field Spec output, you won't see names identifying any of these custom fields, which is why you needed to record the key values in Step 2\. ![image](images/Using_Custom_Fields_2.png) **Example:** -We know that `customfield_10050` represents the DefectDojo Custom URL Field because we recorded it in Step 2\. We can now see that `customfield_10050` contains a value of `“https://google.com”` in the `EXAMPLE-123` issue. +We know that `customfield_10050` represents the DefectDojo Custom URL Field because we recorded it in Step 2\. We can now see that `customfield_10050` contains a value of `"https://google.com"` in the `EXAMPLE-123` issue. #### Step 4 \- Creating a JSON Field Reference from each Jira Custom Field Key -You’ll now need to take the value of each of the Custom Fields from your list and store them in a JSON object (to use as a reference). You can ignore any Custom Fields that don’t correspond to your list. +You'll now need to take the value of each of the Custom Fields from your list and store them in a JSON object (to use as a reference). You can ignore any Custom Fields that don't correspond to your list. -This JSON object will contain all of the default values for new Jira Issues. We recommend using names that are easy for your team to recognize as ‘default’ values that need to be changed: ‘`change-me.com`’, ‘`Change this paragraph.`’ etc. +This JSON object will contain all of the default values for new Jira Issues. We recommend using names that are easy for your team to recognize as 'default' values that need to be changed: '`change-me.com`', '`Change this paragraph.`' etc. **Example:** -From step 3, we now know that Jira expects a URL string for "`customfield_10050`”. We can use this to build our example JSON object. +From step 3, we now know that Jira expects a URL string for "`customfield_10050`". We can use this to build our example JSON object. -Say we had also located a DefectDojo\-related short text field, which we identified as "`customfield_67890`”. We would look at this field in our second API output, look at the associated value, and reference the stored value in our example JSON object as well. +Say we had also located a DefectDojo\-related short text field, which we identified as "`customfield_67890`". We would look at this field in our second API output, look at the associated value, and reference the stored value in our example JSON object as well. ​ Your JSON object will start to look like this as you add more Custom Fields to it. @@ -539,7 +441,7 @@ Repeat this process until all of the DefectDojo\-relevant custom fields from Jir #### Data types \& Jira Syntax -Some fields, such as Date fields, may relate to multiple custom fields in Jira. If that is the case, you’ll need to add both fields to your JSON Field Reference. +Some fields, such as Date fields, may relate to multiple custom fields in Jira. If that is the case, you'll need to add both fields to your JSON Field Reference. ``` "customfield_10040": "1970-01-01", @@ -557,7 +459,7 @@ Other fields, such as the Label field, may be tracked as a list of strings \- pl ], ``` -Other custom fields may contain additional, contextual information that should be removed from the Field Reference. For example, the Custom Multichoice Field contains an extra block in the API output, which you’ll need to remove, as this block stores the current value of the field. +Other custom fields may contain additional, contextual information that should be removed from the Field Reference. For example, the Custom Multichoice Field contains an extra block in the API output, which you'll need to remove, as this block stores the current value of the field. * you should remove the extra object from this field: @@ -642,10 +544,10 @@ You can now add these custom fields to the associated DefectDojo Product, in the * Navigate to Edit Product \- defectdojo.com/product/ID/edit . * Navigate to Custom fields and paste the JSON Field Reference as plain text in the Custom Fields box. -* Click ‘Submit’. +* Click 'Submit'. #### Step 6 \- Testing your Jira Custom Fields from a new Finding: -Now, when you create a new Finding in the Jira\-associated Product, Jira will automatically create all of these Custom Fields in Jira according to the JSON block contained within. These Custom Fields will be created with the default (“change\-me\-please”, etc.) values. +Now, when you create a new Finding in the Jira\-associated Product, Jira will automatically create all of these Custom Fields in Jira according to the JSON block contained within. These Custom Fields will be created with the default ("change\-me\-please", etc.) values. -Within the Product on DefectDojo, navigate to the Findings \> Add New Finding page. Make sure the Finding is both Active and Verified to ensure that it pushes to Jira, and then confirm on the Jira side that the Custom Fields are successfully created without any inconsistencies. \ No newline at end of file +Within the Product on DefectDojo, navigate to the Findings \> Add New Finding page. Make sure the Finding is both Active and Verified to ensure that it pushes to Jira, and then confirm on the Jira side that the Custom Fields are successfully created without any inconsistencies. diff --git a/docs/content/issue_tracking/jira/PRO__jira_guide.md b/docs/content/issue_tracking/jira/PRO__jira_guide.md new file mode 100644 index 00000000000..6fe271f367a --- /dev/null +++ b/docs/content/issue_tracking/jira/PRO__jira_guide.md @@ -0,0 +1,562 @@ +--- +title: "📋 Jira Integration Guide" +description: "Work with the Jira integration" +weight: 1 +audience: pro +aliases: + - /en/share_your_findings/jira_guide +--- +DefectDojo's Jira integration can be used to push Finding data to one or more Jira Spaces. By doing so, you can integrate DefectDojo into your standard development workflow. Here are some examples of how this can work: + +* The AppSec team can selectively push Findings to a Jira Space used by developers, so that issue remediation can be appropriately prioritized alongside regular development. Developers on this board don't need to access DefectDojo - they can keep all their work in one place. +* DefectDojo can push ALL Findings to a bidirectional Jira Space which the AppSec team uses, which allows them to split up issue validation. This board keeps in sync with DefectDojo and allows for complex remediation workflows. +* DefectDojo can selectively push Findings from separate Products &/or Engagements to separate Jira Spaces, to keep things in their proper context. + +# Setting Up Jira +Setting Up Jira requires the following steps: +1. Connect a Jira Instance, either with a username / password or an API token. Multiple instances can be linked. +2. Add that Jira Instance to one or more Products or Engagements within DefectDojo. +3. If you wish to use bidirectional sync, create a Jira Webhook which will send updates to DefectDojo. + +## Step 1: Connect a Jira Instance + +Connecting a Jira Instance is the first step to take when setting up DefectDojo's Jira integration. Please note Jira Service Management is currently not supported. + +#### Required information from Jira + +Atlassian uses different ways of authentication between Jira Cloud and Jira Data Center. + +for **Jira Cloud**, you will need: +* a Jira URL, i.e. https://yourcompany.atlassian.net/ +* an account with permissions to create and update issues in your Jira instance. This can be: + * A standard **username / password** combination + * A **username / API Token** combination + +for **Jira Data Center (or Server)**, you will need: +* a Jira URL, i.e. https://jira.yourcompany.com +* an account with permissions to create and update issues in your Jira instance. This can be: + * A standard **username / password** combination + * A **emailaddress / Personal Access Token** combination + +Optionally, you can map: +* Jira Transitions to trigger Re-Opening and Closing Findings +* Jira Resolutions which can apply Risk Acceptance and False Positive statuses to Findings (optional) + +Multiple Jira Spaces can be handled by a single Jira Instance connection, as long as the Jira account / token used by DefectDojo has permission to create Issues in the associated Jira Space. + +### Add a Jira Instance + +1. If you have not already done so, navigate to the System Settings page and check the box on **Enable Jira Integration**. + +2. Navigate to the **Enterprise Settings \> Jira Instances \> + New Jira Instance** page from the DefectDojo sidebar. + +![image](images/jira-instance-beta.png) + +3. Select a **Configuration Name** for this Jira Instance to use in DefectDojo. This name is simply a label for the Instance connection in DefectDojo, and does not need to be related to any Jira data. + +4. Select the URL for your company's Jira instance \- likely similar to `https://**yourcompany**.atlassian.net` if you're using a Jira Cloud installation. + +5. Enter an appropriate authentication method in the Username / Password fields for Jira: + * For standard **username / password Jira authentication**, enter a Jira Username and corresponding Password in these fields. + * For authentication with a **user's API token (Jira Cloud)** enter the Username with the corresponding **API token** in the password field. + * For authentication with a Jira **Personal Access Token (aka PAT, used in Jira Data Center and Jira Server only)**, enter the PAT in the password field. Username is not used for authentication with a Jira PAT, but the field is still required in this form, so you can use a placeholder value here to identify your PAT. + +Note that the user associated with this connection must have permission to create Issues and access data in your Jira instance. + +6. You will need to provide values for an Epic Name ID, Re-open Transition ID and Close Transition ID. These values can be changed later. While logged into Jira, you can access these values from the following URLs: +- **Epic Name ID**: visit `https:///rest/api/2/field` and search for Epic Name. Copy the number out of `number` and paste it here. If you do not have an Epic Name ID associated with your Space in Jira (due to using a Team-Managed Space, for example), enter 0 on this field. +- **Re-open Transition ID**: visit `https:///rest/api/latest/issue//transitions?expand-transitions.fields` to find the ID for your Jira instance. Paste it in the Reopen Transition ID field. +- **Close Transition ID**: Visit `https:///rest/api/latest/issue//transitions?expand-transitions.fields` to find the ID for your Jira instance. Paste it in the Close Transition ID field. + +7. Select the Default issue type which you want to create Issues as in Jira. The options for this are **Bug, Task, Story** and **Epic** (which are standard Jira issue types) as well as **Spike** and **Security**, which are custom issue types. If you have a different Issue Type which you want to use, please contact [support@defectdojo.com](mailto:support@defectdojo.com) for assistance. + +8. Select your Issue Template, which will determine the Issue Description when Issues are created in Jira. + +The two types are: +- **Jira\_full**, which will include all Finding information in Jira Issues +- **Jira\_limited**, which will include a smaller amount of Finding information and metadata. + +If you leave this field blank, it will default to **Jira\_full.** If you need a different kind of template, reach out to [support@defectdojo.com](mailto:support@defectdojo.com). + +9. If you wish, enter the name of a Jira Resolution which will change the status of a Finding to Accepted or to False Positive (when the Resolution is triggered on the Issue). + +The form can be submitted from here. If you wish, you can further customize your Jira integration under Optional Fields. Clicking this button will allow you to apply generic text to Jira Issues or change the mapping of Jira Severity Mappings. + +## Step 2: Connect a Product or Engagement to Jira + +Each Product or Engagement in DefectDojo has its own settings which govern how Findings are converted to JIRA Issues. From here, you can decide the associated Jira Space and set the default behaviour for creating Issues, Epics, Labels and other JIRA metadata. + +### Add Jira to a Product + +You can find this page by clicking the Gear menu on a Product ⚙️ and opening the **Jira Project Settings** page. + +![image](images/jira-project-settings.png) + +#### Jira Instance + +If you have multiple instances of Jira set up, for separate products or teams within your organization, you can indicate which Jira Space you want DefectDojo to create Issues in. Select a Space from the drop\-down menu. + +If this menu doesn't list any Jira instances, confirm that those Spaces are connected in your global Jira Configuration for DefectDojo \- yourcompany.defectdojo.com/jira. + +#### Project key + +This is the key of the Space that you want to use with DefectDojo. The Space Key for a given Space can be found in the URL. (This was previously referred to as a **Jira Project Key**, but as of September 2025, this is now referred to in Jira as the **Space Key**). + +![image](images/Add_a_Connected_Jira_Project_to_a_Product_3.png) + +#### Epic Issue Type Name + +The name of the Epic issue type in Jira. This defaults to "Epic" but can be changed if your Jira instance uses a different name. + +#### Issue template + +Here you can determine how much DefectDojo metadata you want to send to Jira. Select one of two options: + +* **jira\_full**: Issues will track all of the parameters from DefectDojo \- a full Description, CVE, Severity, etc. Useful if you need complete Finding context in Jira (for example, if someone is working on this Issue who doesn't have access to DefectDojo). + +Here is an example of a **jira\_full** Issue: +​ +![image](images/Add_a_Connected_Jira_Project_to_a_Product_4.png) + +* **Jira\_limited:** Issues will only track the DefectDojo link, the Product/Engagement/Test links, the Reporter and Environment fields. All other fields are tracked in DefectDojo only. Useful if you don't require full Finding context in Jira (for example, if someone is working on this Issue who mainly works in DefectDojo, and doesn't need the full picture in JIRA as well.) + +​Here is an example of a **jira\_limited** Issue: + +![image](images/Add_a_Connected_Jira_Project_to_a_Product_5.png) + +#### Component + +If you manage your Jira Space using Components, you can assign the appropriate Component for DefectDojo here. + +#### Custom fields + +If you don't need to use Custom Fields with DefectDojo issues, you can leave this field as 'null'. + +However, if your Jira Space Settings **require you** to use Custom Fields on new Issues, you will need to hard-code these mappings. + +Note that DefectDojo cannot send any Issue\-specific metadata as Custom Fields, only a default value. This section should only be set up if your Jira Space **requires that these Custom Fields exist** in every Issue in your Space. + +Follow **[this guide](#custom-fields-in-jira)** to get started working with Custom Fields. + +#### Jira labels + +Select the relevant labels that you want the Issue to be created with in Jira, e.g. **DefectDojo**, **YourProductName..** + +![image](images/Add_a_Connected_Jira_Project_to_a_Product_6.png) + +#### Default assignee + +The name of the default assignee in Jira. If left blank, DefectDojo will follow the default behaviour in your Jira Space when creating Issues. + +### Jira Project Settings + +#### Enabled + +This toggle controls whether DefectDojo pushes Findings to Jira for this Product. Disabling this will not delete or change any existing Jira tickets created by DefectDojo, but will prevent any further updates or new Issue creation. + +Jira integrations can be removed from your instance only if no related Issues have been created. If Issues have been created, there is no way to completely remove a Jira Instance from DefectDojo. + +#### Add Vulnerability Id as a Jira label + +This allows you to add the Vulnerability ID data as a Jira Label automatically. Vulnerability IDs are added to Findings from individual security tools \- these may be Common Vulnerabilities and Exposures (CVE) IDs or a different format, specific to the tool reporting the Finding. + +#### Push All Issues + +If checked, DefectDojo will automatically push any Active and Verified Findings to Jira as Issues. If left unchecked, all Findings will need to be pushed to Jira manually (individually or via bulk push). + +When this setting is enabled, Jira Issues will continue to sync with DefectDojo even if the Finding's status changes. + +#### Enable Engagement Epic Mapping + +In DefectDojo, Engagements represent a collection of work. Each Engagement contains one or more tests, which contain one or more Findings which need to be mitigated. Epics in Jira work in a similar way, and this checkbox allows you to push Engagements to Jira as Epics. + +* An Engagement in DefectDojo \- note the three findings listed at the bottom. +​ +![image](images/Add_a_Connected_Jira_Project_to_a_Product_8.png) +* How the same Engagement becomes an Epic when pushed to JIRA \- the Engagement's Findings are also pushed, and live inside the Engagement as Child Issues. + +![image](images/Add_a_Connected_Jira_Project_to_a_Product_9.png) + +#### Push Notes + +If enabled, Jira comments will populate on the associated Finding in DefectDojo, under Notes, and vice versa; Notes on Findings will be added to the associated Jira Issue as Comments. + +#### Send SLA Notifications As Comments + +If enabled, any Issue which breaches DefectDojo's Service Level Agreement rules will have comments added to the Jira issue indicating this. These comments will be posted daily until the Issue is resolved. + +Service Level Agreements can be configured under **Configuration \> SLA Configuration** in DefectDojo and assigned to each Product. + +#### Send Risk Acceptance Expiration Notifications As Comment + +If enabled, any Issue where the associated DefectDojo Risk Acceptance expires will have a comment added to the Jira issue indicating this. These comments will be posted daily until the Issue is resolved. + +### Engagement-Level Jira Settings + +By default, Engagements **inherit Jira settings from their Product**. However, you can override the Jira settings for individual Engagements. + +To access Engagement-level Jira settings, click the Gear menu ⚙️ on an Engagement and open the **Jira Project Settings** page. + +From here, you can uncheck **Inherit from Product** and provide Engagement-specific values for: **Project Key**, **Issue Template, Custom Fields, Jira Labels, Default Assignee**, and other settings. + +Note that once an Engagement has its own Jira project assigned, it can no longer inherit from the Product. + +![image](images/Creating_Issues_in_Jira_5.png) + +## Step 3: Configure Bidirectional Sync: Jira Webhook + +The Jira integration allows for bidirectional sync via webhook. DefectDojo receives Jira notifications at a unique address, which can allow for Jira comments to be received on Findings, or for Findings to be resolved via Jira depending on your configuration. + +### Locating your Jira Webhook URL + +Your Jira Webhook is located on the System Settings form under **Jira Integration Settings**: **Enterprise Settings \> System Settings** from the sidebar. + +![image](images/Configuring_the_Jira_DefectDojo_Webhook.png) + +### Creating the Jira Webhook + +1. Visit `**https:// \ /plugins/servlet/webhooks**` +2. Click 'Create a Webhook'. +3. For the field labeled 'URL' enter: `https:// \<**YOUR DOJO DOMAIN**\> /jira/webhook/ \<**YOUR GENERATED WEBHOOK SECRET**\>`. The Web Hook Secret is listed under the Jira Integration Settings as listed above. +4. Under 'Comments' enable 'Created'. Under Issue enable 'Updated'. +5. Make sure your JIRA instance trusts the SSL certificate used by your DefectDojo instance. For JIRA Cloud DefectDojo must use [a valid SSL/TLS certificate, signed by a globally trusted certificate authority](https://developer.atlassian.com/cloud/jira/platform/deprecation-notice-registering-webhooks-with-non-secure-urls/) + +Note that you do not need to create a Secret within Jira to use this webhook. The Secret is built into DefectDojo's URL, so simply adding the complete URL to the Jira Webhook form is sufficient. + +DefectDojo's Jira Webhook only accepts requests from the Jira API. + +#### Testing the Webhook + +Once you have one or more Issues created from DefectDojo Findings, you can test the Webhook by adding a Comment to one of those Findings. The Comment should be received by the Jira webhook as a note. + +If this doesn't work correctly, it could be due to a Firewall issue on your Jira instance blocking the Webhook. + +* DefectDojo's Firewall Rules include a checkbox for **Jira Cloud,** which needs to be enabled before DefectDojo can receive Webhook messages from Jira. + +## Testing the Jira integration + +#### Test 1: Do Findings successfully push to Jira? + +In order to test that the Jira integration is working properly, you can add a new blank Finding to the Product associated with Jira in DefectDojo. **Product \> Findings \> Add New Finding.** + +Add whatever title severity and description you wish, and then click "Finished". The Finding should appear as an Issue in Jira with all of the relevant metadata. + +If Jira Issues are not being created correctly, check your Notifications for error codes. + +* Confirm that the Jira User associated with DefectDojo's Jira Configuration has permission to create and update issues on that particular Jira Space. + +#### Test 2: Jira Webhooks send to DefectDojo + +In order to test the Jira webhooks, add a Note to a Finding which also exists in JIRA as an Issue (for example, the test issue in the section above). + +If the webhooks are configured correctly, you should see the Note in Jira as a Comment on the issue. + +If this doesn't work correctly, it could be due to a Firewall issue on your Jira instance blocking the Webhook. + +* DefectDojo's Firewall Rules include a checkbox for **Jira Cloud,** which needs to be enabled before DefectDojo can receive Webhook messages from Jira. + +## Disconnecting from Jira + +Jira integrations can be removed from your instance only if no related Issues have been created. If Issues have been created, there is no way to completely remove a Jira Instance from DefectDojo. + +However, you can disable your Jira integration by disabling it at the Product level. From the **Jira Project Settings** page (accessible via the ⚙️ Gear menu on a Product), uncheck the **Enabled** toggle. This will not delete or change any existing Jira tickets created by DefectDojo, but will disable any further updates. + +# Pushing Findings To Jira + +A Product with a JIRA mapping can push Findings to Jira as Issues using several methods. You can push Findings individually, in bulk, as Finding Groups, or automatically. + +## Push a Single Finding + +1. Open the Finding you want to push. +2. Click the **☰ Finding Menu** and select **Push to Jira**. +3. Confirm the push when prompted. DefectDojo will create a Jira Issue and link it to the Finding. + +Once the Issue is created, DefectDojo will display a link to the Jira Issue on the Finding page. + +![image](images/Creating_Issues_in_Jira_2.png) + +You can also check the **Push to Jira** checkbox when editing a Finding via the **Edit Finding** form. When the Finding is saved, it will be pushed to Jira. + +### Updating a Linked Jira Issue + +If a Finding already has a linked Jira Issue, selecting **Push to Jira** again will update the existing Jira Issue with any changes made in DefectDojo. If **Push All Issues** is enabled on the Product, this syncing happens automatically. + +### Unlinking a Finding from Jira + +To remove the association between a Finding and its Jira Issue, click the **☰ Finding Menu** and select **Unlink From Jira**. This removes the link in DefectDojo but does not delete the Jira Issue itself. + +## Bulk Push Findings + +You can push multiple Findings to Jira at once using the Bulk Update form: + +1. From a Findings list, select the Findings you want to push using the checkboxes. +2. Open the **Bulk Update** form. +3. Under **Jira Settings**, check the **Push to Jira** checkbox. +4. Click **Submit**. + +The selected Findings will be queued for Jira push. DefectDojo will display a confirmation message indicating how many Findings were queued. + +## Push Engagements as Epics + +If **Enable Engagement Epic Mapping** is turned on in your Jira Project Settings, you can push an Engagement to Jira as an Epic. The Engagement's Findings will be pushed as Child Issues within that Epic. + +To push an Engagement as an Epic: + +1. Open the Engagement you want to push. +2. Click the **☰ Engagement Menu** and select **Push to Jira**. +3. Optionally, provide an **Epic Name** (defaults to the Engagement name if left blank) and an **Epic Priority**. +4. Check **Push to Jira (Create Epic)** and submit the form. + +## Push Finding Groups as Jira Issues + +If you have Finding Groups enabled, you can push a Group of Findings to Jira as a single Issue rather than separate Issues for each Finding. + +To push a Finding Group: + +1. Open the Finding Group. +2. Click the **☰ Finding Group Menu** and select **Push to Jira**, or check the **Push to Jira** checkbox when editing the Finding Group. + +The Jira Issue associated with a Finding Group must be deleted directly from the Jira instance if removal is needed. + +### Automatically Create and Push Finding Groups + +With **Push All Issues** enabled on the Product, and a **Group By** option selected on import: + +As long as the Finding Groups are being created successfully, the Finding Group is what will automatically push to Jira as an Issue, not the individual Findings. + +![image](images/Creating_Issues_in_Jira_4.png) + +## Automatic Push Behaviour + +DefectDojo can automatically push Findings and updates to Jira in several scenarios: + +### Push All Issues + +When the **Push All Issues** setting is enabled on a Product's Jira Project Settings, DefectDojo will automatically create Jira Issues for all Active and Verified Findings. This includes Findings created via scan import. Once a Jira Issue is created, it will continue to sync with DefectDojo even if the Finding's status changes. + +### Auto-Sync on Status Changes + +When **Push All Issues** or the system-level **Finding Jira Sync** setting is enabled, DefectDojo will automatically update linked Jira Issues when certain actions are taken on Findings: + +* **Request Review** \- A comment is added to the linked Jira Issue (or the Finding Group's Jira Issue if the Finding belongs to a group). +* **Clear Review** \- A comment is added to the linked Jira Issue. +* **Close Finding** \- The linked Jira Issue is updated to reflect the closure. If **Push Notes** is enabled, a comment is also added. + +## Jira Comments and Notes + +When **Push Notes** is enabled in the Jira Project Settings: + +* If a comment is added to a Jira Issue, the same comment will be added to the Finding, under the **Notes** section. +* Likewise, if a Note is added to a Finding, the Note will be added to the Jira issue as a comment. + +## Jira Status Changes + +The Jira Instance configuration has entries for two Jira Transitions which will trigger a status change on a Finding. + +* When the **'Close' Transition** is performed on Jira, the associated Finding will also Close, and become marked as **Inactive** and **Mitigated** on DefectDojo. DefectDojo will record this change on the Finding page under the **Mitigated By** heading. +​ +![image](images/Creating_Issues_in_Jira_3.png) + +* When the **'Reopen' Transition** is performed on the Jira Issue, the associated Finding will be set as **Active** on DefectDojo, and will lose its **Mitigated** status. + +# Custom Fields in Jira + +DefectDojo does not currently support passing any Issue\-specific information into these Custom Fields \- these fields will need to be updated manually in Jira after the issue is created. Each Custom Field will only be created from DefectDojo with a default value. + + Jira Cloud now allows you to create a default Custom Field value directly in\-app. [See Atlassian's documentation on Custom Fields](https://support.atlassian.com/jira-cloud-administration/docs/configure-a-custom-field/) for more information on how to configure this. + +DefectDojo's built\-in Jira Issue Types (**Bug, Task, Story** and **Epic)** are set up to work 'out of the box'. Data fields in DefectDojo will automatically map to the corresponding fields in Jira. By default, DefectDojo will assign Priority, Labels and a Reporter to any new Issue it creates. + +Some Jira configurations require additional custom fields to be accounted for before an issue can be created. This process will allow you to account for these custom fields in your DefectDojo \-\> Jira integration, ensuring that issues are created successfully. These custom fields will be added to any API calls sent from DefectDojo to a linked Jira instance. + +If you don't already use Custom Fields in Jira, there is no need to follow this process. + +1. Recording the names of your Custom Fields in Jira (**Jira UI**) +2. Determine the Key values for the new Custom Fields (Jira Field Spec Endpoint) +3. Locate the acceptable data for each Custom Field, using the Key values as a reference (Jira Issue Endpoint) +4. Create a Field Reference JSON block to track all of the Custom Field Keys and acceptable data (Jira Issue Endpoint) +5. Store the JSON block in the associated DefectDojo Product, to allow Custom Fields to be created from Jira (DefectDojo UI) +6. Test your work and ensure that all required data is flowing from Jira properly + +#### Step 1: Record the names of your Custom Fields in Jira + +Jira supports a variety of different Context Fields, including Date Pickers, Custom Labels, Radio Buttons. Each of these Context Fields will have a different Key value that can be found in the Jira API. + +Write down the names of each required Custom Field, as you will need to search through the Jira API to find them in the next step. + +**Example of a Custom Field list (your Custom Field names will be different):** + +* DefectDojo Custom URL Field +* Another example of a Custom Field +* ... + +#### Step 2: Finding your Jira Custom Field Key Values + +Start this process by navigating to the Field Spec URL for your entire Jira instance. + +Here is an example of a Field Spec URL: + +`https://yourcompany-example.atlassian.net/rest/api/2/field` + +The API will return a long string of JSON, which should be formatted into readable text (using a code editor, browser extension or ). + +The JSON returned from this URL will contain all of your Jira custom fields, most of which are irrelevant to DefectDojo and have values of `"Null"`. Each object in this API response corresponds to a different field in Jira. You will need to search for the objects that have `"name"` attributes which match the names of each Custom Field you created in the Jira UI, and then note the value of their "key" attribute. + +![image](images/Using_Custom_Fields.png) + +Once you've found the matching object in the JSON output, you can determine the "key" value \- in this case, it's `customfield_10050`. + +Jira generates different key values for each Custom Field, but these key values do not change once created. If you create another Custom Field in the future, it will have a new key value. + +**Expanding our Custom Field list:** + +* "DefectDojo Custom URL Field" \= customfield\_10050 +* "Another example of a Custom Field" \= customfield\_12345 +* ... + +#### Step 3 \- Finding the Custom Fields on a Jira Issue + +Locate an Issue in Jira that contains the Custom Fields which you recorded in Step 2\. Copy the Issue Key for the title (should look similar to "`EXAMPLE-123`") and navigate to the following URL: + +`https://yourcompany-example.atlassian.net/rest/api/2/issue/EXAMPLE-123` + +This will return another string of JSON. + +As before, API output will contain lots of `customfield_##` object parameters with `null` values \- these are custom fields that Jira adds by default, which aren't relevant to this issue. It will also contain `customfield_##` values that match the Custom Field Key values that you found in the previous step. Unlike with the Field Spec output, you won't see names identifying any of these custom fields, which is why you needed to record the key values in Step 2\. + +![image](images/Using_Custom_Fields_2.png) + +**Example:** +We know that `customfield_10050` represents the DefectDojo Custom URL Field because we recorded it in Step 2\. We can now see that `customfield_10050` contains a value of `"https://google.com"` in the `EXAMPLE-123` issue. + +#### Step 4 \- Creating a JSON Field Reference from each Jira Custom Field Key + +You'll now need to take the value of each of the Custom Fields from your list and store them in a JSON object (to use as a reference). You can ignore any Custom Fields that don't correspond to your list. + +This JSON object will contain all of the default values for new Jira Issues. We recommend using names that are easy for your team to recognize as 'default' values that need to be changed: '`change-me.com`', '`Change this paragraph.`' etc. + +**Example:** + +From step 3, we now know that Jira expects a URL string for "`customfield_10050`". We can use this to build our example JSON object. + +Say we had also located a DefectDojo\-related short text field, which we identified as "`customfield_67890`". We would look at this field in our second API output, look at the associated value, and reference the stored value in our example JSON object as well. +​ +Your JSON object will start to look like this as you add more Custom Fields to it. + +``` +{ + "customfield_10050": "https://change-me.com", + "customfield_67890": "This is the short text custom field." +} +``` + +Repeat this process until all of the DefectDojo\-relevant custom fields from Jira have been added to your JSON Field Reference. + +#### Data types \& Jira Syntax + +Some fields, such as Date fields, may relate to multiple custom fields in Jira. If that is the case, you'll need to add both fields to your JSON Field Reference. + +``` + "customfield_10040": "1970-01-01", + "customfield_10041": "1970-01-01T03:30:00.000+0200", +``` + +Other fields, such as the Label field, may be tracked as a list of strings \- please make sure your JSON Field Reference uses a format that matches API output from Jira. + +``` +// a list of custom labels on a Jira object + "customfield_10042": [ + "custom-label-one", + "this-is-default", + "change-me-please" + ], +``` + +Other custom fields may contain additional, contextual information that should be removed from the Field Reference. For example, the Custom Multichoice Field contains an extra block in the API output, which you'll need to remove, as this block stores the current value of the field. + +* you should remove the extra object from this field: + +``` +"customfield_10047": [ + { + "value": "A" + }, + { + "self": "example.url...", + "value": "C", + "id": "example ID" + } +] +``` +* instead, you can shorten this to the following and disregard the second part: + +``` +"customfield_10047": [ + { + "value": "A" + } +] +``` + +#### Example Completed Field Reference + +Here is a complete JSON Field Reference, with in\-line comments explaining what each custom field pertains to. This is meant as an all\-encompassing example. Your JSON will contain different key values and data points depending on the Custom Values you want to use during issue creation. + +``` +{ + "customfield_10050": "https://change-me.com", + + "customfield_10049": "This is a short text custom field", + +// two different fields, but both correspond to the same custom date attribute + "customfield_10040": "1970-01-01", + "customfield_10041": "1970-01-01T03:30:00.000+0200", + +// a list of custom labels on a Jira object + "customfield_10042": [ + "custom-label-one", + "this-is-default", + "change-me-please" + ], + +// custom number field + "customfield_10043": 0, + +// custom paragraph field + "customfield_10044": "This is a very long winded way to say CHANGE ME PLEASE", + +// custom radio button field + "customfield_10045": { + "value": "radio button option" + }, + +// custom multichoice field + "customfield_10047": [ + { + "value": "A" + } + ], + +// custom checkbox field + "customfield_10039": [ + { + "value": "A" + } + ], + +// custom select list (singlechoice) field + "customfield_10048": { + "value": "1" + } +} +``` + +#### Step 5 \- Adding the Custom Fields to a DefectDojo Product + +You can now add these custom fields to the associated DefectDojo Product, in the Jira Project Settings page (accessible via the ⚙️ Gear menu on the Product). Paste the JSON Field Reference as plain text in the **Custom Fields** box and save. + +#### Step 6 \- Testing your Jira Custom Fields from a new Finding: + +Now, when you create a new Finding in the Jira\-associated Product, Jira will automatically create all of these Custom Fields in Jira according to the JSON block contained within. These Custom Fields will be created with the default ("change\-me\-please", etc.) values. + +Within the Product on DefectDojo, navigate to the Findings \> Add New Finding page. Make sure the Finding is both Active and Verified to ensure that it pushes to Jira, and then confirm on the Jira side that the Custom Fields are successfully created without any inconsistencies. diff --git a/docs/content/issue_tracking/jira/troubleshooting_jira.md b/docs/content/issue_tracking/jira/troubleshooting_jira.md index 131bc4fbbe8..552c70f9eed 100644 --- a/docs/content/issue_tracking/jira/troubleshooting_jira.md +++ b/docs/content/issue_tracking/jira/troubleshooting_jira.md @@ -65,7 +65,7 @@ Using the 'Push To Jira' workflow triggers an asynchronous process, however an I Common reasons issues are not created: * The Default Issue Type you have selected is not usable with the Jira Space -* Issues in the Space have required attributes that prevent them from being created via DefectDojo (see our guide to [Custom Fields](../jira_guide/#custom-fields-in-jira)) +* Issues in the Space have required attributes that prevent them from being created via DefectDojo (which can be handled via Custom Fields in Jira) ## Error: Product Misconfigured or no permissions in Jira? @@ -77,11 +77,11 @@ This error message can appear when attempting to add a created Jira configuratio ## Changes made to Jira issues are not updating Findings in DefectDojo -* Start by confirming that the [DefectDojo webhook receiver](../jira_guide/#step-3-configure-bidirectional-sync-jira-webhook) is configured correctly and can successfully receive updates. +* Start by confirming that the DefectDojo webhook receiver is configured correctly and can successfully receive updates. * Ensure the SSL certificate used by Defect Dojo is trusted by JIRA. For JIRA Cloud you must use [a valid SSL/TLS certificate, signed by a globally trusted certificate authority](https://developer.atlassian.com/cloud/jira/platform/deprecation-notice-registering-webhooks-with-non-secure-urls/) -* If you're trying to push status changes, confirm that Jira transition mappings are set up correctly (Reopen / Close [Transition IDs](../jira_guide/#step-3-configure-bidirectional-sync-jira-webhook)). +* If you're trying to push status changes, confirm that Jira transition mappings are set up correctly (Reopen / Close Transition IDs). * [Test](https://support.atlassian.com/jira/kb/testing-webhooks-in-jira-cloud/) your JIRA webhook using a public endpoint such as Pipedream or Beeceptor: diff --git a/docs/content/releases/pro/changelog.md b/docs/content/releases/pro/changelog.md index b15a105c203..4caa1e784f5 100644 --- a/docs/content/releases/pro/changelog.md +++ b/docs/content/releases/pro/changelog.md @@ -12,6 +12,30 @@ For Open Source release notes, please see the [Releases page on GitHub](https:// ## Mar 2026: v2.56 +### Mar 30, 2026: v2.56.4 + +* **(Deduplication)** Fixed an issue where cross-tool deduplication could silently fail to match duplicates when findings were imported across different scan tools. +* **(Pro UI)** Audit Log table now supports global search and query parameter–based filtering. +* **(Pro UI)** Improved page load performance for large listing tables (Findings, Endpoints, etc.) by reducing unnecessary computation during pagination. + +### Mar 23, 2026: v2.56.3 + +* **(MFA)** All authenticated users can now access their own MFA settings page, regardless of role. +* **(Pro UI)** Alerts table now uses server-side filtering, sorting, and pagination for improved performance. +* **(Pro UI)** Removed the deprecated Credentials section from System Settings. +* **(Pro UI)** Fixed boolean filters on the Product Types table for the Critical and Key Asset columns. +* **(Pro UI)** Fixed a filter alignment issue on the Engagements table. +* **(Pro UI)** Standardized the Test field label to "Title" across all screens. +* **(Rules Engine)** Fixed a timeout (502 error) that could occur when previewing rules against a large number of Findings. + +### Mar 16, 2026: v2.56.2 + +* **(API)** Added pagination limit enforcement and deprecation warnings for unpaginated API requests. +* **(Jira)** Custom field values are now properly encoded and decoded as JSON, with validation errors shown for invalid input. +* **(Pro UI)** The New Risk Acceptance form now pre-fills the expiration date using the system default number of days. +* **(Pro UI)** Improved handling of Group membership and permissions in the UI. +* **(SBOM)** SBOM imports are now processed asynchronously, improving upload responsiveness for large files. + ### Mar 12, 2026: v2.56.1 * **(Pro UI)** Finding Groups can now be filtered by computed status: resolved, active, or risk-accepted. From cb5b2282fde463520f045b81480f2cae50ad9e68 Mon Sep 17 00:00:00 2001 From: Paul Osinski Date: Fri, 3 Apr 2026 16:52:50 -0400 Subject: [PATCH 10/15] update sarif documentation --- .../supported_tools/parsers/file/sarif.md | 37 +++++++++++++++---- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/docs/content/supported_tools/parsers/file/sarif.md b/docs/content/supported_tools/parsers/file/sarif.md index b6c1ee62eab..f986bca910b 100644 --- a/docs/content/supported_tools/parsers/file/sarif.md +++ b/docs/content/supported_tools/parsers/file/sarif.md @@ -6,15 +6,38 @@ OASIS Static Analysis Results Interchange Format (SARIF). SARIF is supported by many tools. More details about the format here: -SARIF parser customizes the Test_Type with data from the report. -For example, a report with `Dockle` as a driver name will produce a Test with a Test_Type named `Dockle Scan (SARIF)` +Current implementation will aggregate all the findings in the SARIF file into a single report. -Current implementation is limited and will aggregate all the findings in the SARIF file in one single report. +## How Test Types Are Determined -##### Support for de-duplication (fingerprinting) +Unlike most parsers in DefectDojo, the SARIF parser has a **report-defined Test Type**. When you import a SARIF file with `scan_type=SARIF`, DefectDojo reads the tool name from within the SARIF file at `runs[].tool.driver.name` and uses it to construct the Test Type name. -SARIF parser take into account data for fingerprinting. It's base on `fingerprints` and `partialFingerprints` properties. -It's possible to activate de-duplication based on this data by customizing settings. +The naming pattern is: **`{tool name} ({scan_type})`** + +For example: + +| Tool | `runs[].tool.driver.name` value | Resulting Test Type | +|------|-------------------------------|---------------------| +| Semgrep | `semgrep` | `semgrep (SARIF)` | +| Trivy | `Trivy Scan` | `Trivy Scan (SARIF)` | +| Dockle | `Dockle` | `Dockle Scan (SARIF)` | +| MobSF | `mobsfscan` | `mobsfscan (SARIF)` | + +This means that even though all of these tools produce SARIF output and are imported with `scan_type=SARIF`, each tool will create a **distinct Test Type** in DefectDojo. For more information on how report-defined Test Types work, see **[Test Types](/asset_modelling/hierarchy/product_hierarchy#test-types)**. + +## Reimporting SARIF Results + +When using the `/api/v2/reimport-scan/` endpoint, DefectDojo needs to match incoming results to an existing Test. Understanding how this matching works is important when multiple SARIF-based tools are reporting into the same Engagement. + +### One Tool Per Test + +Each Test in DefectDojo represents results from a single tool. SARIF results from different tools (e.g. Semgrep, Trivy, MobSF) cannot be combined into the same Test, even though they share the same `scan_type=SARIF`. DefectDojo enforces this by validating that the tool name inside the SARIF file matches the existing Test's Test Type on reimport. + +This constraint is what makes reimport's comparison logic reliable: when a Finding is absent from a new report, DefectDojo can safely assume it has been resolved. If results from multiple tools were mixed in a single Test, DefectDojo would not be able to distinguish between a resolved Finding and a Finding that simply isn't covered by the current tool. + +## Support for Deduplication (Fingerprinting) + +The SARIF parser takes into account data for fingerprinting, based on the `fingerprints` and `partialFingerprints` properties in the SARIF file. It's possible to activate deduplication based on this data by customizing settings: ```Python # in your settings.py file @@ -25,7 +48,7 @@ DEDUPLICATION_ALGORITHM_PER_PARSER["SARIF"] = DEDUPE_ALGO_UNIQUE_ID_FROM_TOOL_OR Sample SARIF scans can be found [here](https://github.com/DefectDojo/django-DefectDojo/tree/master/unittests/scans/sarif). ### Default Deduplication Hashcode Fields -By default, DefectDojo identifies duplicate Findings using these [hashcode fields](https://docs.defectdojo.com/en/working_with_findings/finding_deduplication/about_deduplication/): +By default, DefectDojo identifies duplicate Findings using these [hashcode fields]( triage_findings/finding_deduplication/about_deduplication): - title - cwe From 098d08168afbae7b8f6a3c1eb6e8255cc201462d Mon Sep 17 00:00:00 2001 From: Paul Osinski Date: Fri, 3 Apr 2026 17:07:13 -0400 Subject: [PATCH 11/15] fix broken link --- docs/content/supported_tools/parsers/file/sarif.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/supported_tools/parsers/file/sarif.md b/docs/content/supported_tools/parsers/file/sarif.md index f986bca910b..a53bb7eee92 100644 --- a/docs/content/supported_tools/parsers/file/sarif.md +++ b/docs/content/supported_tools/parsers/file/sarif.md @@ -48,7 +48,7 @@ DEDUPLICATION_ALGORITHM_PER_PARSER["SARIF"] = DEDUPE_ALGO_UNIQUE_ID_FROM_TOOL_OR Sample SARIF scans can be found [here](https://github.com/DefectDojo/django-DefectDojo/tree/master/unittests/scans/sarif). ### Default Deduplication Hashcode Fields -By default, DefectDojo identifies duplicate Findings using these [hashcode fields]( triage_findings/finding_deduplication/about_deduplication): +By default, DefectDojo identifies duplicate Findings using these [hashcode fields](/ triage_findings/finding_deduplication/about_deduplication): - title - cwe From 04e7232f88f5ec87fe368a84fa94d38821b2c976 Mon Sep 17 00:00:00 2001 From: Cody Maffucci <46459665+Maffooch@users.noreply.github.com> Date: Mon, 6 Apr 2026 09:04:37 -0600 Subject: [PATCH 12/15] Update docs/content/supported_tools/parsers/file/sarif.md Co-authored-by: dogboat --- docs/content/supported_tools/parsers/file/sarif.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/supported_tools/parsers/file/sarif.md b/docs/content/supported_tools/parsers/file/sarif.md index a53bb7eee92..f544eb6f5eb 100644 --- a/docs/content/supported_tools/parsers/file/sarif.md +++ b/docs/content/supported_tools/parsers/file/sarif.md @@ -48,7 +48,7 @@ DEDUPLICATION_ALGORITHM_PER_PARSER["SARIF"] = DEDUPE_ALGO_UNIQUE_ID_FROM_TOOL_OR Sample SARIF scans can be found [here](https://github.com/DefectDojo/django-DefectDojo/tree/master/unittests/scans/sarif). ### Default Deduplication Hashcode Fields -By default, DefectDojo identifies duplicate Findings using these [hashcode fields](/ triage_findings/finding_deduplication/about_deduplication): +By default, DefectDojo identifies duplicate Findings using these [hashcode fields](/triage_findings/finding_deduplication/about_deduplication): - title - cwe From e8100cbabd78aa5f376388f02293bd4612f1f642 Mon Sep 17 00:00:00 2001 From: valentijnscholten Date: Mon, 6 Apr 2026 17:41:55 +0200 Subject: [PATCH 13/15] Reimport: batch-refresh finding status fields in close_old_findings (#14638) * Batch-refresh close_old_findings status fields to avoid N refresh_from_db queries. Replace per-finding refresh_from_db(false_p, risk_accepted, out_of_scope) with one values() query for all PKs and assign onto instances, falling back to refresh_from_db when a row is missing. * docs: cite #12291 for close_old_findings status refresh origin * perf: chunk close_old_findings status sync queries (1000 PKs per SELECT) * tests: add 4th reimport step (empty scan, close_old_findings) to performance tests - Add step 4 to _import_reimport_performance: reimport with an empty StackHawk scan and close_old_findings=True, verifying findings are actually closed (assertGreater on len_closed_findings). - Fix all reimport steps to pass service="Secured Application" so the reimporter's service filter matches findings produced by the StackHawk parser (which sets service from the scan's application field). Without this, original_items was always empty and no matching/closing occurred. - Add stackhawk_empty.json scan fixture. - Fix update_performance_test_counts.py to handle reimport3 (step 4) by adding reimport3_queries/reimport3_async_tasks to param_map. - Update all expected query/task counts for both Small and Locations test classes to reflect the new step and the batch status-sync fix. --- dojo/importers/default_reimporter.py | 58 ++++++++++++++--- scripts/update_performance_test_counts.py | 2 + .../scans/stackhawk/stackhawk_empty.json | 32 +++++++++ unittests/test_importers_performance.py | 65 ++++++++++++++++++- 4 files changed, 147 insertions(+), 10 deletions(-) create mode 100644 unittests/scans/stackhawk/stackhawk_empty.json diff --git a/dojo/importers/default_reimporter.py b/dojo/importers/default_reimporter.py index 2a24afe8981..625712ccea0 100644 --- a/dojo/importers/default_reimporter.py +++ b/dojo/importers/default_reimporter.py @@ -1,4 +1,5 @@ import logging +from itertools import batched from django.conf import settings from django.core.files.uploadedfile import TemporaryUploadedFile @@ -30,6 +31,9 @@ logger = logging.getLogger(__name__) deduplicationLogger = logging.getLogger("dojo.specific-loggers.deduplication") +# Bound IN-list size when bulk-loading status fields for close_old_findings. +_CLOSE_OLD_FINDINGS_STATUS_FIELDS_CHUNK = 1000 + class DefaultReImporterOptions(ImporterOptions): def validate_test( @@ -465,6 +469,44 @@ def process_findings( return self.new_items, self.reactivated_items, self.to_mitigate, self.untouched + def _sync_close_old_finding_status_fields(self, findings: list[Finding]) -> None: + """ + Refresh false_p, risk_accepted, and out_of_scope from the DB for each finding. + + These can change during reimport (e.g. false positive) while the in-memory instances + are stale. Per-finding refresh_from_db in close_old_findings was added in + https://github.com/DefectDojo/django-DefectDojo/pull/12291. A naive refresh per + finding issues one SELECT each; we batch one query per chunk of primary keys and fall + back to refresh_from_db only when needed. + + This really should be fixed differently, but for now we at least optimize it to be done in bulk. + """ + findings_without_pk = [f for f in findings if f.pk is None] + findings_with_pk = [f for f in findings if f.pk is not None] + + for finding in findings_without_pk: + finding.refresh_from_db(fields=["false_p", "risk_accepted", "out_of_scope"]) + + for chunk in batched(findings_with_pk, _CLOSE_OLD_FINDINGS_STATUS_FIELDS_CHUNK, strict=False): + ids = [f.pk for f in chunk] + fresh_by_id = { + row["id"]: row + for row in Finding.objects.filter(pk__in=ids).values( + "id", + "false_p", + "risk_accepted", + "out_of_scope", + ) + } + for finding in chunk: + row = fresh_by_id.get(finding.pk) + if row is not None: + finding.false_p = row["false_p"] + finding.risk_accepted = row["risk_accepted"] + finding.out_of_scope = row["out_of_scope"] + else: + finding.refresh_from_db(fields=["false_p", "risk_accepted", "out_of_scope"]) + def close_old_findings( self, findings: list[Finding], @@ -478,17 +520,17 @@ def close_old_findings( if self.close_old_findings_toggle is False: return [] logger.debug("REIMPORT_SCAN: Closing findings no longer present in scan report") + # Get any status changes that could have occurred earlier in the process + # for special statuses only. + # An example of such is a finding being reported as false positive, and + # reimport makes this change in the database. However, the findings here + # are calculated based from the original values before the reimport, so + # any updates made during reimport are discarded without first getting the + # state of the finding as it stands at this moment (django-DefectDojo #12291). + self._sync_close_old_finding_status_fields(findings) # Determine if pushing to jira or if the finding groups are enabled mitigated_findings = [] for finding in findings: - # Get any status changes that could have occurred earlier in the process - # for special statuses only. - # An example of such is a finding being reported as false positive, and - # reimport makes this change in the database. However, the findings here - # are calculated based from the original values before the reimport, so - # any updates made during reimport are discarded without first getting the - # state of the finding as it stands at this moment - finding.refresh_from_db(fields=["false_p", "risk_accepted", "out_of_scope"]) # Ensure the finding is not already closed if not finding.mitigated or not finding.is_mitigated: logger.debug("mitigating finding: %i:%s", finding.id, finding) diff --git a/scripts/update_performance_test_counts.py b/scripts/update_performance_test_counts.py index f9fd077e0e8..77a2e629e11 100644 --- a/scripts/update_performance_test_counts.py +++ b/scripts/update_performance_test_counts.py @@ -422,6 +422,8 @@ def _extract_call_span(method_content: str, call_name: str) -> tuple[int, int] | "reimport1_async_tasks": "expected_num_async_tasks2", "reimport2_queries": "expected_num_queries3", "reimport2_async_tasks": "expected_num_async_tasks3", + "reimport3_queries": "expected_num_queries4", + "reimport3_async_tasks": "expected_num_async_tasks4", } param_map_deduplication = { "first_import_queries": "expected_num_queries1", diff --git a/unittests/scans/stackhawk/stackhawk_empty.json b/unittests/scans/stackhawk/stackhawk_empty.json new file mode 100644 index 00000000000..056193baafe --- /dev/null +++ b/unittests/scans/stackhawk/stackhawk_empty.json @@ -0,0 +1,32 @@ +{ + "service": "StackHawk", + "scanCompleted": { + "scan": { + "comment defect dojo team": "This is an empty StackHawk scan results", + "id": "e2ff5651-7eef-47e9-b743-0c2f7d861e27", + "hawkscanVersion": "2.1.1", + "env": "Development", + "status": "COMPLETED", + "application": "Secured Application", + "startedTimestamp": "2022-02-16T23:07:19.575Z", + "scanURL": "https://app.stackhawk.com/scans/e2ff5651-7eef-47e9-b743-0c2f7d861e27" + }, + "scanDuration": "21", + "spiderDuration": "45", + "completedScanStats": { + "urlsCount": "31", + "duration": "66", + "scanResultsStats": { + "totalCount": "0", + "lowCount": "0", + "mediumCount": "0", + "highCount": "0", + "lowTriagedCount": "0", + "mediumTriagedCount": "0", + "highTriagedCount": "0" + } + }, + "findings": [ + ] + } +} diff --git a/unittests/test_importers_performance.py b/unittests/test_importers_performance.py index ea3b3b79b40..ef7b4763460 100644 --- a/unittests/test_importers_performance.py +++ b/unittests/test_importers_performance.py @@ -51,6 +51,7 @@ STACK_HAWK_FILENAME = get_unit_tests_scans_path("stackhawk") / "stackhawk_many_vul_without_duplicated_findings.json" STACK_HAWK_SUBSET_FILENAME = get_unit_tests_scans_path("stackhawk") / "stackhawk_many_vul_without_duplicated_findings_subset.json" +STACK_HAWK_EMPTY = get_unit_tests_scans_path("stackhawk") / "stackhawk_empty.json" STACK_HAWK_SCAN_TYPE = "StackHawk HawkScan" @@ -126,12 +127,17 @@ def _import_reimport_performance( expected_num_async_tasks2, expected_num_queries3, expected_num_async_tasks3, + expected_num_queries4, + expected_num_async_tasks4, scan_file1, scan_file2, scan_file3, + scan_file4, scan_type, product_name, engagement_name, + *, + close_old_findings4=False, ): """ Test import/reimport/reimport performance with specified scan files and scan type. @@ -195,6 +201,7 @@ def _import_reimport_performance( "verified": True, "sync": True, "scan_type": scan_type, + "service": "Secured Application", "tags": ["performance-test-reimport", "reimport-tag-in-param", "reimport-go-faster"], "apply_tags_to_findings": True, } @@ -224,10 +231,44 @@ def _import_reimport_performance( "verified": True, "sync": True, "scan_type": scan_type, + "service": "Secured Application", } reimporter = DefaultReImporter(**reimport_options) test, _, _len_new_findings, _len_closed_findings, _, _, _ = reimporter.process_scan(scan) + # Fourth import (reimport again, empty report) + # Each assertion context manager is wrapped in its own subTest so that if one fails, the others still run. + # This allows us to see all count mismatches in a single test run, making it easier to fix + # all incorrect expected values at once rather than fixing them one at a time. + # Nested with statements are intentional - each assertion needs its own subTest wrapper. + with ( # noqa: SIM117 + self.subTest("reimport3"), impersonate(Dojo_User.objects.get(username="admin")), + scan_file4.open(encoding="utf-8") as scan, + ): + with self.subTest(step="reimport3", metric="queries"): + with self.assertNumQueries(expected_num_queries4): + with self.subTest(step="reimport3", metric="async_tasks"): + with self._assertNumAsyncTask(expected_num_async_tasks4): + reimport_options = { + "test": test, + "user": lead, + "lead": lead, + "scan_date": None, + "minimum_severity": "Info", + "active": True, + "verified": True, + "sync": True, + "scan_type": scan_type, + # StackHawk parser sets the service field causing close old findings to fail if we do not specify the service field + # This is a big problem that needs fixing. Parsers should not set the service field. + "service": "Secured Application", + "close_old_findings": close_old_findings4, + } + reimporter = DefaultReImporter(**reimport_options) + test, _, len_new_findings4, len_closed_findings4, _, _, _ = reimporter.process_scan(scan) + logger.info("Step 4: new=%s closed=%s", len_new_findings4, len_closed_findings4) + self.assertGreater(len_closed_findings4, 0, "Step 4 (empty reimport with close_old_findings=True) should close findings") + @tag("performance") @skip_unless_v2 @@ -235,7 +276,7 @@ class TestDojoImporterPerformanceSmall(TestDojoImporterPerformanceBase): """Performance tests using small sample files (StackHawk, ~6 findings).""" - def _import_reimport_performance(self, expected_num_queries1, expected_num_async_tasks1, expected_num_queries2, expected_num_async_tasks2, expected_num_queries3, expected_num_async_tasks3): + def _import_reimport_performance(self, expected_num_queries1, expected_num_async_tasks1, expected_num_queries2, expected_num_async_tasks2, expected_num_queries3, expected_num_async_tasks3, expected_num_queries4, expected_num_async_tasks4): """ Log output can be quite large as when the assertNumQueries fails, all queries are printed. It could be usefule to capture the output in `less`: @@ -251,12 +292,16 @@ def _import_reimport_performance(self, expected_num_queries1, expected_num_async expected_num_async_tasks2, expected_num_queries3, expected_num_async_tasks3, + expected_num_queries4, + expected_num_async_tasks4, scan_file1=STACK_HAWK_SUBSET_FILENAME, scan_file2=STACK_HAWK_FILENAME, scan_file3=STACK_HAWK_SUBSET_FILENAME, + scan_file4=STACK_HAWK_EMPTY, scan_type=STACK_HAWK_SCAN_TYPE, product_name="TestDojoDefaultImporter", engagement_name="Test Create Engagement", + close_old_findings4=True, ) @override_settings(ENABLE_AUDITLOG=True) @@ -275,6 +320,8 @@ def test_import_reimport_reimport_performance_pghistory_async(self): expected_num_async_tasks2=17, expected_num_queries3=108, expected_num_async_tasks3=16, + expected_num_queries4=155, + expected_num_async_tasks4=6, ) @override_settings(ENABLE_AUDITLOG=True) @@ -297,6 +344,8 @@ def test_import_reimport_reimport_performance_pghistory_no_async(self): expected_num_async_tasks2=17, expected_num_queries3=115, expected_num_async_tasks3=16, + expected_num_queries4=155, + expected_num_async_tasks4=6, ) @override_settings(ENABLE_AUDITLOG=True) @@ -320,6 +369,8 @@ def test_import_reimport_reimport_performance_pghistory_no_async_with_product_gr expected_num_async_tasks2=19, expected_num_queries3=119, expected_num_async_tasks3=18, + expected_num_queries4=162, + expected_num_async_tasks4=8, ) # Deduplication is enabled in the tests above, but to properly test it we must run the same import twice and capture the results. @@ -486,7 +537,7 @@ def setUp(self): for model in [Location, LocationFindingReference]: ContentType.objects.get_for_model(model) - def _import_reimport_performance(self, expected_num_queries1, expected_num_async_tasks1, expected_num_queries2, expected_num_async_tasks2, expected_num_queries3, expected_num_async_tasks3): + def _import_reimport_performance(self, expected_num_queries1, expected_num_async_tasks1, expected_num_queries2, expected_num_async_tasks2, expected_num_queries3, expected_num_async_tasks3, expected_num_queries4, expected_num_async_tasks4): r""" Log output can be quite large as when the assertNumQueries fails, all queries are printed. It could be useful to capture the output in `less`: @@ -502,12 +553,16 @@ def _import_reimport_performance(self, expected_num_queries1, expected_num_async expected_num_async_tasks2, expected_num_queries3, expected_num_async_tasks3, + expected_num_queries4, + expected_num_async_tasks4, scan_file1=STACK_HAWK_SUBSET_FILENAME, scan_file2=STACK_HAWK_FILENAME, scan_file3=STACK_HAWK_SUBSET_FILENAME, + scan_file4=STACK_HAWK_EMPTY, scan_type=STACK_HAWK_SCAN_TYPE, product_name="TestDojoDefaultImporterLocations", engagement_name="Test Create Engagement Locations", + close_old_findings4=True, ) @override_settings(ENABLE_AUDITLOG=True) @@ -526,6 +581,8 @@ def test_import_reimport_reimport_performance_pghistory_async(self): expected_num_async_tasks2=17, expected_num_queries3=346, expected_num_async_tasks3=16, + expected_num_queries4=212, + expected_num_async_tasks4=6, ) @override_settings(ENABLE_AUDITLOG=True) @@ -548,6 +605,8 @@ def test_import_reimport_reimport_performance_pghistory_no_async(self): expected_num_async_tasks2=17, expected_num_queries3=355, expected_num_async_tasks3=16, + expected_num_queries4=212, + expected_num_async_tasks4=6, ) @override_settings(ENABLE_AUDITLOG=True) @@ -571,6 +630,8 @@ def test_import_reimport_reimport_performance_pghistory_no_async_with_product_gr expected_num_async_tasks2=19, expected_num_queries3=359, expected_num_async_tasks3=18, + expected_num_queries4=222, + expected_num_async_tasks4=8, ) def _deduplication_performance(self, expected_num_queries1, expected_num_async_tasks1, expected_num_queries2, expected_num_async_tasks2, *, check_duplicates=True): From 8d66b079c5790d842322c9957d94d183af7c333a Mon Sep 17 00:00:00 2001 From: valentijnscholten Date: Mon, 6 Apr 2026 17:42:26 +0200 Subject: [PATCH 14/15] async search index: run async (#14639) --- dojo/middleware.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dojo/middleware.py b/dojo/middleware.py index 8d274202f90..231846a4efe 100644 --- a/dojo/middleware.py +++ b/dojo/middleware.py @@ -326,6 +326,7 @@ def _trigger_async_index_update(self, model_groups): # Import here to avoid circular import from django.conf import settings # noqa: PLC0415 circular import + from dojo.celery_dispatch import dojo_dispatch_task # noqa: PLC0415 circular import from dojo.tasks import update_watson_search_index_for_model # noqa: PLC0415 circular import # Create tasks per model type, chunking large lists into configurable batches @@ -337,4 +338,4 @@ def _trigger_async_index_update(self, model_groups): # Create tasks for each batch and log each one for i, batch in enumerate(batches, 1): logger.debug(f"AsyncSearchContextMiddleware: Triggering batch {i}/{len(batches)} for {model_name}: {len(batch)} instances") - update_watson_search_index_for_model(model_name, batch) + dojo_dispatch_task(update_watson_search_index_for_model, model_name, batch) From 7a7a402c337906a346a8ecbd5fd4a5735dc7ea21 Mon Sep 17 00:00:00 2001 From: Jino Tesauro <53376807+Jino-T@users.noreply.github.com> Date: Mon, 6 Apr 2026 11:09:16 -0500 Subject: [PATCH 15/15] AWS Inspector 2 Line number bug + other changes (#14616) * Fixed line number bug and added multiple fields to Package Vulnerability finding type * changed startLine and endLine to keep descriptions consistent with past imports * Add LocationData.dependency() support for package vulnerability findings Populate unsaved_locations with dependency location data from vulnerablePackages, gated behind V3_FEATURE_LOCATIONS. Also fix process_endpoints to extend rather than overwrite unsaved_locations so dependency locations are preserved. Co-Authored-By: Claude Opus 4.6 (1M context) * Remove validate_locations call from metadata test The test fixture contains Lambda ARNs with "$LATEST" which produces invalid hostnames for endpoint validation. Endpoint validation is already covered by the other parser tests. Co-Authored-By: Claude Opus 4.6 (1M context) * Gate LocationData test assertions behind V3_FEATURE_LOCATIONS Finding.unsaved_locations only exists when V3_FEATURE_LOCATIONS is enabled, so the dependency location assertions must be conditional. Co-Authored-By: Claude Opus 4.6 (1M context) * Fix import sorting for ruff linting Co-Authored-By: Claude Opus 4.6 (1M context) --------- Co-authored-by: Cody Maffucci <46459665+Maffooch@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 (1M context) --- dojo/tools/aws_inspector2/parser.py | 44 +- .../aws_inspector2_package_vuln_metadata.json | 3340 +++++++++++++++++ unittests/tools/test_aws_inspector2_parser.py | 39 +- 3 files changed, 3414 insertions(+), 9 deletions(-) create mode 100644 unittests/scans/aws_inspector2/aws_inspector2_package_vuln_metadata.json diff --git a/dojo/tools/aws_inspector2/parser.py b/dojo/tools/aws_inspector2/parser.py index 0b95d842c38..2174d06e977 100644 --- a/dojo/tools/aws_inspector2/parser.py +++ b/dojo/tools/aws_inspector2/parser.py @@ -1,3 +1,4 @@ +import contextlib import json from datetime import UTC, datetime @@ -114,6 +115,7 @@ def get_cvss_details(self, finding: Finding, raw_finding: dict) -> Finding: def get_package_vulnerability(self, finding: Finding, raw_finding: dict) -> Finding: vulnerability_details = raw_finding.get("packageVulnerabilityDetails", {}) + vulnerable_packages = vulnerability_details.get("vulnerablePackages", []) vulnerability_packages_descriptions = "\n".join( [ ( @@ -123,14 +125,40 @@ def get_package_vulnerability(self, finding: Finding, raw_finding: dict) -> Find f"\tfixed version: {vulnerability_package.get('fixedInVersion', 'N/A')}\n" f"\tremediation: {vulnerability_package.get('remediation', 'N/A')}\n" ) - for vulnerability_package in vulnerability_details.get("vulnerablePackages", []) + for vulnerability_package in vulnerable_packages ], ) if (vulnerability_id := vulnerability_details.get("vulnerabilityId", None)) is not None: finding.unsaved_vulnerability_ids = [vulnerability_id] vulnerability_source = vulnerability_details.get("source") vulnerability_source_url = vulnerability_details.get("sourceUrl") - # populate fields + # component name/version/file_path from the first vulnerable package + if vulnerable_packages: + finding.component_name = vulnerable_packages[0].get("name") + finding.component_version = vulnerable_packages[0].get("version") + finding.file_path = vulnerable_packages[0].get("filePath") + if settings.V3_FEATURE_LOCATIONS and finding.component_name: + finding.unsaved_locations.append( + LocationData.dependency( + name=finding.component_name, + version=finding.component_version or "", + file_path=finding.file_path or "", + ), + ) + # reference URLs from the advisory + reference_urls = vulnerability_details.get("referenceUrls", []) + if reference_urls: + finding.references = "\n".join(reference_urls) + # publish date from when the vendor first created the advisory + if vendor_created_at := vulnerability_details.get("vendorCreatedAt"): + with contextlib.suppress(ValueError): + finding.publish_date = date_parser.parse(vendor_created_at).date() + # CVSS v3 base score from the vendor-supplied CVSS entries + for cvss_entry in vulnerability_details.get("cvss", []): + if str(cvss_entry.get("version", "")).startswith("3") and cvss_entry.get("baseScore") is not None: + finding.cvssv3_score = float(cvss_entry["baseScore"]) + break + # populate description fields if vulnerability_source is not None and vulnerability_source_url is not None: finding.url = vulnerability_source_url finding.description += ( @@ -149,8 +177,8 @@ def get_code_vulnerability(self, finding: Finding, raw_finding: dict) -> Finding file_path_info = raw_finding.get("filePath", {}) file_name = file_path_info.get("fileName", "N/A") file_path = file_path_info.get("filePath", "N/A") - start_line = file_path_info.get("startLine", "N/A") - end_line = file_path_info.get("endLine", "N/A") + start_line = file_path_info.get("startLine", None) + end_line = file_path_info.get("endLine", None) detector_tags = ", ".join(raw_finding.get("detectorTags", [])) reference_urls = ", ".join(raw_finding.get("referenceUrls", [])) rule_id = raw_finding.get("ruleId", "N/A") @@ -162,6 +190,10 @@ def get_code_vulnerability(self, finding: Finding, raw_finding: dict) -> Finding finding.sast_source_file_path = f"{file_path}{file_name}" finding.line = start_line finding.sast_source_line = start_line + if start_line is None: + start_line = "N/A" + if end_line is None: + end_line = "N/A" finding.description += ( "\n**Additional info**\n" f"CWEs: {string_cwes}\n" @@ -270,9 +302,9 @@ def process_endpoints(self, finding: Finding, raw_finding: dict) -> Finding: endpoints.append(Endpoint(host=endpoint_host)) finding.impact = "\n".join(impact) if settings.V3_FEATURE_LOCATIONS: - finding.unsaved_locations = endpoints + finding.unsaved_locations.extend(endpoints) else: # TODO: Delete this after the move to Locations - finding.unsaved_endpoints = endpoints + finding.unsaved_endpoints.extend(endpoints) return finding diff --git a/unittests/scans/aws_inspector2/aws_inspector2_package_vuln_metadata.json b/unittests/scans/aws_inspector2/aws_inspector2_package_vuln_metadata.json new file mode 100644 index 00000000000..a8fdb2a07c2 --- /dev/null +++ b/unittests/scans/aws_inspector2/aws_inspector2_package_vuln_metadata.json @@ -0,0 +1,3340 @@ +{ + "findings": [ + { + "findingArn": "arn:aws:inspector2:us-west-2:123456789012:finding/00000000000000000000000000000001", + "awsAccountId": "123456789016", + "type": "PACKAGE_VULNERABILITY", + "description": "Due to the design of the name constraint checking algorithm, the processing time of some inputs scale non-linearly with respect to the size of the certificate. This affects programs which validate arbitrary certificate chains.", + "title": "CVE-2025-58187 - go/stdlib", + "remediation": { + "recommendation": { + "text": "None Provided" + } + }, + "severity": "HIGH", + "firstObservedAt": "2025-12-26 14:21:44.742000+01:00", + "lastObservedAt": "2026-03-13 22:38:57.161000+01:00", + "updatedAt": "2026-03-13 22:38:57.161000+01:00", + "status": "ACTIVE", + "resources": [ + { + "type": "AWS_LAMBDA_FUNCTION", + "id": "arn:aws:lambda:us-west-2:123456789014:function:web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD:$LATEST", + "partition": "aws", + "region": "us-west-2", + "tags": { + "InspectorCodeExclusion": "None", + "InspectorExclusion": "None", + "aws:cloudformation:logical-id": "healthCheck", + "aws:cloudformation:stack-id": "arn:aws:cloudformation:us-west-2:123456789015:stack/web-user-manager-api-stage/a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "aws:cloudformation:stack-name": "stack name", + "deployed_at": "2026-02-18T12:38:52Z", + "deployed_by": "user1@example.com", + "env": "stage", + "environment": "stage", + "gitlab_ci_job": "1234568", + "lambda:createdBy": "DeployUser", + "owner_email": "user2@example.com", + "project": "web-user-manager-api", + "service": "web-user-manager-api", + "team": "backend-team-web-user-manager" + }, + "details": { + "awsLambdaFunction": { + "functionName": "web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD", + "runtime": "PYTHON_3_12", + "codeSha256": "abc123def456ghi789jkl012mno345pqr678stu901vw==", + "version": "$LATEST", + "executionRoleArn": "arn:aws:iam::123456789012:role/web-user-manager-api-stage-LambdaExecutionRole-EXAMPLE12345", + "layers": [ + "arn:aws:lambda:us-west-2:123456789012:layer:web-user-manager-api-stage:12", + "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + ], + "vpcConfig": { + "subnetIds": [ + "subnet-03709ee21c427acf6", + "subnet-0b6f7a6987b5e689d", + "subnet-0123c6fff46639b68" + ], + "securityGroupIds": [ + "sg-0fd8fe5dae2694a95" + ], + "vpcId": "vpc-055aa15ae33f4297b" + }, + "packageType": "ZIP", + "architectures": [ + "X86_64" + ], + "lastModifiedAt": "2026-02-18 13:40:35.830000+01:00" + } + } + } + ], + "inspectorScore": 7.5, + "inspectorScoreDetails": { + "adjustedCvss": { + "scoreSource": "NVD", + "cvssSource": "NVD", + "version": "3.1", + "score": 7.5, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "adjustments": [] + } + }, + "packageVulnerabilityDetails": { + "vulnerabilityId": "CVE-2025-58187", + "vulnerablePackages": [ + { + "name": "go/stdlib", + "version": "1.24.4", + "epoch": 0, + "packageManager": "GENERIC", + "filePath": "extensions/collector", + "fixedInVersion": "1.25.3", + "sourceLambdaLayerArn": "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + } + ], + "source": "NVD", + "cvss": [ + { + "baseScore": 7.5, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "version": "3.1", + "source": "NVD" + } + ], + "relatedVulnerabilities": [], + "sourceUrl": "https://nvd.nist.gov/vuln/detail/CVE-2025-58187", + "vendorSeverity": "HIGH", + "vendorCreatedAt": "2025-10-30 00:16:19+01:00", + "vendorUpdatedAt": "2026-01-29 17:02:27+01:00", + "referenceUrls": [ + "https://nvd.nist.gov/vuln/detail/CVE-2025-58187", + "https://groups.google.com/g/golang-announce/c/4Emdl2iQ_bI" + ] + }, + "fixAvailable": "YES", + "exploitAvailable": "NO", + "epss": { + "score": 0.00013 + } + }, + { + "findingArn": "arn:aws:inspector2:us-west-2:123456789012:finding/00000000000000000000000000000002", + "awsAccountId": "123456789012", + "type": "PACKAGE_VULNERABILITY", + "description": "Requests is a HTTP library. Due to a URL parsing issue, Requests releases prior to 2.32.4 may leak .netrc credentials to third parties for specific maliciously-crafted URLs. Users should upgrade to version 2.32.4 to receive a fix. For older versions of Requests, use of the .netrc file can be disabled with `trust_env=False` on one's Requests Session.", + "title": "CVE-2024-47081 - requests", + "remediation": { + "recommendation": { + "text": "None Provided" + } + }, + "severity": "MEDIUM", + "firstObservedAt": "2025-06-10 23:43:07.201000+02:00", + "lastObservedAt": "2026-03-07 23:40:17.655000+01:00", + "updatedAt": "2026-03-07 23:40:17.655000+01:00", + "status": "ACTIVE", + "resources": [ + { + "type": "AWS_LAMBDA_FUNCTION", + "id": "arn:aws:lambda:us-west-2:123456789012:function:web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD:$LATEST", + "partition": "aws", + "region": "us-west-2", + "tags": { + "InspectorCodeExclusion": "None", + "InspectorExclusion": "None", + "aws:cloudformation:logical-id": "healthCheck", + "aws:cloudformation:stack-id": "arn:aws:cloudformation:us-west-2:123456789012:stack/web-user-manager-api-stage/a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "aws:cloudformation:stack-name": "web-user-manager-api-stage", + "deployed_at": "2026-02-18T12:38:52Z", + "deployed_by": "user2@example.com", + "env": "stage", + "environment": "stage", + "gitlab_ci_job": "1234567", + "lambda:createdBy": "SAM", + "owner_email": "user1@example.com", + "project": "web-user-manager-api", + "service": "web-user-manager-api", + "team": "backend-team-web-user-manager" + }, + "details": { + "awsLambdaFunction": { + "functionName": "web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD", + "runtime": "PYTHON_3_12", + "codeSha256": "abc123def456ghi789jkl012mno345pqr678stu901vw==", + "version": "$LATEST", + "executionRoleArn": "arn:aws:iam::123456789012:role/web-user-manager-api-stage-LambdaExecutionRole-EXAMPLE12345", + "layers": [ + "arn:aws:lambda:us-west-2:123456789012:layer:web-user-manager-api-stage:12", + "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + ], + "vpcConfig": { + "subnetIds": [ + "subnet-03709ee21c427acf6", + "subnet-0b6f7a6987b5e689d", + "subnet-0123c6fff46639b68" + ], + "securityGroupIds": [ + "sg-0fd8fe5dae2694a95" + ], + "vpcId": "vpc-055aa15ae33f4297b" + }, + "packageType": "ZIP", + "architectures": [ + "X86_64" + ], + "lastModifiedAt": "2026-02-18 13:40:35.830000+01:00" + } + } + } + ], + "inspectorScore": 5.3, + "inspectorScoreDetails": { + "adjustedCvss": { + "scoreSource": "NVD", + "cvssSource": "NVD", + "version": "3.1", + "score": 5.3, + "scoringVector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:N/A:N", + "adjustments": [] + } + }, + "packageVulnerabilityDetails": { + "vulnerabilityId": "CVE-2024-47081", + "vulnerablePackages": [ + { + "name": "requests", + "version": "2.32.0", + "epoch": 0, + "packageManager": "PYTHON", + "filePath": "python/requests-2.32.0.dist-info/METADATA", + "fixedInVersion": "2.32.4", + "sourceLambdaLayerArn": "arn:aws:lambda:us-west-2:123456789012:layer:web-user-manager-api-stage:12" + }, + { + "name": "requests", + "version": "2.32.0", + "epoch": 0, + "packageManager": "PYTHON", + "filePath": "requirements.txt", + "fixedInVersion": "2.32.4" + } + ], + "source": "NVD", + "cvss": [ + { + "baseScore": 5.3, + "scoringVector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:N/A:N", + "version": "3.1", + "source": "NVD" + } + ], + "relatedVulnerabilities": [], + "sourceUrl": "https://nvd.nist.gov/vuln/detail/CVE-2024-47081", + "vendorSeverity": "MEDIUM", + "vendorCreatedAt": "2025-06-09 20:15:24+02:00", + "vendorUpdatedAt": "2025-06-12 18:06:47+02:00", + "referenceUrls": [ + "https://seclists.org/fulldisclosure/2025/Jun/2", + "https://nvd.nist.gov/vuln/detail/CVE-2024-47081", + "https://github.com/psf/requests/commit/96ba401c1296ab1dda74a2365ef36d88f7d144ef", + "https://github.com/psf/requests/pull/6965", + "https://github.com/psf/requests/security/advisories/GHSA-9hjg-9r4m-mvj7" + ] + }, + "fixAvailable": "YES", + "exploitAvailable": "NO", + "epss": { + "score": 0.00154 + } + }, + { + "findingArn": "arn:aws:inspector2:us-west-2:123456789012:finding/00000000000000000000000000000003", + "awsAccountId": "123456789012", + "type": "PACKAGE_VULNERABILITY", + "description": "The net/url package does not set a limit on the number of query parameters in a query. While the maximum size of query parameters in URLs is generally limited by the maximum request header size, the net/http.Request.ParseForm method can parse large URL-encoded forms. Parsing a large form containing many unique query parameters can cause excessive memory consumption.", + "title": "CVE-2025-61726 - go/stdlib", + "remediation": { + "recommendation": { + "text": "None Provided" + } + }, + "severity": "HIGH", + "firstObservedAt": "2026-01-29 22:42:51.151000+01:00", + "lastObservedAt": "2026-03-07 23:40:17.700000+01:00", + "updatedAt": "2026-03-07 23:40:17.700000+01:00", + "status": "ACTIVE", + "resources": [ + { + "type": "AWS_LAMBDA_FUNCTION", + "id": "arn:aws:lambda:us-west-2:123456789012:function:web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD:$LATEST", + "partition": "aws", + "region": "us-west-2", + "tags": { + "InspectorCodeExclusion": "None", + "InspectorExclusion": "None", + "aws:cloudformation:logical-id": "healthCheck", + "aws:cloudformation:stack-id": "arn:aws:cloudformation:us-west-2:123456789012:stack/web-user-manager-api-stage/a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "aws:cloudformation:stack-name": "web-user-manager-api-stage", + "deployed_at": "2026-02-18T12:38:52Z", + "deployed_by": "user1@example.com", + "env": "stage", + "environment": "stage", + "gitlab_ci_job": "1234567", + "lambda:createdBy": "SAM", + "owner_email": "user1@example.com", + "project": "web-user-manager-api", + "service": "web-user-manager-api", + "team": "backend-team-web-user-manager" + }, + "details": { + "awsLambdaFunction": { + "functionName": "web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD", + "runtime": "PYTHON_3_12", + "codeSha256": "abc123def456ghi789jkl012mno345pqr678stu901vw==", + "version": "$LATEST", + "executionRoleArn": "arn:aws:iam::123456789012:role/web-user-manager-api-stage-LambdaExecutionRole-EXAMPLE12345", + "layers": [ + "arn:aws:lambda:us-west-2:123456789012:layer:web-user-manager-api-stage:12", + "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + ], + "vpcConfig": { + "subnetIds": [ + "subnet-03709ee21c427acf6", + "subnet-0b6f7a6987b5e689d", + "subnet-0123c6fff46639b68" + ], + "securityGroupIds": [ + "sg-0fd8fe5dae2694a95" + ], + "vpcId": "vpc-055aa15ae33f4297b" + }, + "packageType": "ZIP", + "architectures": [ + "X86_64" + ], + "lastModifiedAt": "2026-02-18 13:40:35.830000+01:00" + } + } + } + ], + "inspectorScore": 7.5, + "inspectorScoreDetails": { + "adjustedCvss": { + "scoreSource": "NVD", + "cvssSource": "NVD", + "version": "3.1", + "score": 7.5, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "adjustments": [] + } + }, + "packageVulnerabilityDetails": { + "vulnerabilityId": "CVE-2025-61726", + "vulnerablePackages": [ + { + "name": "go/stdlib", + "version": "1.24.4", + "epoch": 0, + "packageManager": "GENERIC", + "filePath": "extensions/collector", + "fixedInVersion": "1.25.6", + "sourceLambdaLayerArn": "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + } + ], + "source": "NVD", + "cvss": [ + { + "baseScore": 7.5, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "version": "3.1", + "source": "NVD" + } + ], + "relatedVulnerabilities": [], + "sourceUrl": "https://nvd.nist.gov/vuln/detail/CVE-2025-61726", + "vendorSeverity": "HIGH", + "vendorCreatedAt": "2026-01-28 21:16:09+01:00", + "vendorUpdatedAt": "2026-02-06 19:47:34+01:00", + "referenceUrls": [ + "https://nvd.nist.gov/vuln/detail/CVE-2025-61726", + "https://groups.google.com/g/golang-announce/c/Vd2tYVM8eUc" + ] + }, + "fixAvailable": "YES", + "exploitAvailable": "NO", + "epss": { + "score": 0.00032 + } + }, + { + "findingArn": "arn:aws:inspector2:us-west-2:123456789012:finding/00000000000000000000000000000004", + "awsAccountId": "123456789012", + "type": "PACKAGE_VULNERABILITY", + "description": "Expr is an expression language and expression evaluation for Go. Prior to version 1.17.7, several builtin functions in Expr, including `flatten`, `min`, `max`, `mean`, and `median`, perform recursive traversal over user-provided data structures without enforcing a maximum recursion depth. If the evaluation environment contains deeply nested or cyclic data structures, these functions may recurse indefinitely until exceed the Go runtime stack limit. This results in a stack overflow panic, causing the host application to crash. While exploitability depends on whether an attacker can influence or inject cyclic or pathologically deep data into the evaluation environment, this behavior represents a denial-of-service (DoS) risk and affects overall library robustness. Instead of returning a recoverable evaluation error, the process may terminate unexpectedly. In affected versions, evaluation of expressions that invoke certain builtin functions on untrusted or insufficiently validated data structures can lead to a pro", + "title": "CVE-2025-68156 - github.com/expr-lang/expr", + "remediation": { + "recommendation": { + "text": "None Provided" + } + }, + "severity": "HIGH", + "firstObservedAt": "2025-12-26 14:21:44.662000+01:00", + "lastObservedAt": "2026-03-07 23:40:17.764000+01:00", + "updatedAt": "2026-03-07 23:40:17.764000+01:00", + "status": "ACTIVE", + "resources": [ + { + "type": "AWS_LAMBDA_FUNCTION", + "id": "arn:aws:lambda:us-west-2:123456789012:function:web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD:$LATEST", + "partition": "aws", + "region": "us-west-2", + "tags": { + "InspectorCodeExclusion": "None", + "InspectorExclusion": "None", + "aws:cloudformation:logical-id": "healthCheck", + "aws:cloudformation:stack-id": "arn:aws:cloudformation:us-west-2:123456789012:stack/web-user-manager-api-stage/a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "aws:cloudformation:stack-name": "web-user-manager-api-stage", + "deployed_at": "2026-02-18T12:38:52Z", + "deployed_by": "user1@example.com", + "env": "stage", + "environment": "stage", + "gitlab_ci_job": "1234567", + "lambda:createdBy": "SAM", + "owner_email": "user1@example.com", + "project": "web-user-manager-api", + "service": "web-user-manager-api", + "team": "backend-team-web-user-manager" + }, + "details": { + "awsLambdaFunction": { + "functionName": "web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD", + "runtime": "PYTHON_3_12", + "codeSha256": "abc123def456ghi789jkl012mno345pqr678stu901vw==", + "version": "$LATEST", + "executionRoleArn": "arn:aws:iam::123456789012:role/web-user-manager-api-stage-LambdaExecutionRole-EXAMPLE12345", + "layers": [ + "arn:aws:lambda:us-west-2:123456789012:layer:web-user-manager-api-stage:12", + "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + ], + "vpcConfig": { + "subnetIds": [ + "subnet-03709ee21c427acf6", + "subnet-0b6f7a6987b5e689d", + "subnet-0123c6fff46639b68" + ], + "securityGroupIds": [ + "sg-0fd8fe5dae2694a95" + ], + "vpcId": "vpc-055aa15ae33f4297b" + }, + "packageType": "ZIP", + "architectures": [ + "X86_64" + ], + "lastModifiedAt": "2026-02-18 13:40:35.830000+01:00" + } + } + } + ], + "inspectorScore": 7.5, + "inspectorScoreDetails": { + "adjustedCvss": { + "scoreSource": "NVD", + "cvssSource": "NVD", + "version": "3.1", + "score": 7.5, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "adjustments": [] + } + }, + "packageVulnerabilityDetails": { + "vulnerabilityId": "CVE-2025-68156", + "vulnerablePackages": [ + { + "name": "github.com/expr-lang/expr", + "version": "v1.17.6", + "epoch": 0, + "packageManager": "GO", + "filePath": "extensions/collector", + "fixedInVersion": "1.17.7", + "sourceLambdaLayerArn": "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + } + ], + "source": "NVD", + "cvss": [ + { + "baseScore": 7.5, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "version": "3.1", + "source": "NVD" + } + ], + "relatedVulnerabilities": [], + "sourceUrl": "https://nvd.nist.gov/vuln/detail/CVE-2025-68156", + "vendorSeverity": "HIGH", + "vendorCreatedAt": "2025-12-16 20:16:00+01:00", + "vendorUpdatedAt": "2026-03-05 20:56:33+01:00", + "referenceUrls": [ + "https://github.com/expr-lang/expr/pull/870", + "https://nvd.nist.gov/vuln/detail/CVE-2025-68156", + "https://github.com/expr-lang/expr/security/advisories/GHSA-cfpf-hrx2-8rv6" + ] + }, + "fixAvailable": "YES", + "exploitAvailable": "NO", + "epss": { + "score": 0.00085 + } + }, + { + "findingArn": "arn:aws:inspector2:us-west-2:123456789012:finding/00000000000000000000000000000005", + "awsAccountId": "123456789012", + "type": "PACKAGE_VULNERABILITY", + "description": "The Parse function permits values other than IPv6 addresses to be included in square brackets within the host component of a URL. RFC 3986 permits IPv6 addresses to be included within the host component, enclosed within square brackets. For example: \"http://[::1]/\". IPv4 addresses and hostnames must not appear within square brackets. Parse did not enforce this requirement.", + "title": "CVE-2025-47912 - go/stdlib", + "remediation": { + "recommendation": { + "text": "None Provided" + } + }, + "severity": "MEDIUM", + "firstObservedAt": "2025-12-26 14:21:44.742000+01:00", + "lastObservedAt": "2026-03-13 22:38:57.160000+01:00", + "updatedAt": "2026-03-13 22:38:57.160000+01:00", + "status": "ACTIVE", + "resources": [ + { + "type": "AWS_LAMBDA_FUNCTION", + "id": "arn:aws:lambda:us-west-2:123456789012:function:web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD:$LATEST", + "partition": "aws", + "region": "us-west-2", + "tags": { + "InspectorCodeExclusion": "None", + "InspectorExclusion": "None", + "aws:cloudformation:logical-id": "healthCheck", + "aws:cloudformation:stack-id": "arn:aws:cloudformation:us-west-2:123456789012:stack/web-user-manager-api-stage/a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "aws:cloudformation:stack-name": "web-user-manager-api-stage", + "deployed_at": "2026-02-18T12:38:52Z", + "deployed_by": "user1@example.com", + "env": "stage", + "environment": "stage", + "gitlab_ci_job": "1234567", + "lambda:createdBy": "SAM", + "owner_email": "user1@example.com", + "project": "web-user-manager-api", + "service": "web-user-manager-api", + "team": "backend-team-web-user-manager" + }, + "details": { + "awsLambdaFunction": { + "functionName": "web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD", + "runtime": "PYTHON_3_12", + "codeSha256": "abc123def456ghi789jkl012mno345pqr678stu901vw==", + "version": "$LATEST", + "executionRoleArn": "arn:aws:iam::123456789012:role/web-user-manager-api-stage-LambdaExecutionRole-EXAMPLE12345", + "layers": [ + "arn:aws:lambda:us-west-2:123456789012:layer:web-user-manager-api-stage:12", + "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + ], + "vpcConfig": { + "subnetIds": [ + "subnet-03709ee21c427acf6", + "subnet-0b6f7a6987b5e689d", + "subnet-0123c6fff46639b68" + ], + "securityGroupIds": [ + "sg-0fd8fe5dae2694a95" + ], + "vpcId": "vpc-055aa15ae33f4297b" + }, + "packageType": "ZIP", + "architectures": [ + "X86_64" + ], + "lastModifiedAt": "2026-02-18 13:40:35.830000+01:00" + } + } + } + ], + "inspectorScore": 5.3, + "inspectorScoreDetails": { + "adjustedCvss": { + "scoreSource": "NVD", + "cvssSource": "NVD", + "version": "3.1", + "score": 5.3, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N", + "adjustments": [] + } + }, + "packageVulnerabilityDetails": { + "vulnerabilityId": "CVE-2025-47912", + "vulnerablePackages": [ + { + "name": "go/stdlib", + "version": "1.24.4", + "epoch": 0, + "packageManager": "GENERIC", + "filePath": "extensions/collector", + "fixedInVersion": "1.25.2", + "sourceLambdaLayerArn": "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + } + ], + "source": "NVD", + "cvss": [ + { + "baseScore": 5.3, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N", + "version": "3.1", + "source": "NVD" + } + ], + "relatedVulnerabilities": [], + "sourceUrl": "https://nvd.nist.gov/vuln/detail/CVE-2025-47912", + "vendorSeverity": "MEDIUM", + "vendorCreatedAt": "2025-10-30 00:16:18+01:00", + "vendorUpdatedAt": "2026-01-29 14:57:18+01:00", + "referenceUrls": [ + "https://nvd.nist.gov/vuln/detail/CVE-2025-47912", + "https://groups.google.com/g/golang-announce/c/4Emdl2iQ_bI" + ] + }, + "fixAvailable": "YES", + "exploitAvailable": "NO", + "epss": { + "score": 0.00023 + } + }, + { + "findingArn": "arn:aws:inspector2:us-west-2:123456789012:finding/00000000000000000000000000000006", + "awsAccountId": "123456789012", + "type": "PACKAGE_VULNERABILITY", + "description": "Within HostnameError.Error(), when constructing an error string, there is no limit to the number of hosts that will be printed out. Furthermore, the error string is constructed by repeated string concatenation, leading to quadratic runtime. Therefore, a certificate provided by a malicious actor can result in excessive resource consumption.", + "title": "CVE-2025-61729 - go/stdlib", + "remediation": { + "recommendation": { + "text": "None Provided" + } + }, + "severity": "HIGH", + "firstObservedAt": "2025-12-26 14:21:44.741000+01:00", + "lastObservedAt": "2026-02-18 13:40:45.341000+01:00", + "updatedAt": "2026-02-18 13:40:45.341000+01:00", + "status": "ACTIVE", + "resources": [ + { + "type": "AWS_LAMBDA_FUNCTION", + "id": "arn:aws:lambda:us-west-2:123456789012:function:web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD:$LATEST", + "partition": "aws", + "region": "us-west-2", + "tags": { + "InspectorCodeExclusion": "None", + "InspectorExclusion": "None", + "aws:cloudformation:logical-id": "healthCheck", + "aws:cloudformation:stack-id": "arn:aws:cloudformation:us-west-2:123456789012:stack/web-user-manager-api-stage/a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "aws:cloudformation:stack-name": "web-user-manager-api-stage", + "deployed_at": "2026-02-18T12:38:52Z", + "deployed_by": "user1@example.com", + "env": "stage", + "environment": "stage", + "gitlab_ci_job": "1234567", + "lambda:createdBy": "SAM", + "owner_email": "user1@example.com", + "project": "web-user-manager-api", + "service": "web-user-manager-api", + "team": "backend-team-web-user-manager" + }, + "details": { + "awsLambdaFunction": { + "functionName": "web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD", + "runtime": "PYTHON_3_12", + "codeSha256": "abc123def456ghi789jkl012mno345pqr678stu901vw==", + "version": "$LATEST", + "executionRoleArn": "arn:aws:iam::123456789012:role/web-user-manager-api-stage-LambdaExecutionRole-EXAMPLE12345", + "layers": [ + "arn:aws:lambda:us-west-2:123456789012:layer:web-user-manager-api-stage:12", + "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + ], + "vpcConfig": { + "subnetIds": [ + "subnet-03709ee21c427acf6", + "subnet-0b6f7a6987b5e689d", + "subnet-0123c6fff46639b68" + ], + "securityGroupIds": [ + "sg-0fd8fe5dae2694a95" + ], + "vpcId": "vpc-055aa15ae33f4297b" + }, + "packageType": "ZIP", + "architectures": [ + "X86_64" + ], + "lastModifiedAt": "2026-02-18 13:40:35.830000+01:00" + } + } + } + ], + "inspectorScore": 7.5, + "inspectorScoreDetails": { + "adjustedCvss": { + "scoreSource": "NVD", + "cvssSource": "NVD", + "version": "3.1", + "score": 7.5, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "adjustments": [] + } + }, + "packageVulnerabilityDetails": { + "vulnerabilityId": "CVE-2025-61729", + "vulnerablePackages": [ + { + "name": "go/stdlib", + "version": "1.24.4", + "epoch": 0, + "packageManager": "GENERIC", + "filePath": "extensions/collector", + "fixedInVersion": "1.25.5", + "sourceLambdaLayerArn": "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + } + ], + "source": "NVD", + "cvss": [ + { + "baseScore": 7.5, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "version": "3.1", + "source": "NVD" + } + ], + "relatedVulnerabilities": [], + "sourceUrl": "https://nvd.nist.gov/vuln/detail/CVE-2025-61729", + "vendorSeverity": "HIGH", + "vendorCreatedAt": "2025-12-02 20:15:51+01:00", + "vendorUpdatedAt": "2025-12-19 19:25:28+01:00", + "referenceUrls": [ + "https://groups.google.com/g/golang-announce/c/8FJoBkPddm4", + "https://nvd.nist.gov/vuln/detail/CVE-2025-61729" + ] + }, + "fixAvailable": "YES", + "exploitAvailable": "NO", + "epss": { + "score": 0.00017 + } + }, + { + "findingArn": "arn:aws:inspector2:us-west-2:123456789012:finding/00000000000000000000000000000007", + "awsAccountId": "123456789012", + "type": "PACKAGE_VULNERABILITY", + "description": "During the TLS 1.3 handshake if multiple messages are sent in records that span encryption level boundaries (for instance the Client Hello and Encrypted Extensions messages), the subsequent messages may be processed before the encryption level changes. This can cause some minor information disclosure if a network-local attacker can inject messages during the handshake.", + "title": "CVE-2025-61730 - go/stdlib", + "remediation": { + "recommendation": { + "text": "None Provided" + } + }, + "severity": "MEDIUM", + "firstObservedAt": "2026-01-29 22:42:51.149000+01:00", + "lastObservedAt": "2026-03-07 23:40:17.699000+01:00", + "updatedAt": "2026-03-07 23:40:17.699000+01:00", + "status": "ACTIVE", + "resources": [ + { + "type": "AWS_LAMBDA_FUNCTION", + "id": "arn:aws:lambda:us-west-2:123456789012:function:web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD:$LATEST", + "partition": "aws", + "region": "us-west-2", + "tags": { + "InspectorCodeExclusion": "None", + "InspectorExclusion": "None", + "aws:cloudformation:logical-id": "healthCheck", + "aws:cloudformation:stack-id": "arn:aws:cloudformation:us-west-2:123456789012:stack/web-user-manager-api-stage/a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "aws:cloudformation:stack-name": "web-user-manager-api-stage", + "deployed_at": "2026-02-18T12:38:52Z", + "deployed_by": "user1@example.com", + "env": "stage", + "environment": "stage", + "gitlab_ci_job": "1234567", + "lambda:createdBy": "SAM", + "owner_email": "user1@example.com", + "project": "web-user-manager-api", + "service": "web-user-manager-api", + "team": "backend-team-web-user-manager" + }, + "details": { + "awsLambdaFunction": { + "functionName": "web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD", + "runtime": "PYTHON_3_12", + "codeSha256": "abc123def456ghi789jkl012mno345pqr678stu901vw==", + "version": "$LATEST", + "executionRoleArn": "arn:aws:iam::123456789012:role/web-user-manager-api-stage-LambdaExecutionRole-EXAMPLE12345", + "layers": [ + "arn:aws:lambda:us-west-2:123456789012:layer:web-user-manager-api-stage:12", + "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + ], + "vpcConfig": { + "subnetIds": [ + "subnet-03709ee21c427acf6", + "subnet-0b6f7a6987b5e689d", + "subnet-0123c6fff46639b68" + ], + "securityGroupIds": [ + "sg-0fd8fe5dae2694a95" + ], + "vpcId": "vpc-055aa15ae33f4297b" + }, + "packageType": "ZIP", + "architectures": [ + "X86_64" + ], + "lastModifiedAt": "2026-02-18 13:40:35.830000+01:00" + } + } + } + ], + "inspectorScore": 5.3, + "inspectorScoreDetails": { + "adjustedCvss": { + "scoreSource": "NVD", + "cvssSource": "NVD", + "version": "3.1", + "score": 5.3, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N", + "adjustments": [] + } + }, + "packageVulnerabilityDetails": { + "vulnerabilityId": "CVE-2025-61730", + "vulnerablePackages": [ + { + "name": "go/stdlib", + "version": "1.24.4", + "epoch": 0, + "packageManager": "GENERIC", + "filePath": "extensions/collector", + "fixedInVersion": "1.25.6", + "sourceLambdaLayerArn": "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + } + ], + "source": "NVD", + "cvss": [ + { + "baseScore": 5.3, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N", + "version": "3.1", + "source": "NVD" + } + ], + "relatedVulnerabilities": [], + "sourceUrl": "https://nvd.nist.gov/vuln/detail/CVE-2025-61730", + "vendorSeverity": "MEDIUM", + "vendorCreatedAt": "2026-01-28 21:16:09+01:00", + "vendorUpdatedAt": "2026-02-03 21:36:41+01:00", + "referenceUrls": [ + "https://nvd.nist.gov/vuln/detail/CVE-2025-61730", + "https://groups.google.com/g/golang-announce/c/Vd2tYVM8eUc" + ] + }, + "fixAvailable": "YES", + "exploitAvailable": "NO", + "epss": { + "score": 7e-05 + } + }, + { + "findingArn": "arn:aws:inspector2:us-west-2:123456789012:finding/00000000000000000000000000000008", + "awsAccountId": "123456789012", + "type": "PACKAGE_VULNERABILITY", + "description": "Validating certificate chains which contain DSA public keys can cause programs to panic, due to a interface cast that assumes they implement the Equal method. This affects programs which validate arbitrary certificate chains.", + "title": "CVE-2025-58188 - go/stdlib", + "remediation": { + "recommendation": { + "text": "None Provided" + } + }, + "severity": "HIGH", + "firstObservedAt": "2025-12-26 14:21:44.743000+01:00", + "lastObservedAt": "2026-03-13 22:38:57.161000+01:00", + "updatedAt": "2026-03-13 22:38:57.161000+01:00", + "status": "ACTIVE", + "resources": [ + { + "type": "AWS_LAMBDA_FUNCTION", + "id": "arn:aws:lambda:us-west-2:123456789012:function:web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD:$LATEST", + "partition": "aws", + "region": "us-west-2", + "tags": { + "InspectorCodeExclusion": "None", + "InspectorExclusion": "None", + "aws:cloudformation:logical-id": "healthCheck", + "aws:cloudformation:stack-id": "arn:aws:cloudformation:us-west-2:123456789012:stack/web-user-manager-api-stage/a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "aws:cloudformation:stack-name": "web-user-manager-api-stage", + "deployed_at": "2026-02-18T12:38:52Z", + "deployed_by": "user1@example.com", + "env": "stage", + "environment": "stage", + "gitlab_ci_job": "1234567", + "lambda:createdBy": "SAM", + "owner_email": "user1@example.com", + "project": "web-user-manager-api", + "service": "web-user-manager-api", + "team": "backend-team-web-user-manager" + }, + "details": { + "awsLambdaFunction": { + "functionName": "web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD", + "runtime": "PYTHON_3_12", + "codeSha256": "abc123def456ghi789jkl012mno345pqr678stu901vw==", + "version": "$LATEST", + "executionRoleArn": "arn:aws:iam::123456789012:role/web-user-manager-api-stage-LambdaExecutionRole-EXAMPLE12345", + "layers": [ + "arn:aws:lambda:us-west-2:123456789012:layer:web-user-manager-api-stage:12", + "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + ], + "vpcConfig": { + "subnetIds": [ + "subnet-03709ee21c427acf6", + "subnet-0b6f7a6987b5e689d", + "subnet-0123c6fff46639b68" + ], + "securityGroupIds": [ + "sg-0fd8fe5dae2694a95" + ], + "vpcId": "vpc-055aa15ae33f4297b" + }, + "packageType": "ZIP", + "architectures": [ + "X86_64" + ], + "lastModifiedAt": "2026-02-18 13:40:35.830000+01:00" + } + } + } + ], + "inspectorScore": 7.5, + "inspectorScoreDetails": { + "adjustedCvss": { + "scoreSource": "NVD", + "cvssSource": "NVD", + "version": "3.1", + "score": 7.5, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "adjustments": [] + } + }, + "packageVulnerabilityDetails": { + "vulnerabilityId": "CVE-2025-58188", + "vulnerablePackages": [ + { + "name": "go/stdlib", + "version": "1.24.4", + "epoch": 0, + "packageManager": "GENERIC", + "filePath": "extensions/collector", + "fixedInVersion": "1.25.2", + "sourceLambdaLayerArn": "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + } + ], + "source": "NVD", + "cvss": [ + { + "baseScore": 7.5, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "version": "3.1", + "source": "NVD" + } + ], + "relatedVulnerabilities": [], + "sourceUrl": "https://nvd.nist.gov/vuln/detail/CVE-2025-58188", + "vendorSeverity": "HIGH", + "vendorCreatedAt": "2025-10-30 00:16:19+01:00", + "vendorUpdatedAt": "2026-01-29 16:55:11+01:00", + "referenceUrls": [ + "https://nvd.nist.gov/vuln/detail/CVE-2025-58188", + "https://groups.google.com/g/golang-announce/c/4Emdl2iQ_bI" + ] + }, + "fixAvailable": "YES", + "exploitAvailable": "NO", + "epss": { + "score": 7e-05 + } + }, + { + "findingArn": "arn:aws:inspector2:us-west-2:123456789012:finding/00000000000000000000000000000009", + "awsAccountId": "123456789012", + "type": "PACKAGE_VULNERABILITY", + "description": "On Unix platforms, when listing the contents of a directory using File.ReadDir or File.Readdir the returned FileInfo could reference a file outside of the Root in which the File was opened. The impact of this escape is limited to reading metadata provided by lstat from arbitrary locations on the filesystem without permitting reading or writing files outside the root.", + "title": "CVE-2026-27139 - go/stdlib", + "remediation": { + "recommendation": { + "text": "None Provided" + } + }, + "severity": "LOW", + "firstObservedAt": "2026-03-07 23:40:17.699000+01:00", + "lastObservedAt": "2026-03-13 22:38:57.160000+01:00", + "updatedAt": "2026-03-13 22:38:57.160000+01:00", + "status": "ACTIVE", + "resources": [ + { + "type": "AWS_LAMBDA_FUNCTION", + "id": "arn:aws:lambda:us-west-2:123456789012:function:web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD:$LATEST", + "partition": "aws", + "region": "us-west-2", + "tags": { + "InspectorCodeExclusion": "None", + "InspectorExclusion": "None", + "aws:cloudformation:logical-id": "healthCheck", + "aws:cloudformation:stack-id": "arn:aws:cloudformation:us-west-2:123456789012:stack/web-user-manager-api-stage/a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "aws:cloudformation:stack-name": "web-user-manager-api-stage", + "deployed_at": "2026-02-18T12:38:52Z", + "deployed_by": "user1@example.com", + "env": "stage", + "environment": "stage", + "gitlab_ci_job": "1234567", + "lambda:createdBy": "SAM", + "owner_email": "user1@example.com", + "project": "web-user-manager-api", + "service": "web-user-manager-api", + "team": "backend-team-web-user-manager" + }, + "details": { + "awsLambdaFunction": { + "functionName": "web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD", + "runtime": "PYTHON_3_12", + "codeSha256": "abc123def456ghi789jkl012mno345pqr678stu901vw==", + "version": "$LATEST", + "executionRoleArn": "arn:aws:iam::123456789012:role/web-user-manager-api-stage-LambdaExecutionRole-EXAMPLE12345", + "layers": [ + "arn:aws:lambda:us-west-2:123456789012:layer:web-user-manager-api-stage:12", + "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + ], + "vpcConfig": { + "subnetIds": [ + "subnet-03709ee21c427acf6", + "subnet-0b6f7a6987b5e689d", + "subnet-0123c6fff46639b68" + ], + "securityGroupIds": [ + "sg-0fd8fe5dae2694a95" + ], + "vpcId": "vpc-055aa15ae33f4297b" + }, + "packageType": "ZIP", + "architectures": [ + "X86_64" + ], + "lastModifiedAt": "2026-02-18 13:40:35.830000+01:00" + } + } + } + ], + "inspectorScore": 2.5, + "inspectorScoreDetails": { + "adjustedCvss": { + "scoreSource": "NVD", + "cvssSource": "NVD", + "version": "3.1", + "score": 2.5, + "scoringVector": "CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:N/A:N", + "adjustments": [] + } + }, + "packageVulnerabilityDetails": { + "vulnerabilityId": "CVE-2026-27139", + "vulnerablePackages": [ + { + "name": "go/stdlib", + "version": "1.24.4", + "epoch": 0, + "packageManager": "GENERIC", + "filePath": "extensions/collector", + "fixedInVersion": "1.26.1", + "sourceLambdaLayerArn": "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + } + ], + "source": "NVD", + "cvss": [ + { + "baseScore": 2.5, + "scoringVector": "CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:N/A:N", + "version": "3.1", + "source": "NVD" + } + ], + "relatedVulnerabilities": [], + "sourceUrl": "https://nvd.nist.gov/vuln/detail/CVE-2026-27139", + "vendorSeverity": "LOW", + "vendorCreatedAt": "2026-03-06 23:16:01+01:00", + "vendorUpdatedAt": "2026-03-09 16:15:57+01:00", + "referenceUrls": [ + "https://groups.google.com/g/golang-announce/c/EdhZqrQ98hk", + "https://nvd.nist.gov/vuln/detail/CVE-2026-27139" + ] + }, + "fixAvailable": "YES", + "exploitAvailable": "NO", + "epss": { + "score": 5e-05 + } + }, + { + "findingArn": "arn:aws:inspector2:us-west-2:123456789012:finding/0000000000000000000000000000000a", + "awsAccountId": "123456789012", + "type": "PACKAGE_VULNERABILITY", + "description": "archive/zip uses a super-linear file name indexing algorithm that is invoked the first time a file in an archive is opened. This can lead to a denial of service when consuming a maliciously constructed ZIP archive.", + "title": "CVE-2025-61728 - go/stdlib", + "remediation": { + "recommendation": { + "text": "None Provided" + } + }, + "severity": "MEDIUM", + "firstObservedAt": "2026-01-29 22:42:51.148000+01:00", + "lastObservedAt": "2026-03-13 22:38:57.159000+01:00", + "updatedAt": "2026-03-13 22:38:57.159000+01:00", + "status": "ACTIVE", + "resources": [ + { + "type": "AWS_LAMBDA_FUNCTION", + "id": "arn:aws:lambda:us-west-2:123456789012:function:web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD:$LATEST", + "partition": "aws", + "region": "us-west-2", + "tags": { + "InspectorCodeExclusion": "None", + "InspectorExclusion": "None", + "aws:cloudformation:logical-id": "healthCheck", + "aws:cloudformation:stack-id": "arn:aws:cloudformation:us-west-2:123456789012:stack/web-user-manager-api-stage/a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "aws:cloudformation:stack-name": "web-user-manager-api-stage", + "deployed_at": "2026-02-18T12:38:52Z", + "deployed_by": "user1@example.com", + "env": "stage", + "environment": "stage", + "gitlab_ci_job": "1234567", + "lambda:createdBy": "SAM", + "owner_email": "user1@example.com", + "project": "web-user-manager-api", + "service": "web-user-manager-api", + "team": "backend-team-web-user-manager" + }, + "details": { + "awsLambdaFunction": { + "functionName": "web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD", + "runtime": "PYTHON_3_12", + "codeSha256": "abc123def456ghi789jkl012mno345pqr678stu901vw==", + "version": "$LATEST", + "executionRoleArn": "arn:aws:iam::123456789012:role/web-user-manager-api-stage-LambdaExecutionRole-EXAMPLE12345", + "layers": [ + "arn:aws:lambda:us-west-2:123456789012:layer:web-user-manager-api-stage:12", + "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + ], + "vpcConfig": { + "subnetIds": [ + "subnet-03709ee21c427acf6", + "subnet-0b6f7a6987b5e689d", + "subnet-0123c6fff46639b68" + ], + "securityGroupIds": [ + "sg-0fd8fe5dae2694a95" + ], + "vpcId": "vpc-055aa15ae33f4297b" + }, + "packageType": "ZIP", + "architectures": [ + "X86_64" + ], + "lastModifiedAt": "2026-02-18 13:40:35.830000+01:00" + } + } + } + ], + "inspectorScore": 6.5, + "inspectorScoreDetails": { + "adjustedCvss": { + "scoreSource": "NVD", + "cvssSource": "NVD", + "version": "3.1", + "score": 6.5, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", + "adjustments": [] + } + }, + "packageVulnerabilityDetails": { + "vulnerabilityId": "CVE-2025-61728", + "vulnerablePackages": [ + { + "name": "go/stdlib", + "version": "1.24.4", + "epoch": 0, + "packageManager": "GENERIC", + "filePath": "extensions/collector", + "fixedInVersion": "1.25.6", + "sourceLambdaLayerArn": "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + } + ], + "source": "NVD", + "cvss": [ + { + "baseScore": 6.5, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", + "version": "3.1", + "source": "NVD" + } + ], + "relatedVulnerabilities": [], + "sourceUrl": "https://nvd.nist.gov/vuln/detail/CVE-2025-61728", + "vendorSeverity": "MEDIUM", + "vendorCreatedAt": "2026-01-28 21:16:09+01:00", + "vendorUpdatedAt": "2026-02-06 19:45:10+01:00", + "referenceUrls": [ + "https://nvd.nist.gov/vuln/detail/CVE-2025-61728", + "https://groups.google.com/g/golang-announce/c/Vd2tYVM8eUc" + ] + }, + "fixAvailable": "YES", + "exploitAvailable": "NO", + "epss": { + "score": 0.00022 + } + }, + { + "findingArn": "arn:aws:inspector2:us-west-2:123456789012:finding/0000000000000000000000000000000b", + "awsAccountId": "123456789012", + "type": "PACKAGE_VULNERABILITY", + "description": "url.Parse insufficiently validated the host/authority component and accepted some invalid URLs.", + "title": "CVE-2026-25679 - go/stdlib", + "remediation": { + "recommendation": { + "text": "None Provided" + } + }, + "severity": "HIGH", + "firstObservedAt": "2026-03-07 23:40:17.699000+01:00", + "lastObservedAt": "2026-03-13 22:38:57.160000+01:00", + "updatedAt": "2026-03-13 22:38:57.160000+01:00", + "status": "ACTIVE", + "resources": [ + { + "type": "AWS_LAMBDA_FUNCTION", + "id": "arn:aws:lambda:us-west-2:123456789012:function:web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD:$LATEST", + "partition": "aws", + "region": "us-west-2", + "tags": { + "InspectorCodeExclusion": "None", + "InspectorExclusion": "None", + "aws:cloudformation:logical-id": "healthCheck", + "aws:cloudformation:stack-id": "arn:aws:cloudformation:us-west-2:123456789012:stack/web-user-manager-api-stage/a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "aws:cloudformation:stack-name": "web-user-manager-api-stage", + "deployed_at": "2026-02-18T12:38:52Z", + "deployed_by": "user1@example.com", + "env": "stage", + "environment": "stage", + "gitlab_ci_job": "1234567", + "lambda:createdBy": "SAM", + "owner_email": "user1@example.com", + "project": "web-user-manager-api", + "service": "web-user-manager-api", + "team": "backend-team-web-user-manager" + }, + "details": { + "awsLambdaFunction": { + "functionName": "web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD", + "runtime": "PYTHON_3_12", + "codeSha256": "abc123def456ghi789jkl012mno345pqr678stu901vw==", + "version": "$LATEST", + "executionRoleArn": "arn:aws:iam::123456789012:role/web-user-manager-api-stage-LambdaExecutionRole-EXAMPLE12345", + "layers": [ + "arn:aws:lambda:us-west-2:123456789012:layer:web-user-manager-api-stage:12", + "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + ], + "vpcConfig": { + "subnetIds": [ + "subnet-03709ee21c427acf6", + "subnet-0b6f7a6987b5e689d", + "subnet-0123c6fff46639b68" + ], + "securityGroupIds": [ + "sg-0fd8fe5dae2694a95" + ], + "vpcId": "vpc-055aa15ae33f4297b" + }, + "packageType": "ZIP", + "architectures": [ + "X86_64" + ], + "lastModifiedAt": "2026-02-18 13:40:35.830000+01:00" + } + } + } + ], + "inspectorScore": 7.5, + "inspectorScoreDetails": { + "adjustedCvss": { + "scoreSource": "NVD", + "cvssSource": "NVD", + "version": "3.1", + "score": 7.5, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "adjustments": [] + } + }, + "packageVulnerabilityDetails": { + "vulnerabilityId": "CVE-2026-25679", + "vulnerablePackages": [ + { + "name": "go/stdlib", + "version": "1.24.4", + "epoch": 0, + "packageManager": "GENERIC", + "filePath": "extensions/collector", + "fixedInVersion": "1.26.1", + "sourceLambdaLayerArn": "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + } + ], + "source": "NVD", + "cvss": [ + { + "baseScore": 7.5, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "version": "3.1", + "source": "NVD" + } + ], + "relatedVulnerabilities": [], + "sourceUrl": "https://nvd.nist.gov/vuln/detail/CVE-2026-25679", + "vendorSeverity": "HIGH", + "vendorCreatedAt": "2026-03-06 23:16:00+01:00", + "vendorUpdatedAt": "2026-03-10 19:18:37+01:00", + "referenceUrls": [ + "https://groups.google.com/g/golang-announce/c/EdhZqrQ98hk", + "https://nvd.nist.gov/vuln/detail/CVE-2026-25679" + ] + }, + "fixAvailable": "YES", + "exploitAvailable": "NO", + "epss": { + "score": 0.00072 + } + }, + { + "findingArn": "arn:aws:inspector2:us-west-2:123456789012:finding/0000000000000000000000000000000c", + "awsAccountId": "123456789012", + "type": "PACKAGE_VULNERABILITY", + "description": "OpenTelemetry-Go is the Go implementation of OpenTelemetry. The OpenTelemetry Go SDK in version v1.20.0-1.39.0 is vulnerable to Path Hijacking (Untrusted Search Paths) on macOS/Darwin systems. The resource detection code in sdk/resource/host_id.go executes the ioreg system command using a search path. An attacker with the ability to locally modify the PATH environment variable can achieve Arbitrary Code Execution (ACE) within the context of the application. A fix was released with v1.40.0.", + "title": "CVE-2026-24051 - go.opentelemetry.io/otel/sdk", + "remediation": { + "recommendation": { + "text": "None Provided" + } + }, + "severity": "HIGH", + "firstObservedAt": "2026-02-20 22:48:50.875000+01:00", + "lastObservedAt": "2026-03-07 23:40:17.764000+01:00", + "updatedAt": "2026-03-07 23:40:17.764000+01:00", + "status": "ACTIVE", + "resources": [ + { + "type": "AWS_LAMBDA_FUNCTION", + "id": "arn:aws:lambda:us-west-2:123456789012:function:web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD:$LATEST", + "partition": "aws", + "region": "us-west-2", + "tags": { + "InspectorCodeExclusion": "None", + "InspectorExclusion": "None", + "aws:cloudformation:logical-id": "healthCheck", + "aws:cloudformation:stack-id": "arn:aws:cloudformation:us-west-2:123456789012:stack/web-user-manager-api-stage/a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "aws:cloudformation:stack-name": "web-user-manager-api-stage", + "deployed_at": "2026-02-18T12:38:52Z", + "deployed_by": "user1@example.com", + "env": "stage", + "environment": "stage", + "gitlab_ci_job": "1234567", + "lambda:createdBy": "SAM", + "owner_email": "user1@example.com", + "project": "web-user-manager-api", + "service": "web-user-manager-api", + "team": "backend-team-web-user-manager" + }, + "details": { + "awsLambdaFunction": { + "functionName": "web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD", + "runtime": "PYTHON_3_12", + "codeSha256": "abc123def456ghi789jkl012mno345pqr678stu901vw==", + "version": "$LATEST", + "executionRoleArn": "arn:aws:iam::123456789012:role/web-user-manager-api-stage-LambdaExecutionRole-EXAMPLE12345", + "layers": [ + "arn:aws:lambda:us-west-2:123456789012:layer:web-user-manager-api-stage:12", + "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + ], + "vpcConfig": { + "subnetIds": [ + "subnet-03709ee21c427acf6", + "subnet-0b6f7a6987b5e689d", + "subnet-0123c6fff46639b68" + ], + "securityGroupIds": [ + "sg-0fd8fe5dae2694a95" + ], + "vpcId": "vpc-055aa15ae33f4297b" + }, + "packageType": "ZIP", + "architectures": [ + "X86_64" + ], + "lastModifiedAt": "2026-02-18 13:40:35.830000+01:00" + } + } + } + ], + "inspectorScore": 7.0, + "inspectorScoreDetails": { + "adjustedCvss": { + "scoreSource": "NVD", + "cvssSource": "NVD", + "version": "3.1", + "score": 7.0, + "scoringVector": "CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H", + "adjustments": [] + } + }, + "packageVulnerabilityDetails": { + "vulnerabilityId": "CVE-2026-24051", + "vulnerablePackages": [ + { + "name": "go.opentelemetry.io/otel/sdk", + "version": "v1.38.0", + "epoch": 0, + "packageManager": "GO", + "filePath": "extensions/collector", + "fixedInVersion": "1.40.0", + "sourceLambdaLayerArn": "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + } + ], + "source": "NVD", + "cvss": [ + { + "baseScore": 7.0, + "scoringVector": "CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H", + "version": "3.1", + "source": "NVD" + } + ], + "relatedVulnerabilities": [], + "sourceUrl": "https://nvd.nist.gov/vuln/detail/CVE-2026-24051", + "vendorSeverity": "HIGH", + "vendorCreatedAt": "2026-02-03 00:16:07+01:00", + "vendorUpdatedAt": "2026-02-27 21:32:10+01:00", + "referenceUrls": [ + "https://github.com/open-telemetry/opentelemetry-go/security/advisories/GHSA-9h8m-3fm2-qjrq", + "https://github.com/open-telemetry/opentelemetry-go/commit/d45961bcda453fcbdb6469c22d6e88a1f9970a53", + "https://nvd.nist.gov/vuln/detail/CVE-2026-24051" + ] + }, + "fixAvailable": "YES", + "exploitAvailable": "NO", + "epss": { + "score": 7e-05 + } + }, + { + "findingArn": "arn:aws:inspector2:us-west-2:123456789012:finding/0000000000000000000000000000000d", + "awsAccountId": "123456789012", + "type": "PACKAGE_VULNERABILITY", + "description": "Despite HTTP headers having a default limit of 1MB, the number of cookies that can be parsed does not have a limit. By sending a lot of very small cookies such as \"a=;\", an attacker can make an HTTP server allocate a large amount of structs, causing large memory consumption.", + "title": "CVE-2025-58186 - go/stdlib", + "remediation": { + "recommendation": { + "text": "None Provided" + } + }, + "severity": "MEDIUM", + "firstObservedAt": "2025-12-26 14:21:44.745000+01:00", + "lastObservedAt": "2026-03-13 22:38:57.161000+01:00", + "updatedAt": "2026-03-13 22:38:57.161000+01:00", + "status": "ACTIVE", + "resources": [ + { + "type": "AWS_LAMBDA_FUNCTION", + "id": "arn:aws:lambda:us-west-2:123456789012:function:web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD:$LATEST", + "partition": "aws", + "region": "us-west-2", + "tags": { + "InspectorCodeExclusion": "None", + "InspectorExclusion": "None", + "aws:cloudformation:logical-id": "healthCheck", + "aws:cloudformation:stack-id": "arn:aws:cloudformation:us-west-2:123456789012:stack/web-user-manager-api-stage/a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "aws:cloudformation:stack-name": "web-user-manager-api-stage", + "deployed_at": "2026-02-18T12:38:52Z", + "deployed_by": "user1@example.com", + "env": "stage", + "environment": "stage", + "gitlab_ci_job": "1234567", + "lambda:createdBy": "SAM", + "owner_email": "user1@example.com", + "project": "web-user-manager-api", + "service": "web-user-manager-api", + "team": "backend-team-web-user-manager" + }, + "details": { + "awsLambdaFunction": { + "functionName": "web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD", + "runtime": "PYTHON_3_12", + "codeSha256": "abc123def456ghi789jkl012mno345pqr678stu901vw==", + "version": "$LATEST", + "executionRoleArn": "arn:aws:iam::123456789012:role/web-user-manager-api-stage-LambdaExecutionRole-EXAMPLE12345", + "layers": [ + "arn:aws:lambda:us-west-2:123456789012:layer:web-user-manager-api-stage:12", + "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + ], + "vpcConfig": { + "subnetIds": [ + "subnet-03709ee21c427acf6", + "subnet-0b6f7a6987b5e689d", + "subnet-0123c6fff46639b68" + ], + "securityGroupIds": [ + "sg-0fd8fe5dae2694a95" + ], + "vpcId": "vpc-055aa15ae33f4297b" + }, + "packageType": "ZIP", + "architectures": [ + "X86_64" + ], + "lastModifiedAt": "2026-02-18 13:40:35.830000+01:00" + } + } + } + ], + "inspectorScore": 5.3, + "inspectorScoreDetails": { + "adjustedCvss": { + "scoreSource": "NVD", + "cvssSource": "NVD", + "version": "3.1", + "score": 5.3, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L", + "adjustments": [] + } + }, + "packageVulnerabilityDetails": { + "vulnerabilityId": "CVE-2025-58186", + "vulnerablePackages": [ + { + "name": "go/stdlib", + "version": "1.24.4", + "epoch": 0, + "packageManager": "GENERIC", + "filePath": "extensions/collector", + "fixedInVersion": "1.25.2", + "sourceLambdaLayerArn": "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + } + ], + "source": "NVD", + "cvss": [ + { + "baseScore": 5.3, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L", + "version": "3.1", + "source": "NVD" + } + ], + "relatedVulnerabilities": [], + "sourceUrl": "https://nvd.nist.gov/vuln/detail/CVE-2025-58186", + "vendorSeverity": "MEDIUM", + "vendorCreatedAt": "2025-10-30 00:16:19+01:00", + "vendorUpdatedAt": "2025-11-04 23:16:33+01:00", + "referenceUrls": [ + "https://nvd.nist.gov/vuln/detail/CVE-2025-58186", + "https://groups.google.com/g/golang-announce/c/4Emdl2iQ_bI" + ] + }, + "fixAvailable": "YES", + "exploitAvailable": "NO", + "epss": { + "score": 0.00029 + } + }, + { + "findingArn": "arn:aws:inspector2:us-west-2:123456789012:finding/0000000000000000000000000000000e", + "awsAccountId": "123456789012", + "type": "PACKAGE_VULNERABILITY", + "description": "Parsing a maliciously crafted DER payload could allocate large amounts of memory, causing memory exhaustion.", + "title": "CVE-2025-58185 - go/stdlib", + "remediation": { + "recommendation": { + "text": "None Provided" + } + }, + "severity": "MEDIUM", + "firstObservedAt": "2025-12-26 14:21:44.743000+01:00", + "lastObservedAt": "2026-03-13 22:38:57.161000+01:00", + "updatedAt": "2026-03-13 22:38:57.161000+01:00", + "status": "ACTIVE", + "resources": [ + { + "type": "AWS_LAMBDA_FUNCTION", + "id": "arn:aws:lambda:us-west-2:123456789012:function:web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD:$LATEST", + "partition": "aws", + "region": "us-west-2", + "tags": { + "InspectorCodeExclusion": "None", + "InspectorExclusion": "None", + "aws:cloudformation:logical-id": "healthCheck", + "aws:cloudformation:stack-id": "arn:aws:cloudformation:us-west-2:123456789012:stack/web-user-manager-api-stage/a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "aws:cloudformation:stack-name": "web-user-manager-api-stage", + "deployed_at": "2026-02-18T12:38:52Z", + "deployed_by": "user1@example.com", + "env": "stage", + "environment": "stage", + "gitlab_ci_job": "1234567", + "lambda:createdBy": "SAM", + "owner_email": "user1@example.com", + "project": "web-user-manager-api", + "service": "web-user-manager-api", + "team": "backend-team-web-user-manager" + }, + "details": { + "awsLambdaFunction": { + "functionName": "web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD", + "runtime": "PYTHON_3_12", + "codeSha256": "abc123def456ghi789jkl012mno345pqr678stu901vw==", + "version": "$LATEST", + "executionRoleArn": "arn:aws:iam::123456789012:role/web-user-manager-api-stage-LambdaExecutionRole-EXAMPLE12345", + "layers": [ + "arn:aws:lambda:us-west-2:123456789012:layer:web-user-manager-api-stage:12", + "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + ], + "vpcConfig": { + "subnetIds": [ + "subnet-03709ee21c427acf6", + "subnet-0b6f7a6987b5e689d", + "subnet-0123c6fff46639b68" + ], + "securityGroupIds": [ + "sg-0fd8fe5dae2694a95" + ], + "vpcId": "vpc-055aa15ae33f4297b" + }, + "packageType": "ZIP", + "architectures": [ + "X86_64" + ], + "lastModifiedAt": "2026-02-18 13:40:35.830000+01:00" + } + } + } + ], + "inspectorScore": 5.3, + "inspectorScoreDetails": { + "adjustedCvss": { + "scoreSource": "NVD", + "cvssSource": "NVD", + "version": "3.1", + "score": 5.3, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L", + "adjustments": [] + } + }, + "packageVulnerabilityDetails": { + "vulnerabilityId": "CVE-2025-58185", + "vulnerablePackages": [ + { + "name": "go/stdlib", + "version": "1.24.4", + "epoch": 0, + "packageManager": "GENERIC", + "filePath": "extensions/collector", + "fixedInVersion": "1.25.2", + "sourceLambdaLayerArn": "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + } + ], + "source": "NVD", + "cvss": [ + { + "baseScore": 5.3, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L", + "version": "3.1", + "source": "NVD" + } + ], + "relatedVulnerabilities": [], + "sourceUrl": "https://nvd.nist.gov/vuln/detail/CVE-2025-58185", + "vendorSeverity": "MEDIUM", + "vendorCreatedAt": "2025-10-30 00:16:19+01:00", + "vendorUpdatedAt": "2026-02-06 21:26:41+01:00", + "referenceUrls": [ + "https://nvd.nist.gov/vuln/detail/CVE-2025-58185", + "https://groups.google.com/g/golang-announce/c/4Emdl2iQ_bI" + ] + }, + "fixAvailable": "YES", + "exploitAvailable": "NO", + "epss": { + "score": 0.00024 + } + }, + { + "findingArn": "arn:aws:inspector2:us-west-2:123456789012:finding/0000000000000000000000000000000f", + "awsAccountId": "123456789012", + "type": "PACKAGE_VULNERABILITY", + "description": "Actions which insert URLs into the content attribute of HTML meta tags are not escaped. This can allow XSS if the meta tag also has an http-equiv attribute with the value \"refresh\". A new GODEBUG setting has been added, htmlmetacontenturlescape, which can be used to disable escaping URLs in actions in the meta content attribute which follow \"url=\" by setting htmlmetacontenturlescape=0.", + "title": "CVE-2026-27142 - go/stdlib", + "remediation": { + "recommendation": { + "text": "None Provided" + } + }, + "severity": "HIGH", + "firstObservedAt": "2026-03-07 23:40:17.699000+01:00", + "lastObservedAt": "2026-03-13 22:38:57.161000+01:00", + "updatedAt": "2026-03-13 22:38:57.161000+01:00", + "status": "ACTIVE", + "resources": [ + { + "type": "AWS_LAMBDA_FUNCTION", + "id": "arn:aws:lambda:us-west-2:123456789012:function:web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD:$LATEST", + "partition": "aws", + "region": "us-west-2", + "tags": { + "InspectorCodeExclusion": "None", + "InspectorExclusion": "None", + "aws:cloudformation:logical-id": "healthCheck", + "aws:cloudformation:stack-id": "arn:aws:cloudformation:us-west-2:123456789012:stack/web-user-manager-api-stage/a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "aws:cloudformation:stack-name": "web-user-manager-api-stage", + "deployed_at": "2026-02-18T12:38:52Z", + "deployed_by": "user1@example.com", + "env": "stage", + "environment": "stage", + "gitlab_ci_job": "1234567", + "lambda:createdBy": "SAM", + "owner_email": "user1@example.com", + "project": "web-user-manager-api", + "service": "web-user-manager-api", + "team": "backend-team-web-user-manager" + }, + "details": { + "awsLambdaFunction": { + "functionName": "web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD", + "runtime": "PYTHON_3_12", + "codeSha256": "abc123def456ghi789jkl012mno345pqr678stu901vw==", + "version": "$LATEST", + "executionRoleArn": "arn:aws:iam::123456789012:role/web-user-manager-api-stage-LambdaExecutionRole-EXAMPLE12345", + "layers": [ + "arn:aws:lambda:us-west-2:123456789012:layer:web-user-manager-api-stage:12", + "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + ], + "vpcConfig": { + "subnetIds": [ + "subnet-03709ee21c427acf6", + "subnet-0b6f7a6987b5e689d", + "subnet-0123c6fff46639b68" + ], + "securityGroupIds": [ + "sg-0fd8fe5dae2694a95" + ], + "vpcId": "vpc-055aa15ae33f4297b" + }, + "packageType": "ZIP", + "architectures": [ + "X86_64" + ], + "lastModifiedAt": "2026-02-18 13:40:35.830000+01:00" + } + } + } + ], + "inspectorScore": 7.5, + "inspectorScoreDetails": { + "adjustedCvss": { + "scoreSource": "NVD", + "cvssSource": "NVD", + "version": "3.1", + "score": 7.5, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "adjustments": [] + } + }, + "packageVulnerabilityDetails": { + "vulnerabilityId": "CVE-2026-27142", + "vulnerablePackages": [ + { + "name": "go/stdlib", + "version": "1.24.4", + "epoch": 0, + "packageManager": "GENERIC", + "filePath": "extensions/collector", + "fixedInVersion": "1.26.1", + "sourceLambdaLayerArn": "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + } + ], + "source": "NVD", + "cvss": [ + { + "baseScore": 7.5, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "version": "3.1", + "source": "NVD" + } + ], + "relatedVulnerabilities": [], + "sourceUrl": "https://nvd.nist.gov/vuln/detail/CVE-2026-27142", + "vendorSeverity": "HIGH", + "vendorCreatedAt": "2026-03-06 23:16:01+01:00", + "vendorUpdatedAt": "2026-03-10 19:18:44+01:00", + "referenceUrls": [ + "https://groups.google.com/g/golang-announce/c/EdhZqrQ98hk", + "https://nvd.nist.gov/vuln/detail/CVE-2026-27142" + ] + }, + "fixAvailable": "YES", + "exploitAvailable": "NO", + "epss": { + "score": 0.00061 + } + }, + { + "findingArn": "arn:aws:inspector2:us-west-2:123456789012:finding/00000000000000000000000000000010", + "awsAccountId": "123456789012", + "type": "PACKAGE_VULNERABILITY", + "description": "During session resumption in crypto/tls, if the underlying Config has its ClientCAs or RootCAs fields mutated between the initial handshake and the resumed handshake, the resumed handshake may succeed when it should have failed. This may happen when a user calls Config.Clone and mutates the returned Config, or uses Config.GetConfigForClient. This can cause a client to resume a session with a server that it would not have resumed with during the initial handshake, or cause a server to resume a session with a client that it would not have resumed with during the initial handshake.", + "title": "CVE-2025-68121 - go/stdlib", + "remediation": { + "recommendation": { + "text": "None Provided" + } + }, + "severity": "CRITICAL", + "firstObservedAt": "2026-02-06 23:49:39.109000+01:00", + "lastObservedAt": "2026-03-13 22:38:57.160000+01:00", + "updatedAt": "2026-03-13 22:38:57.160000+01:00", + "status": "ACTIVE", + "resources": [ + { + "type": "AWS_LAMBDA_FUNCTION", + "id": "arn:aws:lambda:us-west-2:123456789012:function:web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD:$LATEST", + "partition": "aws", + "region": "us-west-2", + "tags": { + "InspectorCodeExclusion": "None", + "InspectorExclusion": "None", + "aws:cloudformation:logical-id": "healthCheck", + "aws:cloudformation:stack-id": "arn:aws:cloudformation:us-west-2:123456789012:stack/web-user-manager-api-stage/a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "aws:cloudformation:stack-name": "web-user-manager-api-stage", + "deployed_at": "2026-02-18T12:38:52Z", + "deployed_by": "user1@example.com", + "env": "stage", + "environment": "stage", + "gitlab_ci_job": "1234567", + "lambda:createdBy": "SAM", + "owner_email": "user1@example.com", + "project": "web-user-manager-api", + "service": "web-user-manager-api", + "team": "backend-team-web-user-manager" + }, + "details": { + "awsLambdaFunction": { + "functionName": "web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD", + "runtime": "PYTHON_3_12", + "codeSha256": "abc123def456ghi789jkl012mno345pqr678stu901vw==", + "version": "$LATEST", + "executionRoleArn": "arn:aws:iam::123456789012:role/web-user-manager-api-stage-LambdaExecutionRole-EXAMPLE12345", + "layers": [ + "arn:aws:lambda:us-west-2:123456789012:layer:web-user-manager-api-stage:12", + "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + ], + "vpcConfig": { + "subnetIds": [ + "subnet-03709ee21c427acf6", + "subnet-0b6f7a6987b5e689d", + "subnet-0123c6fff46639b68" + ], + "securityGroupIds": [ + "sg-0fd8fe5dae2694a95" + ], + "vpcId": "vpc-055aa15ae33f4297b" + }, + "packageType": "ZIP", + "architectures": [ + "X86_64" + ], + "lastModifiedAt": "2026-02-18 13:40:35.830000+01:00" + } + } + } + ], + "inspectorScore": 10.0, + "inspectorScoreDetails": { + "adjustedCvss": { + "scoreSource": "NVD", + "cvssSource": "NVD", + "version": "3.1", + "score": 10.0, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H", + "adjustments": [] + } + }, + "packageVulnerabilityDetails": { + "vulnerabilityId": "CVE-2025-68121", + "vulnerablePackages": [ + { + "name": "go/stdlib", + "version": "1.24.4", + "epoch": 0, + "packageManager": "GENERIC", + "filePath": "extensions/collector", + "fixedInVersion": "1.26.0-rc.3", + "sourceLambdaLayerArn": "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + } + ], + "source": "NVD", + "cvss": [ + { + "baseScore": 10.0, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H", + "version": "3.1", + "source": "NVD" + } + ], + "relatedVulnerabilities": [], + "sourceUrl": "https://nvd.nist.gov/vuln/detail/CVE-2025-68121", + "vendorSeverity": "CRITICAL", + "vendorCreatedAt": "2026-02-05 19:16:10+01:00", + "vendorUpdatedAt": "2026-02-20 18:25:50+01:00", + "referenceUrls": [ + "https://nvd.nist.gov/vuln/detail/CVE-2025-68121", + "https://groups.google.com/g/golang-announce/c/K09ubi9FQFk" + ] + }, + "fixAvailable": "YES", + "exploitAvailable": "NO", + "epss": { + "score": 0.0001 + } + }, + { + "findingArn": "arn:aws:inspector2:us-west-2:123456789012:finding/00000000000000000000000000000011", + "awsAccountId": "123456789012", + "type": "PACKAGE_VULNERABILITY", + "description": "Black is the uncompromising Python code formatter. Prior to 26.3.1, Black writes a cache file, the name of which is computed from various formatting options. The value of the --python-cell-magics option was placed in the filename without sanitization, which allowed an attacker who controls the value of this argument to write cache files to arbitrary file system locations. Fixed in Black 26.3.1.", + "title": "CVE-2026-32274 - black", + "remediation": { + "recommendation": { + "text": "None Provided" + } + }, + "severity": "HIGH", + "firstObservedAt": "2026-03-13 22:38:57.193000+01:00", + "lastObservedAt": "2026-03-13 22:38:57.193000+01:00", + "updatedAt": "2026-03-13 22:38:57.193000+01:00", + "status": "ACTIVE", + "resources": [ + { + "type": "AWS_LAMBDA_FUNCTION", + "id": "arn:aws:lambda:us-west-2:123456789012:function:web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD:$LATEST", + "partition": "aws", + "region": "us-west-2", + "tags": { + "InspectorCodeExclusion": "None", + "InspectorExclusion": "None", + "aws:cloudformation:logical-id": "healthCheck", + "aws:cloudformation:stack-id": "arn:aws:cloudformation:us-west-2:123456789012:stack/web-user-manager-api-stage/a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "aws:cloudformation:stack-name": "web-user-manager-api-stage", + "deployed_at": "2026-02-18T12:38:52Z", + "deployed_by": "user1@example.com", + "env": "stage", + "environment": "stage", + "gitlab_ci_job": "1234567", + "lambda:createdBy": "SAM", + "owner_email": "user1@example.com", + "project": "web-user-manager-api", + "service": "web-user-manager-api", + "team": "backend-team-web-user-manager" + }, + "details": { + "awsLambdaFunction": { + "functionName": "web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD", + "runtime": "PYTHON_3_12", + "codeSha256": "abc123def456ghi789jkl012mno345pqr678stu901vw==", + "version": "$LATEST", + "executionRoleArn": "arn:aws:iam::123456789012:role/web-user-manager-api-stage-LambdaExecutionRole-EXAMPLE12345", + "layers": [ + "arn:aws:lambda:us-west-2:123456789012:layer:web-user-manager-api-stage:12", + "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + ], + "vpcConfig": { + "subnetIds": [ + "subnet-03709ee21c427acf6", + "subnet-0b6f7a6987b5e689d", + "subnet-0123c6fff46639b68" + ], + "securityGroupIds": [ + "sg-0fd8fe5dae2694a95" + ], + "vpcId": "vpc-055aa15ae33f4297b" + }, + "packageType": "ZIP", + "architectures": [ + "X86_64" + ], + "lastModifiedAt": "2026-02-18 13:40:35.830000+01:00" + } + } + } + ], + "packageVulnerabilityDetails": { + "vulnerabilityId": "CVE-2026-32274", + "vulnerablePackages": [ + { + "name": "black", + "version": "24.10.0", + "epoch": 0, + "packageManager": "PYTHON", + "filePath": "requirements-dev.txt", + "fixedInVersion": "26.3.1" + } + ], + "source": "NVD", + "cvss": [ + { + "baseScore": 8.7, + "scoringVector": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X", + "version": "4.0", + "source": "NVD" + } + ], + "relatedVulnerabilities": [], + "sourceUrl": "https://nvd.nist.gov/vuln/detail/CVE-2026-32274", + "vendorSeverity": "HIGH", + "vendorCreatedAt": "2026-03-12 21:16:06+01:00", + "vendorUpdatedAt": "2026-03-12 22:07:53+01:00", + "referenceUrls": [ + "https://github.com/psf/black/releases/tag/26.3.1", + "https://github.com/psf/black/security/advisories/GHSA-3936-cmfr-pm3m", + "https://nvd.nist.gov/vuln/detail/CVE-2026-32274", + "https://github.com/psf/black/commit/4937fe6cf241139ddbfc16b0bdbb5b422798909d", + "https://github.com/psf/black/pull/5038" + ] + }, + "fixAvailable": "YES", + "exploitAvailable": "YES", + "exploitabilityDetails": { + "lastKnownExploitAt": "2026-03-12 22:34:42+01:00" + } + }, + { + "findingArn": "arn:aws:inspector2:us-west-2:123456789012:finding/00000000000000000000000000000012", + "awsAccountId": "123456789012", + "type": "PACKAGE_VULNERABILITY", + "description": "If the PATH environment variable contains paths which are executables (rather than just directories), passing certain strings to LookPath (\"\", \".\", and \"..\"), can result in the binaries listed in the PATH being unexpectedly returned.", + "title": "CVE-2025-47906 - go/stdlib", + "remediation": { + "recommendation": { + "text": "None Provided" + } + }, + "severity": "MEDIUM", + "firstObservedAt": "2025-12-26 14:21:44.744000+01:00", + "lastObservedAt": "2026-03-07 23:40:17.699000+01:00", + "updatedAt": "2026-03-07 23:40:17.699000+01:00", + "status": "ACTIVE", + "resources": [ + { + "type": "AWS_LAMBDA_FUNCTION", + "id": "arn:aws:lambda:us-west-2:123456789012:function:web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD:$LATEST", + "partition": "aws", + "region": "us-west-2", + "tags": { + "InspectorCodeExclusion": "None", + "InspectorExclusion": "None", + "aws:cloudformation:logical-id": "healthCheck", + "aws:cloudformation:stack-id": "arn:aws:cloudformation:us-west-2:123456789012:stack/web-user-manager-api-stage/a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "aws:cloudformation:stack-name": "web-user-manager-api-stage", + "deployed_at": "2026-02-18T12:38:52Z", + "deployed_by": "user1@example.com", + "env": "stage", + "environment": "stage", + "gitlab_ci_job": "1234567", + "lambda:createdBy": "SAM", + "owner_email": "user1@example.com", + "project": "web-user-manager-api", + "service": "web-user-manager-api", + "team": "backend-team-web-user-manager" + }, + "details": { + "awsLambdaFunction": { + "functionName": "web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD", + "runtime": "PYTHON_3_12", + "codeSha256": "abc123def456ghi789jkl012mno345pqr678stu901vw==", + "version": "$LATEST", + "executionRoleArn": "arn:aws:iam::123456789012:role/web-user-manager-api-stage-LambdaExecutionRole-EXAMPLE12345", + "layers": [ + "arn:aws:lambda:us-west-2:123456789012:layer:web-user-manager-api-stage:12", + "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + ], + "vpcConfig": { + "subnetIds": [ + "subnet-03709ee21c427acf6", + "subnet-0b6f7a6987b5e689d", + "subnet-0123c6fff46639b68" + ], + "securityGroupIds": [ + "sg-0fd8fe5dae2694a95" + ], + "vpcId": "vpc-055aa15ae33f4297b" + }, + "packageType": "ZIP", + "architectures": [ + "X86_64" + ], + "lastModifiedAt": "2026-02-18 13:40:35.830000+01:00" + } + } + } + ], + "inspectorScore": 6.5, + "inspectorScoreDetails": { + "adjustedCvss": { + "scoreSource": "NVD", + "cvssSource": "NVD", + "version": "3.1", + "score": 6.5, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:L", + "adjustments": [] + } + }, + "packageVulnerabilityDetails": { + "vulnerabilityId": "CVE-2025-47906", + "vulnerablePackages": [ + { + "name": "go/stdlib", + "version": "1.24.4", + "epoch": 0, + "packageManager": "GENERIC", + "filePath": "extensions/collector", + "fixedInVersion": "1.24.6", + "sourceLambdaLayerArn": "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + } + ], + "source": "NVD", + "cvss": [ + { + "baseScore": 6.5, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:L", + "version": "3.1", + "source": "NVD" + } + ], + "relatedVulnerabilities": [], + "sourceUrl": "https://nvd.nist.gov/vuln/detail/CVE-2025-47906", + "vendorSeverity": "MEDIUM", + "vendorCreatedAt": "2025-09-18 21:15:37+02:00", + "vendorUpdatedAt": "2026-01-27 20:56:17+01:00", + "referenceUrls": [ + "https://groups.google.com/g/golang-announce/c/x5MKroML2yM", + "https://nvd.nist.gov/vuln/detail/CVE-2025-47906" + ] + }, + "fixAvailable": "YES", + "exploitAvailable": "NO", + "epss": { + "score": 0.00028 + } + }, + { + "findingArn": "arn:aws:inspector2:us-west-2:123456789012:finding/00000000000000000000000000000013", + "awsAccountId": "123456789012", + "type": "CODE_VULNERABILITY", + "description": "User-provided inputs must be sanitized before they are logged. An attacker can use unsanitized input to break a log's integrity, forge log entries, or bypass log monitors.", + "title": "CWE-117,93 - Log injection", + "remediation": { + "recommendation": { + "text": "You have a log statement that might use unsanitized input originating from HTTP requests or AWS Lambda sources. Depending on the context, this could result in:\n\n1. A log injection attack that breaks log integrity, forges log entries, or bypasses monitors that use the logs. To increase the security of your code, sanitize your inputs before logging them. [Learn more](https://cwe.mitre.org/data/definitions/117.html)\n\n2. A sensitive information leak that exposes users' credentials, private information, or identifying information to an attacker. To preserve privacy in your code, redact sensitive user information before logging it. [Learn more](https://cwe.mitre.org/data/definitions/532.html)" + } + }, + "severity": "HIGH", + "firstObservedAt": "2026-02-18 12:01:00.079000+01:00", + "lastObservedAt": "2026-02-18 13:41:11.095000+01:00", + "updatedAt": "2026-02-18 13:41:11.095000+01:00", + "status": "ACTIVE", + "resources": [ + { + "type": "AWS_LAMBDA_FUNCTION", + "id": "arn:aws:lambda:us-west-2:123456789012:function:web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD:$LATEST", + "partition": "aws", + "region": "us-west-2", + "tags": { + "InspectorCodeExclusion": "None", + "InspectorExclusion": "None", + "aws:cloudformation:logical-id": "healthCheck", + "aws:cloudformation:stack-id": "arn:aws:cloudformation:us-west-2:123456789012:stack/web-user-manager-api-stage/a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "aws:cloudformation:stack-name": "web-user-manager-api-stage", + "deployed_at": "2026-02-18T12:38:52Z", + "deployed_by": "user1@example.com", + "env": "stage", + "environment": "stage", + "gitlab_ci_job": "1234567", + "lambda:createdBy": "SAM", + "owner_email": "user1@example.com", + "project": "web-user-manager-api", + "service": "web-user-manager-api", + "team": "backend-team-web-user-manager" + }, + "details": { + "awsLambdaFunction": { + "functionName": "web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD", + "runtime": "PYTHON_3_12", + "codeSha256": "abc123def456ghi789jkl012mno345pqr678stu901vw==", + "version": "$LATEST", + "executionRoleArn": "arn:aws:iam::123456789012:role/web-user-manager-api-stage-LambdaExecutionRole-EXAMPLE12345", + "layers": [ + "arn:aws:lambda:us-west-2:123456789012:layer:web-user-manager-api-stage:12", + "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + ], + "vpcConfig": { + "subnetIds": [ + "subnet-03709ee21c427acf6", + "subnet-0b6f7a6987b5e689d", + "subnet-0123c6fff46639b68" + ], + "securityGroupIds": [ + "sg-0fd8fe5dae2694a95" + ], + "vpcId": "vpc-055aa15ae33f4297b" + }, + "packageType": "ZIP", + "architectures": [ + "X86_64" + ], + "lastModifiedAt": "2026-02-18 13:40:35.830000+01:00" + } + } + } + ], + "codeVulnerabilityDetails": { + "filePath": { + "fileName": "api_client.py", + "filePath": "src/project_api/service/api_client.py", + "startLine": 268, + "endLine": 268 + }, + "detectorTags": [ + "data-integrity", + "injection", + "security", + "owasp-top10" + ], + "referenceUrls": [], + "ruleId": "python-log-injection", + "detectorId": "python/log-injection@v1.0", + "detectorName": "Log injection", + "cwes": [ + "CWE-117", + "CWE-93" + ] + } + }, + { + "findingArn": "arn:aws:inspector2:us-west-2:123456789012:finding/00000000000000000000000000000014", + "awsAccountId": "123456789012", + "type": "PACKAGE_VULNERABILITY", + "description": "cryptography is a package designed to expose cryptographic primitives and recipes to Python developers. Prior to 46.0.5, the public_key_from_numbers (or EllipticCurvePublicNumbers.public_key()), EllipticCurvePublicNumbers.public_key(), load_der_public_key() and load_pem_public_key() functions do not verify that the point belongs to the expected prime-order subgroup of the curve. This missing validation allows an attacker to provide a public key point P from a small-order subgroup. This can lead to security issues in various situations, such as the most commonly used signature verification (ECDSA) and shared key negotiation (ECDH). When the victim computes the shared secret as S = [victim_private_key]P via ECDH, this leaks information about victim_private_key mod (small_subgroup_order). For curves with cofactor > 1, this reveals the least significant bits of the private key. When these weak public keys are used in ECDSA , it's easy to forge signatures on the small subgroup. Only SECT curves are impacted by thi", + "title": "CVE-2026-26007 - cryptography", + "remediation": { + "recommendation": { + "text": "None Provided" + } + }, + "severity": "MEDIUM", + "firstObservedAt": "2026-02-11 22:36:39.094000+01:00", + "lastObservedAt": "2026-03-13 22:38:57.193000+01:00", + "updatedAt": "2026-03-13 22:38:57.193000+01:00", + "status": "ACTIVE", + "resources": [ + { + "type": "AWS_LAMBDA_FUNCTION", + "id": "arn:aws:lambda:us-west-2:123456789012:function:web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD:$LATEST", + "partition": "aws", + "region": "us-west-2", + "tags": { + "InspectorCodeExclusion": "None", + "InspectorExclusion": "None", + "aws:cloudformation:logical-id": "healthCheck", + "aws:cloudformation:stack-id": "arn:aws:cloudformation:us-west-2:123456789012:stack/web-user-manager-api-stage/a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "aws:cloudformation:stack-name": "web-user-manager-api-stage", + "deployed_at": "2026-02-18T12:38:52Z", + "deployed_by": "user1@example.com", + "env": "stage", + "environment": "stage", + "gitlab_ci_job": "1234567", + "lambda:createdBy": "SAM", + "owner_email": "user1@example.com", + "project": "web-user-manager-api", + "service": "web-user-manager-api", + "team": "backend-team-web-user-manager" + }, + "details": { + "awsLambdaFunction": { + "functionName": "web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD", + "runtime": "PYTHON_3_12", + "codeSha256": "abc123def456ghi789jkl012mno345pqr678stu901vw==", + "version": "$LATEST", + "executionRoleArn": "arn:aws:iam::123456789012:role/web-user-manager-api-stage-LambdaExecutionRole-EXAMPLE12345", + "layers": [ + "arn:aws:lambda:us-west-2:123456789012:layer:web-user-manager-api-stage:12", + "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + ], + "vpcConfig": { + "subnetIds": [ + "subnet-03709ee21c427acf6", + "subnet-0b6f7a6987b5e689d", + "subnet-0123c6fff46639b68" + ], + "securityGroupIds": [ + "sg-0fd8fe5dae2694a95" + ], + "vpcId": "vpc-055aa15ae33f4297b" + }, + "packageType": "ZIP", + "architectures": [ + "X86_64" + ], + "lastModifiedAt": "2026-02-18 13:40:35.830000+01:00" + } + } + } + ], + "inspectorScore": 6.5, + "inspectorScoreDetails": { + "adjustedCvss": { + "scoreSource": "NVD", + "cvssSource": "NVD", + "version": "3.1", + "score": 6.5, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N", + "adjustments": [] + } + }, + "packageVulnerabilityDetails": { + "vulnerabilityId": "CVE-2026-26007", + "vulnerablePackages": [ + { + "name": "cryptography", + "version": "43.0.1", + "epoch": 0, + "packageManager": "PYTHON", + "filePath": "requirements.txt", + "fixedInVersion": "46.0.5" + }, + { + "name": "cryptography", + "version": "43.0.1", + "epoch": 0, + "packageManager": "PYTHON", + "filePath": "python/cryptography-43.0.1.dist-info/METADATA", + "fixedInVersion": "46.0.5", + "sourceLambdaLayerArn": "arn:aws:lambda:us-west-2:123456789012:layer:web-user-manager-api-stage:12" + } + ], + "source": "NVD", + "cvss": [ + { + "baseScore": 6.5, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N", + "version": "3.1", + "source": "NVD" + }, + { + "baseScore": 8.2, + "scoringVector": "CVSS:4.0/AV:N/AC:H/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X", + "version": "4.0", + "source": "NVD" + } + ], + "relatedVulnerabilities": [], + "sourceUrl": "https://nvd.nist.gov/vuln/detail/CVE-2026-26007", + "vendorSeverity": "MEDIUM", + "vendorCreatedAt": "2026-02-10 23:17:00+01:00", + "vendorUpdatedAt": "2026-02-23 16:40:33+01:00", + "referenceUrls": [ + "https://github.com/pyca/cryptography/commit/0eebb9dbb6343d9bc1d91e5a2482ed4e054a6d8c", + "https://github.com/pyca/cryptography/security/advisories/GHSA-r6ph-v2qm-q3c2", + "https://nvd.nist.gov/vuln/detail/CVE-2026-26007" + ] + }, + "fixAvailable": "YES", + "exploitAvailable": "NO", + "epss": { + "score": 7e-05 + } + }, + { + "findingArn": "arn:aws:inspector2:us-west-2:123456789012:finding/00000000000000000000000000000015", + "awsAccountId": "123456789012", + "type": "PACKAGE_VULNERABILITY", + "description": "Issue summary: Clients using RFC7250 Raw Public Keys (RPKs) to authenticate a server may fail to notice that the server was not authenticated, because handshakes don't abort as expected when the SSL_VERIFY_PEER verification mode is set.\n\nImpact summary: TLS and DTLS connections using raw public keys may be vulnerable to man-in-middle attacks when server authentication failure is not detected by clients.\n\nRPKs are disabled by default in both TLS clients and TLS servers. The issue only arises when TLS clients explicitly enable RPK use by the server, and the server, likewise, enables sending of an RPK instead of an X.509 certificate chain. The affected clients are those that then rely on the handshake to fail when the server's RPK fails to match one of the expected public keys, by setting the verification mode to SSL_VERIFY_PEER.\n\nClients that enable server-side raw public keys can still find out that raw public key verification failed by calling SSL_get_verify_result(), and those that do, and take appropriate a", + "title": "CVE-2024-12797 - cryptography", + "remediation": { + "recommendation": { + "text": "None Provided" + } + }, + "severity": "MEDIUM", + "firstObservedAt": "2025-02-12 21:55:49.747000+01:00", + "lastObservedAt": "2026-03-13 22:38:57.193000+01:00", + "updatedAt": "2026-03-13 22:38:57.193000+01:00", + "status": "ACTIVE", + "resources": [ + { + "type": "AWS_LAMBDA_FUNCTION", + "id": "arn:aws:lambda:us-west-2:123456789012:function:web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD:$LATEST", + "partition": "aws", + "region": "us-west-2", + "tags": { + "InspectorCodeExclusion": "None", + "InspectorExclusion": "None", + "aws:cloudformation:logical-id": "healthCheck", + "aws:cloudformation:stack-id": "arn:aws:cloudformation:us-west-2:123456789012:stack/web-user-manager-api-stage/a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "aws:cloudformation:stack-name": "web-user-manager-api-stage", + "deployed_at": "2026-02-18T12:38:52Z", + "deployed_by": "user1@example.com", + "env": "stage", + "environment": "stage", + "gitlab_ci_job": "1234567", + "lambda:createdBy": "SAM", + "owner_email": "user1@example.com", + "project": "web-user-manager-api", + "service": "web-user-manager-api", + "team": "backend-team-web-user-manager" + }, + "details": { + "awsLambdaFunction": { + "functionName": "web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD", + "runtime": "PYTHON_3_12", + "codeSha256": "abc123def456ghi789jkl012mno345pqr678stu901vw==", + "version": "$LATEST", + "executionRoleArn": "arn:aws:iam::123456789012:role/web-user-manager-api-stage-LambdaExecutionRole-EXAMPLE12345", + "layers": [ + "arn:aws:lambda:us-west-2:123456789012:layer:web-user-manager-api-stage:12", + "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + ], + "vpcConfig": { + "subnetIds": [ + "subnet-03709ee21c427acf6", + "subnet-0b6f7a6987b5e689d", + "subnet-0123c6fff46639b68" + ], + "securityGroupIds": [ + "sg-0fd8fe5dae2694a95" + ], + "vpcId": "vpc-055aa15ae33f4297b" + }, + "packageType": "ZIP", + "architectures": [ + "X86_64" + ], + "lastModifiedAt": "2026-02-18 13:40:35.830000+01:00" + } + } + } + ], + "inspectorScore": 6.3, + "inspectorScoreDetails": { + "adjustedCvss": { + "scoreSource": "NVD", + "cvssSource": "NVD", + "version": "3.1", + "score": 6.3, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:L", + "adjustments": [] + } + }, + "packageVulnerabilityDetails": { + "vulnerabilityId": "CVE-2024-12797", + "vulnerablePackages": [ + { + "name": "cryptography", + "version": "43.0.1", + "epoch": 0, + "packageManager": "PYTHON", + "filePath": "requirements.txt", + "fixedInVersion": "44.0.1" + }, + { + "name": "cryptography", + "version": "43.0.1", + "epoch": 0, + "packageManager": "PYTHON", + "filePath": "python/cryptography-43.0.1.dist-info/METADATA", + "fixedInVersion": "44.0.1", + "sourceLambdaLayerArn": "arn:aws:lambda:us-west-2:123456789012:layer:web-user-manager-api-stage:12" + } + ], + "source": "NVD", + "cvss": [ + { + "baseScore": 6.3, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:L", + "version": "3.1", + "source": "NVD" + } + ], + "relatedVulnerabilities": [], + "sourceUrl": "https://nvd.nist.gov/vuln/detail/CVE-2024-12797", + "vendorSeverity": "MEDIUM", + "vendorCreatedAt": "2025-02-11 17:15:38+01:00", + "vendorUpdatedAt": "2025-02-18 15:15:27+01:00", + "referenceUrls": [ + "https://github.com/openssl/openssl/commit/798779d43494549b611233f92652f0da5328fbe7", + "https://github.com/openssl/openssl/commit/87ebd203feffcf92ad5889df92f90bb0ee10a699", + "https://nvd.nist.gov/vuln/detail/CVE-2024-12797", + "https://openssl-library.org/news/secadv/20250211.txt", + "https://github.com/openssl/openssl/commit/738d4f9fdeaad57660dcba50a619fafced3fd5e9" + ] + }, + "fixAvailable": "YES", + "exploitAvailable": "NO", + "epss": { + "score": 0.00869 + } + }, + { + "findingArn": "arn:aws:inspector2:us-west-2:123456789012:finding/00000000000000000000000000000016", + "awsAccountId": "123456789012", + "type": "PACKAGE_VULNERABILITY", + "description": "An excluded subdomain constraint in a certificate chain does not restrict the usage of wildcard SANs in the leaf certificate. For example a constraint that excludes the subdomain test.example.com does not prevent a leaf certificate from claiming the SAN *.example.com.", + "title": "CVE-2025-61727 - go/stdlib", + "remediation": { + "recommendation": { + "text": "None Provided" + } + }, + "severity": "MEDIUM", + "firstObservedAt": "2025-12-26 14:21:44.740000+01:00", + "lastObservedAt": "2026-03-07 23:40:17.698000+01:00", + "updatedAt": "2026-03-07 23:40:17.698000+01:00", + "status": "ACTIVE", + "resources": [ + { + "type": "AWS_LAMBDA_FUNCTION", + "id": "arn:aws:lambda:us-west-2:123456789012:function:web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD:$LATEST", + "partition": "aws", + "region": "us-west-2", + "tags": { + "InspectorCodeExclusion": "None", + "InspectorExclusion": "None", + "aws:cloudformation:logical-id": "healthCheck", + "aws:cloudformation:stack-id": "arn:aws:cloudformation:us-west-2:123456789012:stack/web-user-manager-api-stage/a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "aws:cloudformation:stack-name": "web-user-manager-api-stage", + "deployed_at": "2026-02-18T12:38:52Z", + "deployed_by": "user1@example.com", + "env": "stage", + "environment": "stage", + "gitlab_ci_job": "1234567", + "lambda:createdBy": "SAM", + "owner_email": "user1@example.com", + "project": "web-user-manager-api", + "service": "web-user-manager-api", + "team": "backend-team-web-user-manager" + }, + "details": { + "awsLambdaFunction": { + "functionName": "web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD", + "runtime": "PYTHON_3_12", + "codeSha256": "abc123def456ghi789jkl012mno345pqr678stu901vw==", + "version": "$LATEST", + "executionRoleArn": "arn:aws:iam::123456789012:role/web-user-manager-api-stage-LambdaExecutionRole-EXAMPLE12345", + "layers": [ + "arn:aws:lambda:us-west-2:123456789012:layer:web-user-manager-api-stage:12", + "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + ], + "vpcConfig": { + "subnetIds": [ + "subnet-03709ee21c427acf6", + "subnet-0b6f7a6987b5e689d", + "subnet-0123c6fff46639b68" + ], + "securityGroupIds": [ + "sg-0fd8fe5dae2694a95" + ], + "vpcId": "vpc-055aa15ae33f4297b" + }, + "packageType": "ZIP", + "architectures": [ + "X86_64" + ], + "lastModifiedAt": "2026-02-18 13:40:35.830000+01:00" + } + } + } + ], + "inspectorScore": 6.5, + "inspectorScoreDetails": { + "adjustedCvss": { + "scoreSource": "NVD", + "cvssSource": "NVD", + "version": "3.1", + "score": 6.5, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N", + "adjustments": [] + } + }, + "packageVulnerabilityDetails": { + "vulnerabilityId": "CVE-2025-61727", + "vulnerablePackages": [ + { + "name": "go/stdlib", + "version": "1.24.4", + "epoch": 0, + "packageManager": "GENERIC", + "filePath": "extensions/collector", + "fixedInVersion": "1.25.5", + "sourceLambdaLayerArn": "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + } + ], + "source": "NVD", + "cvss": [ + { + "baseScore": 6.5, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N", + "version": "3.1", + "source": "NVD" + } + ], + "relatedVulnerabilities": [], + "sourceUrl": "https://nvd.nist.gov/vuln/detail/CVE-2025-61727", + "vendorSeverity": "MEDIUM", + "vendorCreatedAt": "2025-12-03 21:16:25+01:00", + "vendorUpdatedAt": "2025-12-18 21:15:10+01:00", + "referenceUrls": [ + "https://nvd.nist.gov/vuln/detail/CVE-2025-61727", + "https://groups.google.com/g/golang-announce/c/8FJoBkPddm4" + ] + }, + "fixAvailable": "YES", + "exploitAvailable": "NO", + "epss": { + "score": 0.00011 + } + }, + { + "findingArn": "arn:aws:inspector2:us-west-2:123456789012:finding/00000000000000000000000000000017", + "awsAccountId": "123456789012", + "type": "PACKAGE_VULNERABILITY", + "description": "When Conn.Handshake fails during ALPN negotiation the error contains attacker controlled information (the ALPN protocols sent by the client) which is not escaped.", + "title": "CVE-2025-58189 - go/stdlib", + "remediation": { + "recommendation": { + "text": "None Provided" + } + }, + "severity": "MEDIUM", + "firstObservedAt": "2025-12-26 14:21:44.742000+01:00", + "lastObservedAt": "2026-03-13 22:38:57.161000+01:00", + "updatedAt": "2026-03-13 22:38:57.161000+01:00", + "status": "ACTIVE", + "resources": [ + { + "type": "AWS_LAMBDA_FUNCTION", + "id": "arn:aws:lambda:us-west-2:123456789012:function:web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD:$LATEST", + "partition": "aws", + "region": "us-west-2", + "tags": { + "InspectorCodeExclusion": "None", + "InspectorExclusion": "None", + "aws:cloudformation:logical-id": "healthCheck", + "aws:cloudformation:stack-id": "arn:aws:cloudformation:us-west-2:123456789012:stack/web-user-manager-api-stage/a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "aws:cloudformation:stack-name": "web-user-manager-api-stage", + "deployed_at": "2026-02-18T12:38:52Z", + "deployed_by": "user1@example.com", + "env": "stage", + "environment": "stage", + "gitlab_ci_job": "1234567", + "lambda:createdBy": "SAM", + "owner_email": "user1@example.com", + "project": "web-user-manager-api", + "service": "web-user-manager-api", + "team": "backend-team-web-user-manager" + }, + "details": { + "awsLambdaFunction": { + "functionName": "web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD", + "runtime": "PYTHON_3_12", + "codeSha256": "abc123def456ghi789jkl012mno345pqr678stu901vw==", + "version": "$LATEST", + "executionRoleArn": "arn:aws:iam::123456789012:role/web-user-manager-api-stage-LambdaExecutionRole-EXAMPLE12345", + "layers": [ + "arn:aws:lambda:us-west-2:123456789012:layer:web-user-manager-api-stage:12", + "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + ], + "vpcConfig": { + "subnetIds": [ + "subnet-03709ee21c427acf6", + "subnet-0b6f7a6987b5e689d", + "subnet-0123c6fff46639b68" + ], + "securityGroupIds": [ + "sg-0fd8fe5dae2694a95" + ], + "vpcId": "vpc-055aa15ae33f4297b" + }, + "packageType": "ZIP", + "architectures": [ + "X86_64" + ], + "lastModifiedAt": "2026-02-18 13:40:35.830000+01:00" + } + } + } + ], + "inspectorScore": 5.3, + "inspectorScoreDetails": { + "adjustedCvss": { + "scoreSource": "NVD", + "cvssSource": "NVD", + "version": "3.1", + "score": 5.3, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N", + "adjustments": [] + } + }, + "packageVulnerabilityDetails": { + "vulnerabilityId": "CVE-2025-58189", + "vulnerablePackages": [ + { + "name": "go/stdlib", + "version": "1.24.4", + "epoch": 0, + "packageManager": "GENERIC", + "filePath": "extensions/collector", + "fixedInVersion": "1.25.2", + "sourceLambdaLayerArn": "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + } + ], + "source": "NVD", + "cvss": [ + { + "baseScore": 5.3, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N", + "version": "3.1", + "source": "NVD" + } + ], + "relatedVulnerabilities": [], + "sourceUrl": "https://nvd.nist.gov/vuln/detail/CVE-2025-58189", + "vendorSeverity": "MEDIUM", + "vendorCreatedAt": "2025-10-30 00:16:19+01:00", + "vendorUpdatedAt": "2026-01-29 16:49:24+01:00", + "referenceUrls": [ + "https://groups.google.com/g/golang-announce/c/4Emdl2iQ_bI", + "https://nvd.nist.gov/vuln/detail/CVE-2025-58189" + ] + }, + "fixAvailable": "YES", + "exploitAvailable": "NO", + "epss": { + "score": 9e-05 + } + }, + { + "findingArn": "arn:aws:inspector2:us-west-2:123456789012:finding/00000000000000000000000000000018", + "awsAccountId": "123456789012", + "type": "PACKAGE_VULNERABILITY", + "description": "The processing time for parsing some invalid inputs scales non-linearly with respect to the size of the input. This affects programs which parse untrusted PEM inputs.", + "title": "CVE-2025-61723 - go/stdlib", + "remediation": { + "recommendation": { + "text": "None Provided" + } + }, + "severity": "HIGH", + "firstObservedAt": "2025-12-26 14:21:44.744000+01:00", + "lastObservedAt": "2026-03-13 22:38:57.161000+01:00", + "updatedAt": "2026-03-13 22:38:57.161000+01:00", + "status": "ACTIVE", + "resources": [ + { + "type": "AWS_LAMBDA_FUNCTION", + "id": "arn:aws:lambda:us-west-2:123456789012:function:web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD:$LATEST", + "partition": "aws", + "region": "us-west-2", + "tags": { + "InspectorCodeExclusion": "None", + "InspectorExclusion": "None", + "aws:cloudformation:logical-id": "healthCheck", + "aws:cloudformation:stack-id": "arn:aws:cloudformation:us-west-2:123456789012:stack/web-user-manager-api-stage/a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "aws:cloudformation:stack-name": "web-user-manager-api-stage", + "deployed_at": "2026-02-18T12:38:52Z", + "deployed_by": "user1@example.com", + "env": "stage", + "environment": "stage", + "gitlab_ci_job": "1234567", + "lambda:createdBy": "SAM", + "owner_email": "user1@example.com", + "project": "web-user-manager-api", + "service": "web-user-manager-api", + "team": "backend-team-web-user-manager" + }, + "details": { + "awsLambdaFunction": { + "functionName": "web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD", + "runtime": "PYTHON_3_12", + "codeSha256": "abc123def456ghi789jkl012mno345pqr678stu901vw==", + "version": "$LATEST", + "executionRoleArn": "arn:aws:iam::123456789012:role/web-user-manager-api-stage-LambdaExecutionRole-EXAMPLE12345", + "layers": [ + "arn:aws:lambda:us-west-2:123456789012:layer:web-user-manager-api-stage:12", + "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + ], + "vpcConfig": { + "subnetIds": [ + "subnet-03709ee21c427acf6", + "subnet-0b6f7a6987b5e689d", + "subnet-0123c6fff46639b68" + ], + "securityGroupIds": [ + "sg-0fd8fe5dae2694a95" + ], + "vpcId": "vpc-055aa15ae33f4297b" + }, + "packageType": "ZIP", + "architectures": [ + "X86_64" + ], + "lastModifiedAt": "2026-02-18 13:40:35.830000+01:00" + } + } + } + ], + "inspectorScore": 7.5, + "inspectorScoreDetails": { + "adjustedCvss": { + "scoreSource": "NVD", + "cvssSource": "NVD", + "version": "3.1", + "score": 7.5, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "adjustments": [] + } + }, + "packageVulnerabilityDetails": { + "vulnerabilityId": "CVE-2025-61723", + "vulnerablePackages": [ + { + "name": "go/stdlib", + "version": "1.24.4", + "epoch": 0, + "packageManager": "GENERIC", + "filePath": "extensions/collector", + "fixedInVersion": "1.25.2", + "sourceLambdaLayerArn": "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + } + ], + "source": "NVD", + "cvss": [ + { + "baseScore": 7.5, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "version": "3.1", + "source": "NVD" + } + ], + "relatedVulnerabilities": [], + "sourceUrl": "https://nvd.nist.gov/vuln/detail/CVE-2025-61723", + "vendorSeverity": "HIGH", + "vendorCreatedAt": "2025-10-30 00:16:19+01:00", + "vendorUpdatedAt": "2026-01-29 16:49:05+01:00", + "referenceUrls": [ + "https://nvd.nist.gov/vuln/detail/CVE-2025-61723", + "https://groups.google.com/g/golang-announce/c/4Emdl2iQ_bI" + ] + }, + "fixAvailable": "YES", + "exploitAvailable": "NO", + "epss": { + "score": 0.00028 + } + }, + { + "findingArn": "arn:aws:inspector2:us-west-2:123456789012:finding/00000000000000000000000000000019", + "awsAccountId": "123456789012", + "type": "PACKAGE_VULNERABILITY", + "description": "The Reader.ReadResponse function constructs a response string through repeated string concatenation of lines. When the number of lines in a response is large, this can cause excessive CPU consumption.", + "title": "CVE-2025-61724 - go/stdlib", + "remediation": { + "recommendation": { + "text": "None Provided" + } + }, + "severity": "MEDIUM", + "firstObservedAt": "2025-12-26 14:21:44.744000+01:00", + "lastObservedAt": "2026-03-13 22:38:57.161000+01:00", + "updatedAt": "2026-03-13 22:38:57.161000+01:00", + "status": "ACTIVE", + "resources": [ + { + "type": "AWS_LAMBDA_FUNCTION", + "id": "arn:aws:lambda:us-west-2:123456789012:function:web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD:$LATEST", + "partition": "aws", + "region": "us-west-2", + "tags": { + "InspectorCodeExclusion": "None", + "InspectorExclusion": "None", + "aws:cloudformation:logical-id": "healthCheck", + "aws:cloudformation:stack-id": "arn:aws:cloudformation:us-west-2:123456789012:stack/web-user-manager-api-stage/a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "aws:cloudformation:stack-name": "web-user-manager-api-stage", + "deployed_at": "2026-02-18T12:38:52Z", + "deployed_by": "user1@example.com", + "env": "stage", + "environment": "stage", + "gitlab_ci_job": "1234567", + "lambda:createdBy": "SAM", + "owner_email": "user1@example.com", + "project": "web-user-manager-api", + "service": "web-user-manager-api", + "team": "backend-team-web-user-manager" + }, + "details": { + "awsLambdaFunction": { + "functionName": "web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD", + "runtime": "PYTHON_3_12", + "codeSha256": "abc123def456ghi789jkl012mno345pqr678stu901vw==", + "version": "$LATEST", + "executionRoleArn": "arn:aws:iam::123456789012:role/web-user-manager-api-stage-LambdaExecutionRole-EXAMPLE12345", + "layers": [ + "arn:aws:lambda:us-west-2:123456789012:layer:web-user-manager-api-stage:12", + "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + ], + "vpcConfig": { + "subnetIds": [ + "subnet-03709ee21c427acf6", + "subnet-0b6f7a6987b5e689d", + "subnet-0123c6fff46639b68" + ], + "securityGroupIds": [ + "sg-0fd8fe5dae2694a95" + ], + "vpcId": "vpc-055aa15ae33f4297b" + }, + "packageType": "ZIP", + "architectures": [ + "X86_64" + ], + "lastModifiedAt": "2026-02-18 13:40:35.830000+01:00" + } + } + } + ], + "inspectorScore": 5.3, + "inspectorScoreDetails": { + "adjustedCvss": { + "scoreSource": "NVD", + "cvssSource": "NVD", + "version": "3.1", + "score": 5.3, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L", + "adjustments": [] + } + }, + "packageVulnerabilityDetails": { + "vulnerabilityId": "CVE-2025-61724", + "vulnerablePackages": [ + { + "name": "go/stdlib", + "version": "1.24.4", + "epoch": 0, + "packageManager": "GENERIC", + "filePath": "extensions/collector", + "fixedInVersion": "1.25.2", + "sourceLambdaLayerArn": "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + } + ], + "source": "NVD", + "cvss": [ + { + "baseScore": 5.3, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L", + "version": "3.1", + "source": "NVD" + } + ], + "relatedVulnerabilities": [], + "sourceUrl": "https://nvd.nist.gov/vuln/detail/CVE-2025-61724", + "vendorSeverity": "MEDIUM", + "vendorCreatedAt": "2025-10-30 00:16:20+01:00", + "vendorUpdatedAt": "2026-01-29 16:30:53+01:00", + "referenceUrls": [ + "https://nvd.nist.gov/vuln/detail/CVE-2025-61724", + "https://groups.google.com/g/golang-announce/c/4Emdl2iQ_bI" + ] + }, + "fixAvailable": "YES", + "exploitAvailable": "NO", + "epss": { + "score": 0.00016 + } + }, + { + "findingArn": "arn:aws:inspector2:us-west-2:123456789012:finding/0000000000000000000000000000001a", + "awsAccountId": "123456789012", + "type": "PACKAGE_VULNERABILITY", + "description": "tar.Reader does not set a maximum size on the number of sparse region data blocks in GNU tar pax 1.0 sparse files. A maliciously-crafted archive containing a large number of sparse regions can cause a Reader to read an unbounded amount of data from the archive into memory. When reading from a compressed source, a small compressed input can result in large allocations.", + "title": "CVE-2025-58183 - go/stdlib", + "remediation": { + "recommendation": { + "text": "None Provided" + } + }, + "severity": "MEDIUM", + "firstObservedAt": "2025-12-26 14:21:44.745000+01:00", + "lastObservedAt": "2026-03-13 22:38:57.161000+01:00", + "updatedAt": "2026-03-13 22:38:57.161000+01:00", + "status": "ACTIVE", + "resources": [ + { + "type": "AWS_LAMBDA_FUNCTION", + "id": "arn:aws:lambda:us-west-2:123456789012:function:web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD:$LATEST", + "partition": "aws", + "region": "us-west-2", + "tags": { + "InspectorCodeExclusion": "None", + "InspectorExclusion": "None", + "aws:cloudformation:logical-id": "healthCheck", + "aws:cloudformation:stack-id": "arn:aws:cloudformation:us-west-2:123456789012:stack/web-user-manager-api-stage/a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "aws:cloudformation:stack-name": "web-user-manager-api-stage", + "deployed_at": "2026-02-18T12:38:52Z", + "deployed_by": "user1@example.com", + "env": "stage", + "environment": "stage", + "gitlab_ci_job": "1234567", + "lambda:createdBy": "SAM", + "owner_email": "user1@example.com", + "project": "web-user-manager-api", + "service": "web-user-manager-api", + "team": "backend-team-web-user-manager" + }, + "details": { + "awsLambdaFunction": { + "functionName": "web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD", + "runtime": "PYTHON_3_12", + "codeSha256": "abc123def456ghi789jkl012mno345pqr678stu901vw==", + "version": "$LATEST", + "executionRoleArn": "arn:aws:iam::123456789012:role/web-user-manager-api-stage-LambdaExecutionRole-EXAMPLE12345", + "layers": [ + "arn:aws:lambda:us-west-2:123456789012:layer:web-user-manager-api-stage:12", + "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + ], + "vpcConfig": { + "subnetIds": [ + "subnet-03709ee21c427acf6", + "subnet-0b6f7a6987b5e689d", + "subnet-0123c6fff46639b68" + ], + "securityGroupIds": [ + "sg-0fd8fe5dae2694a95" + ], + "vpcId": "vpc-055aa15ae33f4297b" + }, + "packageType": "ZIP", + "architectures": [ + "X86_64" + ], + "lastModifiedAt": "2026-02-18 13:40:35.830000+01:00" + } + } + } + ], + "inspectorScore": 4.3, + "inspectorScoreDetails": { + "adjustedCvss": { + "scoreSource": "NVD", + "cvssSource": "NVD", + "version": "3.1", + "score": 4.3, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:L", + "adjustments": [] + } + }, + "packageVulnerabilityDetails": { + "vulnerabilityId": "CVE-2025-58183", + "vulnerablePackages": [ + { + "name": "go/stdlib", + "version": "1.24.4", + "epoch": 0, + "packageManager": "GENERIC", + "filePath": "extensions/collector", + "fixedInVersion": "1.25.2", + "sourceLambdaLayerArn": "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + } + ], + "source": "NVD", + "cvss": [ + { + "baseScore": 4.3, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:L", + "version": "3.1", + "source": "NVD" + } + ], + "relatedVulnerabilities": [], + "sourceUrl": "https://nvd.nist.gov/vuln/detail/CVE-2025-58183", + "vendorSeverity": "MEDIUM", + "vendorCreatedAt": "2025-10-30 00:16:19+01:00", + "vendorUpdatedAt": "2025-11-04 23:16:33+01:00", + "referenceUrls": [ + "https://nvd.nist.gov/vuln/detail/CVE-2025-58183", + "https://groups.google.com/g/golang-announce/c/4Emdl2iQ_bI" + ] + }, + "fixAvailable": "YES", + "exploitAvailable": "NO", + "epss": { + "score": 0.00013 + } + }, + { + "findingArn": "arn:aws:inspector2:us-west-2:123456789012:finding/0000000000000000000000000000001b", + "awsAccountId": "123456789012", + "type": "PACKAGE_VULNERABILITY", + "description": "Cancelling a query (e.g. by cancelling the context passed to one of the query methods) during a call to the Scan method of the returned Rows can result in unexpected results if other queries are being made in parallel. This can result in a race condition that may overwrite the expected results with those of another query, causing the call to Scan to return either unexpected results from the other query or an error.", + "title": "CVE-2025-47907 - go/stdlib", + "remediation": { + "recommendation": { + "text": "None Provided" + } + }, + "severity": "HIGH", + "firstObservedAt": "2025-12-26 14:21:44.743000+01:00", + "lastObservedAt": "2026-03-07 23:40:17.699000+01:00", + "updatedAt": "2026-03-07 23:40:17.699000+01:00", + "status": "ACTIVE", + "resources": [ + { + "type": "AWS_LAMBDA_FUNCTION", + "id": "arn:aws:lambda:us-west-2:123456789012:function:web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD:$LATEST", + "partition": "aws", + "region": "us-west-2", + "tags": { + "InspectorCodeExclusion": "None", + "InspectorExclusion": "None", + "aws:cloudformation:logical-id": "healthCheck", + "aws:cloudformation:stack-id": "arn:aws:cloudformation:us-west-2:123456789012:stack/web-user-manager-api-stage/a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "aws:cloudformation:stack-name": "web-user-manager-api-stage", + "deployed_at": "2026-02-18T12:38:52Z", + "deployed_by": "user1@example.com", + "env": "stage", + "environment": "stage", + "gitlab_ci_job": "1234567", + "lambda:createdBy": "SAM", + "owner_email": "user1@example.com", + "project": "web-user-manager-api", + "service": "web-user-manager-api", + "team": "backend-team-web-user-manager" + }, + "details": { + "awsLambdaFunction": { + "functionName": "web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD", + "runtime": "PYTHON_3_12", + "codeSha256": "abc123def456ghi789jkl012mno345pqr678stu901vw==", + "version": "$LATEST", + "executionRoleArn": "arn:aws:iam::123456789012:role/web-user-manager-api-stage-LambdaExecutionRole-EXAMPLE12345", + "layers": [ + "arn:aws:lambda:us-west-2:123456789012:layer:web-user-manager-api-stage:12", + "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + ], + "vpcConfig": { + "subnetIds": [ + "subnet-03709ee21c427acf6", + "subnet-0b6f7a6987b5e689d", + "subnet-0123c6fff46639b68" + ], + "securityGroupIds": [ + "sg-0fd8fe5dae2694a95" + ], + "vpcId": "vpc-055aa15ae33f4297b" + }, + "packageType": "ZIP", + "architectures": [ + "X86_64" + ], + "lastModifiedAt": "2026-02-18 13:40:35.830000+01:00" + } + } + } + ], + "inspectorScore": 7.0, + "inspectorScoreDetails": { + "adjustedCvss": { + "scoreSource": "NVD", + "cvssSource": "NVD", + "version": "3.1", + "score": 7.0, + "scoringVector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:L/A:L", + "adjustments": [] + } + }, + "packageVulnerabilityDetails": { + "vulnerabilityId": "CVE-2025-47907", + "vulnerablePackages": [ + { + "name": "go/stdlib", + "version": "1.24.4", + "epoch": 0, + "packageManager": "GENERIC", + "filePath": "extensions/collector", + "fixedInVersion": "1.24.6", + "sourceLambdaLayerArn": "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + } + ], + "source": "NVD", + "cvss": [ + { + "baseScore": 7.0, + "scoringVector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:L/A:L", + "version": "3.1", + "source": "NVD" + } + ], + "relatedVulnerabilities": [], + "sourceUrl": "https://nvd.nist.gov/vuln/detail/CVE-2025-47907", + "vendorSeverity": "HIGH", + "vendorCreatedAt": "2025-08-07 18:15:30+02:00", + "vendorUpdatedAt": "2026-01-29 20:11:50+01:00", + "referenceUrls": [ + "https://groups.google.com/g/golang-announce/c/x5MKroML2yM", + "https://nvd.nist.gov/vuln/detail/CVE-2025-47907" + ] + }, + "fixAvailable": "YES", + "exploitAvailable": "NO", + "epss": { + "score": 0.00012 + } + }, + { + "findingArn": "arn:aws:inspector2:us-west-2:123456789012:finding/0000000000000000000000000000001c", + "awsAccountId": "123456789012", + "type": "PACKAGE_VULNERABILITY", + "description": "The ParseAddress function constructs domain-literal address components through repeated string concatenation. When parsing large domain-literal components, this can cause excessive CPU consumption.", + "title": "CVE-2025-61725 - go/stdlib", + "remediation": { + "recommendation": { + "text": "None Provided" + } + }, + "severity": "HIGH", + "firstObservedAt": "2025-12-26 14:21:44.745000+01:00", + "lastObservedAt": "2026-03-13 22:38:57.161000+01:00", + "updatedAt": "2026-03-13 22:38:57.161000+01:00", + "status": "ACTIVE", + "resources": [ + { + "type": "AWS_LAMBDA_FUNCTION", + "id": "arn:aws:lambda:us-west-2:123456789012:function:web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD:$LATEST", + "partition": "aws", + "region": "us-west-2", + "tags": { + "InspectorCodeExclusion": "None", + "InspectorExclusion": "None", + "aws:cloudformation:logical-id": "healthCheck", + "aws:cloudformation:stack-id": "arn:aws:cloudformation:us-west-2:123456789012:stack/web-user-manager-api-stage/a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "aws:cloudformation:stack-name": "web-user-manager-api-stage", + "deployed_at": "2026-02-18T12:38:52Z", + "deployed_by": "user1@example.com", + "env": "stage", + "environment": "stage", + "gitlab_ci_job": "1234567", + "lambda:createdBy": "SAM", + "owner_email": "user1@example.com", + "project": "web-user-manager-api", + "service": "web-user-manager-api", + "team": "backend-team-web-user-manager" + }, + "details": { + "awsLambdaFunction": { + "functionName": "web-user-manager-api-stage-healthCheck-EXAMPLE1ABCD", + "runtime": "PYTHON_3_12", + "codeSha256": "abc123def456ghi789jkl012mno345pqr678stu901vw==", + "version": "$LATEST", + "executionRoleArn": "arn:aws:iam::123456789012:role/web-user-manager-api-stage-LambdaExecutionRole-EXAMPLE12345", + "layers": [ + "arn:aws:lambda:us-west-2:123456789012:layer:web-user-manager-api-stage:12", + "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + ], + "vpcConfig": { + "subnetIds": [ + "subnet-03709ee21c427acf6", + "subnet-0b6f7a6987b5e689d", + "subnet-0123c6fff46639b68" + ], + "securityGroupIds": [ + "sg-0fd8fe5dae2694a95" + ], + "vpcId": "vpc-055aa15ae33f4297b" + }, + "packageType": "ZIP", + "architectures": [ + "X86_64" + ], + "lastModifiedAt": "2026-02-18 13:40:35.830000+01:00" + } + } + } + ], + "inspectorScore": 7.5, + "inspectorScoreDetails": { + "adjustedCvss": { + "scoreSource": "NVD", + "cvssSource": "NVD", + "version": "3.1", + "score": 7.5, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "adjustments": [] + } + }, + "packageVulnerabilityDetails": { + "vulnerabilityId": "CVE-2025-61725", + "vulnerablePackages": [ + { + "name": "go/stdlib", + "version": "1.24.4", + "epoch": 0, + "packageManager": "GENERIC", + "filePath": "extensions/collector", + "fixedInVersion": "1.25.2", + "sourceLambdaLayerArn": "arn:aws:lambda:us-west-2:123456789013:layer:opentelemetry-collector-amd64-0_19_0:1" + } + ], + "source": "NVD", + "cvss": [ + { + "baseScore": 7.5, + "scoringVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "version": "3.1", + "source": "NVD" + } + ], + "relatedVulnerabilities": [], + "sourceUrl": "https://nvd.nist.gov/vuln/detail/CVE-2025-61725", + "vendorSeverity": "HIGH", + "vendorCreatedAt": "2025-10-30 00:16:20+01:00", + "vendorUpdatedAt": "2025-12-09 19:15:56+01:00", + "referenceUrls": [ + "https://nvd.nist.gov/vuln/detail/CVE-2025-61725", + "https://groups.google.com/g/golang-announce/c/4Emdl2iQ_bI" + ] + }, + "fixAvailable": "YES", + "exploitAvailable": "NO", + "epss": { + "score": 0.0003 + } + } + ] +} diff --git a/unittests/tools/test_aws_inspector2_parser.py b/unittests/tools/test_aws_inspector2_parser.py index cc0a9aa7b32..21b1cecf70c 100644 --- a/unittests/tools/test_aws_inspector2_parser.py +++ b/unittests/tools/test_aws_inspector2_parser.py @@ -1,6 +1,7 @@ -from datetime import datetime +from datetime import date, datetime from dateutil.tz import tzoffset +from django.conf import settings from dojo.models import Test from dojo.tools.aws_inspector2.parser import AWSInspector2Parser @@ -26,7 +27,7 @@ def test_aws_inspector2_parser_with_one_vuln_has_one_findings(self): self.assertEqual("CVE-2021-3744 - linux", findings[0].title) self.assertEqual("Medium", findings[0].severity) self.assertEqual("CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H", findings[0].cvssv3) - self.assertIsNone(findings[0].cvssv3_score) # The score will be created by the finding save method + self.assertEqual(5.5, findings[0].cvssv3_score) def test_aws_inspector2_parser_with_many_vuln_has_many_findings(self): with (get_unit_tests_scans_path("aws_inspector2") / "aws_inspector2_many_vul.json").open(encoding="utf-8") as testfile: @@ -39,7 +40,39 @@ def test_aws_inspector2_parser_with_many_vuln_has_many_findings(self): # 2024-06-14T04:03:53.051000+02:00 self.assertEqual(datetime(2024, 6, 14, 4, 3, 53, 51000, tzinfo=tzoffset(None, 7200)), findings[0].mitigated) self.assertEqual("CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H", findings[0].cvssv3) - self.assertIsNone(findings[0].cvssv3_score) # The score will be created by the finding save method + self.assertEqual(5.5, findings[0].cvssv3_score) + + def test_aws_inspector2_package_vuln_metadata_fields(self): + """Verify that packageVulnerabilityDetails metadata fields are populated on findings.""" + with (get_unit_tests_scans_path("aws_inspector2") / "aws_inspector2_package_vuln_metadata.json").open(encoding="utf-8") as testfile: + parser = AWSInspector2Parser() + findings = parser.get_findings(testfile, Test()) + self.assertEqual(28, len(findings)) + # Use the first finding (CVE-2025-58187 - go/stdlib) for field assertions + finding = findings[0] + # component_name and component_version from vulnerablePackages[0] + self.assertEqual("go/stdlib", finding.component_name) + self.assertEqual("1.24.4", finding.component_version) + # file_path from vulnerablePackages[0].filePath + self.assertEqual("extensions/collector", finding.file_path) + # references from referenceUrls joined with newlines + self.assertEqual( + "https://nvd.nist.gov/vuln/detail/CVE-2025-58187\nhttps://groups.google.com/g/golang-announce/c/4Emdl2iQ_bI", + finding.references, + ) + # publish_date parsed from vendorCreatedAt + self.assertEqual(date(2025, 10, 30), finding.publish_date) + # cvssv3_score from packageVulnerabilityDetails.cvss[].baseScore (v3.x entry) + self.assertEqual(7.5, finding.cvssv3_score) + # vulnerability ID still populated + self.assertIn("CVE-2025-58187", finding.unsaved_vulnerability_ids) + # LocationData.dependency populated for package vulnerability findings + if settings.V3_FEATURE_LOCATIONS: + dependency_locations = [loc for loc in finding.unsaved_locations if loc.type == "dependency"] + self.assertEqual(1, len(dependency_locations)) + self.assertEqual("go/stdlib", dependency_locations[0].data["name"]) + self.assertEqual("1.24.4", dependency_locations[0].data["version"]) + self.assertEqual("extensions/collector", dependency_locations[0].data["file_path"]) def test_aws_inspector2_parser_empty_with_error(self): with self.assertRaises(TypeError) as context, \