Bug description
Importing a legacy-format Trivy report that has no Class key crashes the import pipeline after parsing succeeds, with:
TypeError: expected string or bytes-like object, got 'NoneType'
The UI shows a generic import error and re-renders the form (scan type reset to default); the API returns HTTP 500. Full traceback under Logs below.
The repro file is the project's own parser fixture: unittests/scans/trivy/legacy_many_vulns.json. Parser unit tests pass because they exercise parsing only — the failure is in the post-parse import path, which the fixture never reaches in CI.
Steps to reproduce
- Fresh
docker compose up -d (2.59.0), log in as admin.
- Create product type → product → interactive engagement.
- Engagement → Import Scan Results → Scan type: Trivy Scan.
- Upload
unittests/scans/trivy/legacy_many_vulns.json from this repo.
- Submit → see error.
Also reproducible via the API (so not UI-specific):
curl -X POST http://localhost:8080/api/v2/import-scan/ \
-H "Authorization: Token <token>" \
-F "engagement=1" -F "scan_type=Trivy Scan" \
-F "file=@unittests/scans/trivy/legacy_many_vulns.json"
# → HTTP 500, identical TypeError in the log
Expected behavior
93 findings imported (the fixture parses to 93 findings, confirmed in the log line below).
Deployment method (select with an X)
Environment information
- Operating System: macOS 15 (Darwin 24.6.0)
- Docker Compose version: v5.1.4
- DefectDojo version: 2.59.0 (pinned
DJANGO_VERSION=2.59.0 / NGINX_VERSION=2.59.0); code path verified unchanged on current dev
Logs
INFO [dojo.importers.base_importer:275] Parsing findings took 0.01 seconds (93 findings parsed)
ERROR [dojo.engagement.views:922] An exception error occurred during the report import
Traceback (most recent call last):
File "/app/dojo/engagement/views.py", line 913, in import_findings
context["test"], _, finding_count, closed_finding_count, _, _, _ = importer_client.process_scan(
File "/app/dojo/importers/default_importer.py", line 119, in process_scan
new_findings = self.process_findings(parsed_findings, **kwargs)
File "/app/dojo/importers/default_importer.py", line 173, in process_findings
return self._process_findings_internal(parsed_findings, **kwargs)
File "/app/dojo/importers/default_importer.py", line 256, in _process_findings_internal
TypeError: expected string or bytes-like object, got 'NoneType'
Sample scan files
unittests/scans/trivy/legacy_many_vulns.json (already in this repo — the Trivy parser's own legacy-format fixture).
Screenshots
N/A — the UI error is a generic banner; the logs above show the failure.
Additional context
Root cause
dojo/tools/trivy/parser.py:247 — target_class = target_data.get("Class") returns None for legacy-format reports (legacy top-level-list reports have Target/Type/Vulnerabilities but no Class).
- Tags are then set without a None-guard at
parser.py lines 347 / 408 / 439 / 473, e.g. finding.unsaved_tags = [vul_type, target_class] → ["os-pkgs", None].
dojo/validators.py:42 (clean_tags) runs TAG_PATTERN.sub("_", tag) on each list element and raises TypeError on the None.
Any parser that emits a None tag will hit the same crash — Trivy legacy is just one trigger. (Related symptom previously seen in #7348, Prowler v3, closed.)
Proposed fix
Defensive filter in clean_tags (fixes the whole class of failures):
if isinstance(value, list):
return [TAG_PATTERN.sub("_", tag) for tag in value if tag is not None]
optionally plus parser-side hygiene in the four Trivy tag assignments:
finding.unsaved_tags = [t for t in (vul_type, target_class) if t]
I have a fix with regression tests ready and will open a PR referencing this issue if the approach sounds right. Verified against a live 2.59.0 instance: with the two files above patched, the same import returns HTTP 201 with all 93 findings (0 Critical / 18 High / 9 Medium / 65 Low / 1 Info), and each finding keeps its real tag (debian) with the None dropped.
Affected versions
Legacy-format imports succeed on ≤ 2.54.x (findings import, tags absent) and crash on ≥ 2.55.0, when finding tag values started flowing through clean_tags during import.
This may also explain #14628 (intermittent 500s on bulk Trivy API imports, closed pending-feedback): the reporter's imports worked on 2.49.3 until February 2026 and began failing intermittently on 2.55.4 — consistent with a mix of legacy- and current-format reports across their ~100 hosts.
Bug description
Importing a legacy-format Trivy report that has no
Classkey crashes the import pipeline after parsing succeeds, with:The UI shows a generic import error and re-renders the form (scan type reset to default); the API returns HTTP 500. Full traceback under Logs below.
The repro file is the project's own parser fixture:
unittests/scans/trivy/legacy_many_vulns.json. Parser unit tests pass because they exercise parsing only — the failure is in the post-parse import path, which the fixture never reaches in CI.Steps to reproduce
docker compose up -d(2.59.0), log in as admin.unittests/scans/trivy/legacy_many_vulns.jsonfrom this repo.Also reproducible via the API (so not UI-specific):
Expected behavior
93 findings imported (the fixture parses to 93 findings, confirmed in the log line below).
Deployment method (select with an
X)Environment information
DJANGO_VERSION=2.59.0/NGINX_VERSION=2.59.0); code path verified unchanged on currentdevLogs
Sample scan files
unittests/scans/trivy/legacy_many_vulns.json(already in this repo — the Trivy parser's own legacy-format fixture).Screenshots
N/A — the UI error is a generic banner; the logs above show the failure.
Additional context
Root cause
dojo/tools/trivy/parser.py:247—target_class = target_data.get("Class")returnsNonefor legacy-format reports (legacy top-level-list reports haveTarget/Type/Vulnerabilitiesbut noClass).parser.pylines 347 / 408 / 439 / 473, e.g.finding.unsaved_tags = [vul_type, target_class]→["os-pkgs", None].dojo/validators.py:42(clean_tags) runsTAG_PATTERN.sub("_", tag)on each list element and raisesTypeErroron theNone.Any parser that emits a
Nonetag will hit the same crash — Trivy legacy is just one trigger. (Related symptom previously seen in #7348, Prowler v3, closed.)Proposed fix
Defensive filter in
clean_tags(fixes the whole class of failures):optionally plus parser-side hygiene in the four Trivy tag assignments:
I have a fix with regression tests ready and will open a PR referencing this issue if the approach sounds right. Verified against a live 2.59.0 instance: with the two files above patched, the same import returns HTTP 201 with all 93 findings (0 Critical / 18 High / 9 Medium / 65 Low / 1 Info), and each finding keeps its real tag (
debian) with theNonedropped.Affected versions
Legacy-format imports succeed on ≤ 2.54.x (findings import, tags absent) and crash on ≥ 2.55.0, when finding tag values started flowing through
clean_tagsduring import.This may also explain #14628 (intermittent 500s on bulk Trivy API imports, closed pending-feedback): the reporter's imports worked on 2.49.3 until February 2026 and began failing intermittently on 2.55.4 — consistent with a mix of legacy- and current-format reports across their ~100 hosts.