From 31b991cf1d4aaef2b550c723012dcc095d925623 Mon Sep 17 00:00:00 2001 From: Greg Anderson Date: Sat, 8 Aug 2026 09:54:30 -0600 Subject: [PATCH 1/2] fix(dedupe): give Checkmarx Scan detailed a hash_code field list "Checkmarx Scan detailed" is registered in DEDUPLICATION_ALGORITHM_PER_PARSER but has no HASHCODE_FIELDS_PER_SCANNER entry, so hash computation falls through to the legacy field set -- which includes `description`. A parser change that reworded a finding therefore moved its stored hash_code, which is exactly the fragility this list exists to prevent. The three fields are the ones "Checkmarx CxFlow SAST" already uses, and for the same reason: the detailed mode of this parser sets vuln_id_from_tool (queryId), file_path (sinkFilename) and line (sinkLineNumber) on every finding it produces, so all three are populated and none of them carries scan text. The algorithm for this scan type is unique_id_from_tool, so this moves the stored hash without changing how candidates are looked up. Deliberately not doing the same for "Checkmarx One Scan", which has the same missing entry. Its parser covers several result families and get_results_sca sets only title (copied from the description) and severity -- no file_path, no cwe, no line, no vuln_id_from_tool. Any declarable field list is therefore either low-entropy for those findings, which is worse than the legacy hash, or text-derived, which does not fix anything. It sets unique_id_from_tool reliably, so a durable identity is available without a configured hash. Verified: dojo.checks.check_configuration_deduplication returns no warnings with the entry in place, so both halves of the registration agree. --- dojo/settings/settings.dist.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/dojo/settings/settings.dist.py b/dojo/settings/settings.dist.py index adcd4b2f2f..bc7febc0a4 100644 --- a/dojo/settings/settings.dist.py +++ b/dojo/settings/settings.dist.py @@ -1081,6 +1081,15 @@ def generate_url(scheme, double_slashes, user, password, host, port, path, param "Burp Scan": ["title", "severity", "vuln_id_from_tool"], "CargoAudit Scan": ["vulnerability_ids", "severity", "component_name", "component_version", "vuln_id_from_tool"], "Checkmarx Scan": ["cwe", "severity", "file_path"], + # Same three fields as "Checkmarx CxFlow SAST" below, and for the same reason: the + # detailed mode of this parser sets vuln_id_from_tool (queryId), file_path (sinkFilename) + # and line (sinkLineNumber) on every finding, so all three are populated and none of them + # carries scan text. Without an entry here the scan type fell through to the legacy field + # set, which includes `description` -- so a parser change that reworded a finding moved its + # hash_code, which is the fragility this list exists to avoid. The algorithm for this scan + # type is unique_id_from_tool, so the change moves the stored hash without changing how + # candidates are looked up. + "Checkmarx Scan detailed": ["vuln_id_from_tool", "file_path", "line"], "Checkmarx OSA": ["vulnerability_ids", "component_name"], "Cloudsploit Scan": ["title", "description"], "Coverity Scan JSON Report": ["title", "cwe", "line", "file_path", "description"], From b86ce674c962afa02c983ed0c11e49b4e5c2673d Mon Sep 17 00:00:00 2001 From: Greg Anderson Date: Sun, 9 Aug 2026 21:19:56 -0600 Subject: [PATCH 2/2] test(dedupe): refresh the Checkmarx Scan detailed fixture hash_codes Findings 124 and 125 belong to test 55 ("Checkmarx Scan detailed"), which now has its own hash_code field list, so their stored hash moves from the legacy value to the one the configured fields produce (vuln_id_from_tool + file_path + line = "None/dev/urandom123"). Findings 22-24 keep the old value: they are Xanitizer Scan and still use the legacy algorithm, which happens to hash to the same digest because the field values are identical. Both the default and the locations variant of the fixture are updated, plus the fixture map in the test module header. Co-Authored-By: Claude Opus 5 --- dojo/fixtures/dojo_testdata.json | 4 ++-- dojo/fixtures/dojo_testdata_locations.json | 4 ++-- unittests/test_deduplication_logic.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dojo/fixtures/dojo_testdata.json b/dojo/fixtures/dojo_testdata.json index 50707a2d2b..444f834983 100644 --- a/dojo/fixtures/dojo_testdata.json +++ b/dojo/fixtures/dojo_testdata.json @@ -1607,7 +1607,7 @@ "url": null, "notes": [], "dynamic_finding": false, - "hash_code": "9aca00affd340c4da02c934e7e3106a45c6ad0911da479daae421b3b28a2c1aa", + "hash_code": "bc912aacda3a8707cbf94b96e6350a5cc77e7ef4a29a1442cb1a041e4e1f38d8", "last_reviewed": null } }, @@ -1655,7 +1655,7 @@ "url": null, "notes": [], "dynamic_finding": false, - "hash_code": "9aca00affd340c4da02c934e7e3106a45c6ad0911da479daae421b3b28a2c1aa", + "hash_code": "bc912aacda3a8707cbf94b96e6350a5cc77e7ef4a29a1442cb1a041e4e1f38d8", "last_reviewed": null } }, diff --git a/dojo/fixtures/dojo_testdata_locations.json b/dojo/fixtures/dojo_testdata_locations.json index 3d4eb06ff9..a83cf20d84 100644 --- a/dojo/fixtures/dojo_testdata_locations.json +++ b/dojo/fixtures/dojo_testdata_locations.json @@ -1632,7 +1632,7 @@ "url": null, "notes": [], "dynamic_finding": false, - "hash_code": "9aca00affd340c4da02c934e7e3106a45c6ad0911da479daae421b3b28a2c1aa", + "hash_code": "bc912aacda3a8707cbf94b96e6350a5cc77e7ef4a29a1442cb1a041e4e1f38d8", "last_reviewed": null } }, @@ -1680,7 +1680,7 @@ "url": null, "notes": [], "dynamic_finding": false, - "hash_code": "9aca00affd340c4da02c934e7e3106a45c6ad0911da479daae421b3b28a2c1aa", + "hash_code": "bc912aacda3a8707cbf94b96e6350a5cc77e7ef4a29a1442cb1a041e4e1f38d8", "last_reviewed": null } }, diff --git a/unittests/test_deduplication_logic.py b/unittests/test_deduplication_logic.py index 85cf912777..caa75f1872 100644 --- a/unittests/test_deduplication_logic.py +++ b/unittests/test_deduplication_logic.py @@ -112,8 +112,8 @@ # engagement 5: April monthly engagement (dedupe_inside: True) # test 55: Checkmarx Scan detailed (algo=unique_id_from_tool, dynamic=False) # findings: -# 124 : "Low Impact Test Find": Low : act: True : ver: True : mit: False: dup: False: dup_id: None: hash_code: 9aca00affd340c4da02c934e7e3106a45c6ad0911da479daae421b3b28a2c1aa: eps: 0: notes: []: uid: 12345 -# 125 : "Low Impact Test Find": Low : act: True : ver: True : mit: False: dup: True : dup_id: None: hash_code: 9aca00affd340c4da02c934e7e3106a45c6ad0911da479daae421b3b28a2c1aa: eps: 0: notes: []: uid: 12345 +# 124 : "Low Impact Test Find": Low : act: True : ver: True : mit: False: dup: False: dup_id: None: hash_code: bc912aacda3a8707cbf94b96e6350a5cc77e7ef4a29a1442cb1a041e4e1f38d8: eps: 0: notes: []: uid: 12345 +# 125 : "Low Impact Test Find": Low : act: True : ver: True : mit: False: dup: True : dup_id: None: hash_code: bc912aacda3a8707cbf94b96e6350a5cc77e7ef4a29a1442cb1a041e4e1f38d8: eps: 0: notes: []: uid: 12345 # endpoints # 2: ftp://localhost/ # 1: http://127.0.0.1/endpoint/420/edit/