Skip to content

Regression in 2.55.0: Trivy legacy-format import crashes with TypeError in clean_tags when report lacks Class field #15005

@stevewallone

Description

@stevewallone

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

  1. Fresh docker compose up -d (2.59.0), log in as admin.
  2. Create product type → product → interactive engagement.
  3. Engagement → Import Scan Results → Scan type: Trivy Scan.
  4. Upload unittests/scans/trivy/legacy_many_vulns.json from this repo.
  5. 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)

  • Docker Compose
  • Kubernetes
  • GoDojo

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

  1. dojo/tools/trivy/parser.py:247target_class = target_data.get("Class") returns None for legacy-format reports (legacy top-level-list reports have Target/Type/Vulnerabilities but no Class).
  2. 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].
  3. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions