From 0e94317d6ad10f7907e5d50482460daf8dfbe199 Mon Sep 17 00:00:00 2001 From: DefectDojo release bot Date: Mon, 3 Jun 2024 20:28:42 +0000 Subject: [PATCH 1/8] Update versions in application files --- components/package.json | 2 +- dojo/__init__.py | 2 +- helm/defectdojo/Chart.yaml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/package.json b/components/package.json index 3496b28c137..688f4f5d52f 100644 --- a/components/package.json +++ b/components/package.json @@ -1,6 +1,6 @@ { "name": "defectdojo", - "version": "2.35.0", + "version": "2.36.0-dev", "license" : "BSD-3-Clause", "private": true, "dependencies": { diff --git a/dojo/__init__.py b/dojo/__init__.py index 8c662903c28..423f4050e5c 100644 --- a/dojo/__init__.py +++ b/dojo/__init__.py @@ -4,6 +4,6 @@ # Django starts so that shared_task will use this app. from .celery import app as celery_app # noqa: F401 -__version__ = '2.35.0' +__version__ = '2.36.0-dev' __url__ = 'https://github.com/DefectDojo/django-DefectDojo' __docs__ = 'https://documentation.defectdojo.com' diff --git a/helm/defectdojo/Chart.yaml b/helm/defectdojo/Chart.yaml index 31b548564ca..435cbde2193 100644 --- a/helm/defectdojo/Chart.yaml +++ b/helm/defectdojo/Chart.yaml @@ -1,8 +1,8 @@ apiVersion: v2 -appVersion: "2.35.0" +appVersion: "2.36.0-dev" description: A Helm chart for Kubernetes to install DefectDojo name: defectdojo -version: 1.6.132 +version: 1.6.133-dev icon: https://www.defectdojo.org/img/favicon.ico maintainers: - name: madchap From d9c6da4040ad5dbe15414499526ca28b30d225ff Mon Sep 17 00:00:00 2001 From: manuelsommer <47991713+manuel-sommer@users.noreply.github.com> Date: Tue, 4 Jun 2024 20:38:19 +0200 Subject: [PATCH 2/8] :bug: fix netsparker issue #10311 (#10312) * :bug: fix netsparker issue #10311 * fix --- dojo/tools/netsparker/parser.py | 6 +- unittests/scans/netsparker/issue_10311.json | 173 ++++++++++++++++++++ unittests/tools/test_netsparker_parser.py | 14 ++ 3 files changed, 190 insertions(+), 3 deletions(-) create mode 100644 unittests/scans/netsparker/issue_10311.json diff --git a/dojo/tools/netsparker/parser.py b/dojo/tools/netsparker/parser.py index 1a61276fda8..e0cbce557cb 100644 --- a/dojo/tools/netsparker/parser.py +++ b/dojo/tools/netsparker/parser.py @@ -51,8 +51,8 @@ def get_findings(self, filename, test): url = item["Url"] impact = html2text.html2text(item.get("Impact", "")) dupe_key = title - request = item["HttpRequest"]["Content"] - response = item["HttpResponse"]["Content"] + request = item["HttpRequest"].get("Content", None) + response = item["HttpResponse"].get("Content", None) finding = Finding( title=title, @@ -89,7 +89,7 @@ def get_findings(self, filename, test): ) if len(cvss_objects) > 0: finding.cvssv3 = cvss_objects[0].clean_vector() - finding.unsaved_req_resp = [{"req": request, "resp": response}] + finding.unsaved_req_resp = [{"req": str(request), "resp": str(response)}] finding.unsaved_endpoints = [Endpoint.from_uri(url)] if dupe_key in dupes: diff --git a/unittests/scans/netsparker/issue_10311.json b/unittests/scans/netsparker/issue_10311.json new file mode 100644 index 00000000000..3157fafb142 --- /dev/null +++ b/unittests/scans/netsparker/issue_10311.json @@ -0,0 +1,173 @@ +{ + "Generated": "03/02/2019 15:50:29 (UTC-06:00)", + "Target": { + "ScanId": "fg49hk5", + "Url": "https://www.sampleweb.org/", + "Initiated": "03/02/2019 15:48:23 (UTC-06:00)", + "Duration": "00:01:20.4322725" + }, + "Vulnerabilities": [ + { + "Url": "https://www.sampleweb.org/", + "Type": "CookieNotMarkedAsSecure", + "Name": "Cookie Not Marked as Secure", + "Severity": "High", + "Certainty": 100, + "Confirmed": true, + "Classification": { + "Owasp": "A6", + "Owasp2017": "A3", + "Wasc": "15", + "Cwe": "614", + "Capec": "102", + "Pci31": "6.5.10", + "Pci32": "6.5.10", + "Hipaa": null + }, + "HttpRequest": { + "Method": "GET", + "Content": "GET / HTTP/1.1\r\nHost: www.sampleweb.org\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\nAccept-Encoding: gzip, deflate\r\nAccept-Language: en-us,en;q=0.5\r\nCache-Control: no-cache\r\nUser-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)\r\nX-Scanner: Netsparker\r\n\r\n", + "Parameters": [ ] + }, + "HttpResponse": { + "StatusCode": 200, + "Duration": 644.6389, + "Content": "HTTP/1.1 200 OK\r\nX-Cache: MISS\r\nX-Timer: S1551563304.277046,VS0,VE20\r\nAge: 0\r\nCache-Control: max-age=600\r\nETag: W/\"5b8fd2e9-6807\"\r\nAccess-Control-Allow-Origin: *\r\nX-Fastly-Request-ID: 0345654a04250c6d1c420d386643c1f6dc7c3c24\r\nX-Served-By: cache-chi21166-CHI\r\nConnection: keep-alive\r\nExpires: Sat, 02 Mar 2019 21:58:24 GMT\r\nAccept-Ranges: bytes\r\nX-Cache-Hits: 0\r\nContent-Length: 5954\r\nX-GitHub-Request-Id: 0820:594C:6A9400:84F805:5C7AFA26\r\nVary: Accept-Encoding\r\nVia: 1.1 varnish\r\nLast-Modified: Wed, 05 Sep 2018 12:58:17 GMT\r\nContent-Type: text/html; charset=utf-8\r\nServer: GitHub.com\r\nDate: Sat, 02 Mar 2019 21:48:24 GMT\r\nContent-Encoding: \r\n\r\n" + }, + "ExtraInformation": [ + { + "Name": "Identified Cookie(s)", + "Value": "cookieconsent_status" + }, + { + "Name": "Cookie Source", + "Value": "JavaScript" + } + ], + "KnownVulnerabilities": [ ], + "Description": "

Netsparker identified a cookie not marked as secure, and transmitted over HTTPS.

This means the cookie could potentially be stolen by an attacker who can successfully intercept and decrypt the traffic, or following a successful man-in-the-middle attack.

", + "Impact": "
This cookie will be transmitted over a HTTP connection, therefore if this cookie is important (such as a session cookie), an attacker might intercept it and hijack a victim's session. If the attacker can carry out a man-in-the-middle attack, he/she can force the victim to make an HTTP request to steal the cookie.
", + "RemedialActions": "
  1. See the remedy for solution.
  2. Mark all cookies used within the application as secure. (If the cookie is not related to authentication or does not carry any personal information, you do not have to mark it as secure.)
", + "ExploitationSkills": "
To exploit this issue, the attacker needs to be able to intercept traffic. This generally requires local access to the web server or to the victim's network. Attackers need to be understand layer 2, have physical access to systems either as waypoints for the traffic, or have locally gained access to to a system between the victim and the web server.
", + "RemedialProcedure": "
Mark all cookies used within the application as secure.
", + "RemedyReferences": "", + "ExternalReferences": "
", + "ProofOfConcept": "" + }, + { + "Url": "https://www.sampleweb.org/", + "Type": "BootstrapjsOutOfDate", + "Name": "Out-of-date Version (Bootstrap)", + "Severity": "Medium", + "Certainty": 90, + "Confirmed": false, + "Classification": { + "Owasp": "A9", + "Owasp2017": "A9", + "Wasc": null, + "Cwe": null, + "Capec": "310", + "Pci31": "6.2", + "Pci32": "6.2", + "Hipaa": null + }, + "HttpRequest": { + "Method": "GET", + "Content": "GET / HTTP/1.1\r\nHost: www.sampleweb.org\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\nAccept-Encoding: gzip, deflate\r\nAccept-Language: en-us,en;q=0.5\r\nCache-Control: no-cache\r\nUser-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)\r\nX-Scanner: Netsparker\r\n\r\n", + "Parameters": [ ] + }, + "HttpResponse": { + "StatusCode": 200, + "Duration": 644.6389, + "Content": "HTTP/1.1 200 OK\r\nX-Cache: MISS\r\nX-Timer: S1551563304.277046,VS0,VE20\r\nAge: 0\r\nCache-Control: max-age=600\r\nETag: W/\"5b8fd2e9-6807\"\r\nAccess-Control-Allow-Origin: *\r\nX-Fastly-Request-ID: 0345654a04250c6d1c420d386643c1f6dc7c3c24\r\nX-Served-By: cache-chi21166-CHI\r\nConnection: keep-alive\r\nExpires: Sat, 02 Mar 2019 21:58:24 GMT\r\nAccept-Ranges: bytes\r\nX-Cache-Hits: 0\r\nContent-Length: 5954\r\nX-GitHub-Request-Id: 0820:594C:6A9400:84F805:5C7AFA26\r\nVary: Accept-Encoding\r\nVia: 1.1 varnish\r\nLast-Modified: Wed, 05 Sep 2018 12:58:17 GMT\r\nContent-Type: text/html; charset=utf-8\r\nServer: GitHub.com\r\nDate: Sat, 02 Mar 2019 21:48:24 GMT\r\nContent-Encoding: \r\n\r\n" + }, + "ExtraInformation": [ + { + "Name": "Identified Version", + "Value": "4.0.0" + }, + { + "Name": "Latest Version", + "Value": "4.3.1" + }, + { + "Name": "Vulnerability Database", + "Value": "Result is based on 3/1/2019 vulnerability database content." + } + ], + "KnownVulnerabilities": [ + { + "Title": "bootstrap.js Cross-Site Scripting (XSS) Vulnerability", + "Severity": "Medium" + }, + { + "Title": "bootstrap.js Cross-Site Scripting (XSS) Vulnerability", + "Severity": "Medium" + }, + { + "Title": "bootstrap.js Cross-Site Scripting (XSS) Vulnerability", + "Severity": "Medium" + }, + { + "Title": "bootstrap.js Cross-Site Scripting (XSS) Vulnerability", + "Severity": "Medium" + } + ], + "Description": "

Netsparker identified that the target web site is using Bootstrap and detected that it is out of date.

", + "Impact": "
Since this is an old version of the software, it may be vulnerable to attacks.
", + "RemedialActions": "", + "ExploitationSkills": "", + "RemedialProcedure": "
\n

Please upgrade your installation of Bootstrap to the latest stable version.

\n
", + "RemedyReferences": "
", + "ExternalReferences": "", + "ProofOfConcept": "" + }, + { + "Url": "https://www.sampleweb.org/", + "Type": "CookieNotMarkedAsHttpOnly", + "Name": "Cookie Not Marked as HttpOnly", + "Severity": "Low", + "Certainty": 100, + "Confirmed": true, + "Classification": { + "Owasp": "A5", + "Owasp2017": "A6", + "Wasc": "15", + "Cwe": "16", + "Capec": "107", + "Pci31": null, + "Pci32": null, + "Hipaa": null + }, + "HttpRequest": { + "Method": "GET", + "Content": "GET / HTTP/1.1\r\nHost: www.sampleweb.org\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\nAccept-Encoding: gzip, deflate\r\nAccept-Language: en-us,en;q=0.5\r\nCache-Control: no-cache\r\nUser-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)\r\nX-Scanner: Netsparker\r\n\r\n", + "Parameters": [ ] + }, + "HttpResponse": { + "StatusCode": 200, + "Duration": 644.6389, + "Content": null + }, + "ExtraInformation": [ + { + "Name": "Identified Cookie(s)", + "Value": "cookieconsent_status" + }, + { + "Name": "Cookie Source", + "Value": "JavaScript" + } + ], + "KnownVulnerabilities": [ ], + "Description": "

Netsparker identified a cookie not marked as HTTPOnly.

HTTPOnly cookies cannot be read by client-side scripts, therefore marking a cookie as HTTPOnly can provide an additional layer of protection against cross-site scripting attacks.

", + "Impact": "
During a cross-site scripting attack, an attacker might easily access cookies and hijack the victim's session.
", + "RemedialActions": "
  1. See the remedy for solution.
  2. Consider marking all of the cookies used by the application as HTTPOnly. (After these changes javascript code will not be able to read cookies.)
", + "ExploitationSkills": "", + "RemedialProcedure": "
Mark the cookie as HTTPOnly. This will be an extra layer of defense against XSS. However this is not a silver bullet and will not protect the system against cross-site scripting attacks. An attacker can use a tool such as XSS Tunnel to bypass HTTPOnly protection.
", + "RemedyReferences": "", + "ExternalReferences": "
", + "ProofOfConcept": "" + } + ] +} \ No newline at end of file diff --git a/unittests/tools/test_netsparker_parser.py b/unittests/tools/test_netsparker_parser.py index cf8b9837b84..c3c3f33604b 100644 --- a/unittests/tools/test_netsparker_parser.py +++ b/unittests/tools/test_netsparker_parser.py @@ -83,3 +83,17 @@ def test_parse_file_issue_9816(self): self.assertEqual("High", finding.severity) self.assertEqual(614, finding.cwe) self.assertEqual("03/02/2019", finding.date.strftime("%d/%m/%Y")) + + def test_parse_file_issue_10311(self): + with open("unittests/scans/netsparker/issue_10311.json") as testfile: + parser = NetsparkerParser() + findings = parser.get_findings(testfile, Test()) + self.assertEqual(3, len(findings)) + for finding in findings: + for endpoint in finding.unsaved_endpoints: + endpoint.clean() + with self.subTest(i=0): + finding = findings[0] + self.assertEqual("High", finding.severity) + self.assertEqual(614, finding.cwe) + self.assertEqual("03/02/2019", finding.date.strftime("%d/%m/%Y")) From aed025262eb05dd9249b42ca6a351ab7f02e1ad7 Mon Sep 17 00:00:00 2001 From: kiblik Date: Thu, 6 Jun 2024 21:49:53 +0200 Subject: [PATCH 3/8] fix(imp-options): Wrong type-checker in validate_api_scan_configuration (#10345) --- dojo/importers/options.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dojo/importers/options.py b/dojo/importers/options.py index ec73488e928..52b291ecaf1 100644 --- a/dojo/importers/options.py +++ b/dojo/importers/options.py @@ -15,9 +15,9 @@ Endpoint, Engagement, Finding, + Product_API_Scan_Configuration, Test, Test_Import, - Tool_Configuration, ) from dojo.utils import get_current_user, is_finding_groups_enabled @@ -45,7 +45,7 @@ def load_base_options( **kwargs: dict, ): self.active: bool = self.validate_active(*args, **kwargs) - self.api_scan_configuration: Tool_Configuration | None = self.validate_api_scan_configuration(*args, **kwargs) + self.api_scan_configuration: Product_API_Scan_Configuration | None = self.validate_api_scan_configuration(*args, **kwargs) self.apply_tags_to_endpoints: bool = self.validate_apply_tags_to_endpoints(*args, **kwargs) self.apply_tags_to_findings: bool = self.validate_apply_tags_to_findings(*args, **kwargs) self.branch_tag: str = self.validate_branch_tag(*args, **kwargs) @@ -227,10 +227,10 @@ def validate_api_scan_configuration( self, *args: list, **kwargs: dict, - ) -> Tool_Configuration | None: + ) -> Product_API_Scan_Configuration | None: return self.validate( "api_scan_configuration", - expected_types=[Tool_Configuration], + expected_types=[Product_API_Scan_Configuration], required=False, default=None, **kwargs, From 2d18d030d9ce3341b9cd23ed745493a4dec55aa6 Mon Sep 17 00:00:00 2001 From: sfowl Date: Fri, 7 Jun 2024 05:50:39 +1000 Subject: [PATCH 4/8] Mark UserProfile properties user_contact_info and global_role as optional (#10314) --- dojo/api_v2/serializers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dojo/api_v2/serializers.py b/dojo/api_v2/serializers.py index 6c9b3ee48f8..51dd30fa0b0 100644 --- a/dojo/api_v2/serializers.py +++ b/dojo/api_v2/serializers.py @@ -3013,8 +3013,8 @@ def validate(self, data): class UserProfileSerializer(serializers.Serializer): user = UserSerializer(many=False) - user_contact_info = UserContactInfoSerializer(many=False) - global_role = GlobalRoleSerializer(many=False) + user_contact_info = UserContactInfoSerializer(many=False, required=False) + global_role = GlobalRoleSerializer(many=False, required=False) dojo_group_member = DojoGroupMemberSerializer(many=True) product_type_member = ProductTypeMemberSerializer(many=True) product_member = ProductMemberSerializer(many=True) From 50d3c8caa8cb2b2dc6095b8f775020d6feaf2b97 Mon Sep 17 00:00:00 2001 From: Cody Maffucci <46459665+Maffooch@users.noreply.github.com> Date: Thu, 6 Jun 2024 15:16:57 -0500 Subject: [PATCH 5/8] String Filtering: Support ID matching for links on listing pages (#10352) --- dojo/filters.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dojo/filters.py b/dojo/filters.py index d7ae4b6fef5..9fa171ea8d1 100644 --- a/dojo/filters.py +++ b/dojo/filters.py @@ -1663,6 +1663,8 @@ def set_date_fields(self, *args: list, **kwargs: dict): class FindingFilterWithoutObjectLookups(FindingFilterHelper, FindingTagStringFilter): + test__engagement__product__prod_type = NumberFilter(widget=HiddenInput()) + test__engagement__product = NumberFilter(widget=HiddenInput()) reporter = CharFilter( field_name="reporter__username", lookup_expr="iexact", @@ -2471,6 +2473,7 @@ class Meta: class EndpointFilterWithoutObjectLookups(EndpointFilterHelper): + product = NumberFilter(widget=HiddenInput()) product__name = CharFilter( field_name="product__name", lookup_expr="iexact", From 2db52c2a41420c94891e05e6edf687ae60a9ca46 Mon Sep 17 00:00:00 2001 From: Cody Maffucci <46459665+Maffooch@users.noreply.github.com> Date: Thu, 6 Jun 2024 15:54:50 -0500 Subject: [PATCH 6/8] Importer: Correct `add_findings_to_auto_group` args (#10351) --- dojo/importers/default_importer.py | 2 +- dojo/importers/default_reimporter.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/dojo/importers/default_importer.py b/dojo/importers/default_importer.py index 70c71ab31e9..5cf38f38a73 100644 --- a/dojo/importers/default_importer.py +++ b/dojo/importers/default_importer.py @@ -215,7 +215,7 @@ def process_findings( group_name, findings, self.group_by, - self.create_finding_groups_for_all_findings, + create_finding_groups_for_all_findings=self.create_finding_groups_for_all_findings, **kwargs ) if self.push_to_jira: diff --git a/dojo/importers/default_reimporter.py b/dojo/importers/default_reimporter.py index 6d24854d64b..e313afbd1d7 100644 --- a/dojo/importers/default_reimporter.py +++ b/dojo/importers/default_reimporter.py @@ -688,6 +688,8 @@ def process_groups_for_all_findings( finding_helper.add_findings_to_auto_group( group_name, findings, + self.group_by, + create_finding_groups_for_all_findings=self.create_finding_groups_for_all_findings, **kwargs ) if self.push_to_jira: From bb1239aa360cd1baeabdf5b91669ae922be361a7 Mon Sep 17 00:00:00 2001 From: Cody Maffucci <46459665+Maffooch@users.noreply.github.com> Date: Thu, 6 Jun 2024 15:55:25 -0500 Subject: [PATCH 7/8] String Filtering: Correct Typo For Reviewers (#10353) --- dojo/filters.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dojo/filters.py b/dojo/filters.py index 9fa171ea8d1..0b12cc3961f 100644 --- a/dojo/filters.py +++ b/dojo/filters.py @@ -1675,13 +1675,13 @@ class FindingFilterWithoutObjectLookups(FindingFilterHelper, FindingTagStringFil lookup_expr="icontains", label="Reporter Username Contains", help_text="Search for Reporter names that contain a given pattern") - reviewer = CharFilter( - field_name="reviewer__username", + reviewers = CharFilter( + field_name="reviewers__username", lookup_expr="iexact", label="Reviewer Username", help_text="Search for Reviewer names that are an exact match") - reviewer_contains = CharFilter( - field_name="reviewer__username", + reviewers_contains = CharFilter( + field_name="reviewers__username", lookup_expr="icontains", label="Reviewer Username Contains", help_text="Search for Reviewer usernames that contain a given pattern") From b1637503f19442872c272b36d5b7df7a470d10ed Mon Sep 17 00:00:00 2001 From: DefectDojo release bot Date: Thu, 6 Jun 2024 20:57:47 +0000 Subject: [PATCH 8/8] Update versions in application files --- components/package.json | 2 +- dojo/__init__.py | 2 +- helm/defectdojo/Chart.yaml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/package.json b/components/package.json index 688f4f5d52f..f36765a9a80 100644 --- a/components/package.json +++ b/components/package.json @@ -1,6 +1,6 @@ { "name": "defectdojo", - "version": "2.36.0-dev", + "version": "2.35.1", "license" : "BSD-3-Clause", "private": true, "dependencies": { diff --git a/dojo/__init__.py b/dojo/__init__.py index 423f4050e5c..523f51fdd80 100644 --- a/dojo/__init__.py +++ b/dojo/__init__.py @@ -4,6 +4,6 @@ # Django starts so that shared_task will use this app. from .celery import app as celery_app # noqa: F401 -__version__ = '2.36.0-dev' +__version__ = '2.35.1' __url__ = 'https://github.com/DefectDojo/django-DefectDojo' __docs__ = 'https://documentation.defectdojo.com' diff --git a/helm/defectdojo/Chart.yaml b/helm/defectdojo/Chart.yaml index 435cbde2193..8403b51cc38 100644 --- a/helm/defectdojo/Chart.yaml +++ b/helm/defectdojo/Chart.yaml @@ -1,8 +1,8 @@ apiVersion: v2 -appVersion: "2.36.0-dev" +appVersion: "2.35.1" description: A Helm chart for Kubernetes to install DefectDojo name: defectdojo -version: 1.6.133-dev +version: 1.6.133 icon: https://www.defectdojo.org/img/favicon.ico maintainers: - name: madchap