Trivy’s output formats are less about how Trivy sees the vulnerabilities and more about how it communicates them to other tools and humans.

Let’s see Trivy in action. Imagine you’ve got a container image, my-app:latest, and you want to scan it for vulnerabilities.

First, a basic scan to see what we’re working with.

trivy image my-app:latest

This will spit out a table-like output directly to your terminal. It’s human-readable, great for a quick look. But what if you need to feed this data into a CI/CD pipeline, a security dashboard, or another script? That’s where different output formats come in.

JSON: The Universal Translator

The json format is your workhorse for programmatic consumption. It’s structured, unambiguous, and loved by machines.

trivy image --format json --output results.json my-app:latest

This command scans my-app:latest and writes the vulnerability findings into a file named results.json.

Here’s a snippet of what results.json might look like:

[
  {
    "Target": "my-app:latest (linux/amd64)",
    "Type": "docker-image",
    "Vulnerabilities": [
      {
        "VulnerabilityID": "CVE-2023-1234",
        "PkgName": "openssl",
        "InstalledVersion": "1.1.1k-1ubuntu2.12",
        "FixedVersion": "1.1.1k-1ubuntu2.13",
        "Severity": "HIGH",
        "Title": "openssl: Information disclosure vulnerability",
        "Description": "A flaw was found in openssl. An attacker could ...",
        "References": [
          "https://ubuntu.com/security/CVE-2023-1234"
        ],
        "PrimaryURL": "https://avd.aquasec.com/nvd/CVE-2023-1234",
        "DataSource": {
          "Name": "NVD",
          "URL": "https://avd.aquasec.com/nvd/CVE-2023-1234"
        }
      }
      // ... more vulnerabilities
    ],
    "Risks": [
      {
        "Target": "my-app:latest (linux/amd64)",
        "PkgName": "openssl",
        "InstalledVersion": "1.1.1k-1ubuntu2.12",
        "VulnerabilityIDs": [
          "CVE-2023-1234"
        ]
      }
    ]
  }
  // ... more targets if scanning multiple things
]

The json output provides a complete, hierarchical view of the scan results. Each top-level object represents a scanned target (like an image, filesystem, or git repository). Within each target, you’ll find Type, Vulnerabilities (a list of all found issues), and Risks (a more aggregated view of vulnerabilities per package).

SARIF: The Security Standard

Security teams often standardize on the Security Assertion Markup Language (SAML) format, and Trivy supports it via SARIF. This is particularly useful for integrating with security analysis platforms like GitHub Advanced Security, Azure Security Center, or any tool that consumes SARIF.

trivy image --format sarif --output results.sarif my-app:latest

This command produces a results.sarif file. SARIF is an XML-based format, but Trivy serializes it as JSON for ease of use. The structure is more verbose than plain JSON, designed to carry rich metadata about security findings, including severity, remediation steps, and rule information.

A SARIF output from Trivy will contain a runs array. Each run object describes a single scan execution. Inside run, you’ll find tool, which describes Trivy itself, and results. The results array contains locations (where the issue was found) and codeFlows (if applicable, detailing steps to reproduce or understand the vulnerability).

The key advantage here is interoperability. If your security platform expects SARIF, Trivy can speak its language directly.

Template: Customization is Key

Sometimes, the default formats aren’t quite right. You might need a very specific output for a custom report, a Slack notification, or a particular dashboard. This is where --format template shines.

Trivy uses the Go text/template and html/template packages, allowing you to define your own output structure using a templating language.

Let’s say you only want to see the CVE ID, package name, and severity for high and critical vulnerabilities, formatted as a simple comma-separated list.

First, create a template file, say custom-report.tpl:


{{range .Results}}


  {{range .Vulnerabilities}}


    {{if or (eq .Severity "HIGH") (eq .Severity "CRITICAL")}}


{{.VulnerabilityID}},{{.PkgName}},{{.Severity}}


    {{end}}


  {{end}}


{{end}}

Then, run Trivy with this template:

trivy image --format template --template-config custom-report.tpl --output custom_report.csv my-app:latest

This command will generate custom_report.csv containing lines like:

CVE-2023-1234,openssl,HIGH
CVE-2023-5678,bash,CRITICAL

The template format gives you granular control. You can access almost any field from Trivy’s internal data structures. For example, you can loop through Results, then Vulnerabilities, and conditionally print specific fields like VulnerabilityID, PkgName, InstalledVersion, FixedVersion, Severity, Title, Description, or PrimaryURL. You can even include .Metadata.Image to know which image the findings belong to.

The power of templates lies in their flexibility. You can construct HTML reports, markdown summaries, or even generate configuration files for other tools, all based on Trivy’s scan data.

The most surprising thing about Trivy’s output formats is how much they abstract away the underlying scan process. When you request json or SARIF, you’re not just getting a dump of findings; you’re getting a structured, semantically rich representation designed for machine interpretation and integration. The template format, in particular, allows you to treat Trivy’s findings as a data source that can be reshaped into virtually any desired output, effectively making Trivy a data-generation engine for your security workflows.

Once you’ve mastered these output formats, you’ll likely want to explore Trivy’s configuration options for more advanced filtering and scanning behavior.

Want structured learning?

Take the full Trivy course →