Skip to content

Scan Results

Every completed scan produces a detail page at /dashboard/scans/{scanId} and a JSON representation at GET /api/scans/{scanId}. This page documents what is on each tab and how to read it.

The top of the scan page shows:

FieldSource
Image referenceregistry/repo:tag
DigestPinned at scan time so a retag does not reattribute the result
EnginesSubset of trivy, grype, syft, dockle, osv, dive actually run
StatusCOMPLETED, FAILED, or IN_PROGRESS
Origincloud or sensor
DurationEnd-to-end wall time
Compliance gradeA-D (see Grades)
Vulnerability countsCritical / High / Medium / Low / Unknown

Findings tab

The default view. Lists every deduplicated vulnerability and misconfiguration finding.

Each row shows:

  • Severity (CRITICAL, HIGH, MEDIUM, LOW, UNKNOWN)
  • CVE / GHSA / Dockle rule ID
  • Affected package and version
  • Fixed version (when known)
  • sources - the engines that flagged it (["trivy","grype","osv"])
  • Triage state (Open, Acknowledged, In Progress, Fixed, Wont Fix)
  • SLA deadline (when configured)

Bulk-select rows to triage many findings at once. Severity filters and search are in the toolbar.

A finding with sources.length >= 2 has cross-engine corroboration. A single-source finding is still real but worth scrutinizing.

Packages tab

The SBOM produced by Syft. One row per detected package:

ColumnMeaning
NamePackage name
VersionResolved version
Ecosystemapk, deb, rpm, npm, pypi, gem, go-module, maven, ...
LicenseSPDX identifier when detected
LayerThe layer that introduced the package
VulnerabilitiesCount of findings against this package version

Export buttons produce CycloneDX JSON or SPDX JSON of the full SBOM.

Layers tab

Layer-by-layer breakdown produced by Dive. For each layer:

  • Order, command, and size
  • Files added, modified, removed
  • Wasted bytes (files duplicated, deleted-but-still-present)
  • Vulnerabilities attributed to packages introduced in this layer

Useful for finding which RUN line introduced a vulnerable package, or which layer is bloating the image.

Logs tab

Raw stdout/stderr from each scanner process, with timestamps and exit codes. Read this when:

  • A scan finishes FAILED and you want the underlying error.
  • A scanner's count looks wrong - check if it actually ran to completion.
  • You are debugging a private-registry pull failure.

API representation

GET /api/scans/{scanId} returns the full result as JSON:

{
  "data": {
    "id": "scan-lq8a4f2x-9k3p1m",
    "status": "COMPLETED",
    "origin": "cloud",
    "engines": ["trivy", "grype", "syft"],
    "compliance": "B",
    "duration": "47s",
    "image": { "ref": "docker.io/library/nginx:1.25", "digest": "sha256:..." },
    "counts": { "critical": 0, "high": 2, "medium": 14, "low": 31, "unknown": 0 },
    "findings": [ ... ],
    "packages": [ ... ],
    "layers": [ ... ]
  }
}

DELETE /api/scans/{scanId} (admin role) removes the scan and its results. Findings linked to triage decisions in other scans are preserved.

Triage carry-forward

When you re-scan a tag, triage decisions and attestations from the previous scan carry forward to matching findings. A Wont Fix from yesterday stays Wont Fix today. A Fixed finding that reappears is flagged as a regression and fires a notification.

On this page