Library / SDK
aquasecurity/trivy-action avatar
aquasecurity/trivy-action

aquasecurity/trivy-action: running Trivy vulnerability scans inside GitHub Actions

Project brief: Runs Trivy as GitHub action to scan your Docker container image for vulnerabilities.

1,429 stars362 forksShellApache-2.0

At a glance

What is it?
A wrapper action that installs Trivy, runs it against an image, filesystem, repo or IaC directory, and caches the vulnerability databases between workflow runs. It is convenient for teams already on GitHub, and awkward anywhere else.
Who is it for?
Adopt it if your builds already run on GitHub-hosted runners and you want Trivy wired into a workflow with one `uses:` line and a pinned tag such as `aquasecurity/[email protected]`. Do not adopt it if you build on GitLab, Jenkins or Gitea, or if you need a signed or digest-pinned action, since the README shows tag references only.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 42 days ago.
What is it written in?
Mainly Shell, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What trivy-action actually removes from your workflow

Trivy itself is a scanner you install and invoke. This repository is the GitHub Actions packaging of it: a composite action whose job is to get a Trivy binary onto the runner, invoke it with the right arguments, and publish the result. The README describes it as a GitHub Action for Trivy, and that is the whole scope.

The audience is narrow and specific. If your images are built inside a GitHub workflow and you want a vulnerability gate on the pull request that produced them, the action saves you from writing the download, cache and invocation steps yourself. If your CI lives anywhere else, the action has nothing to offer you and you should use the Trivy CLI directly. The repository's primary language is Shell, which is consistent with what a composite action is: a shell entrypoint plus an `action.yaml` input contract.

One thing worth noticing before you commit: the action's own version and the Trivy version it installs are separate numbers. The `version` input selects the Trivy binary, and the Makefile reads that default straight out of `action.yaml` with `yq '.inputs.version.default'`. Bumping the action does not automatically mean you bumped the scanner, unless the default moved with it.

How the action resolves inputs, config and precedence

The mechanism is layered, and the layering is the part most likely to surprise you. The action passes options to Trivy, Trivy reads a config file, and Trivy itself uses Viper for option resolution. The README states the precedence order explicitly: GitHub Action flag, then environment variable, then config file, then default. So an input you set on the `uses:` block wins over anything in `trivy.yaml`, which in turn wins over Trivy's built-in defaults.

Three settings cannot come from the config file and must be supplied through the action: `scan-ref` for `fs` and `repo` scans, `image-ref` for image scans, and `scan-type` to pick the mode. Everything else can live in the checked-in `trivy.yaml`, which the README frames as the preferred direction, with the per-option action inputs kept mainly for backward compatibility.

Caching is the other half of the design. The action caches the vulnerability DB, the Java DB and the checks bundle under `$GITHUB_WORKSPACE/.cache/trivy`, restoring before the scan and saving after. It uses `actions/cache` underneath but exposes fewer knobs. Caching is on by default and the `cache` input turns it off. The README's own reason for leaving it on is rate limiting, not speed, which is a more honest framing than most actions give.

Adding trivy-action to a workflow and reading the first result

The README's first example builds an image and then scans it. The `image-ref` points at the tag you just built, `format: 'table'` prints a human-readable table into the job log, `exit-code: '1'` makes the step fail when findings exist, and `ignore-unfixed: true` drops vulnerabilities with no available fix. That last input is a policy decision, not a cosmetic one: it keeps the gate actionable but hides real risk that nobody can patch yet.

yaml
- name: Run Trivy vulnerability scanner
  uses: aquasecurity/[email protected]
  with:
    image-ref: 'docker.io/my-organization/my-app:${{ github.sha }}'
    format: 'table'
    exit-code: '1'
    ignore-unfixed: true

If you would rather keep policy in a file, the second pattern scans the working tree instead of an image and defers to a checked-in config. Note that `scan-type` and `scan-ref` still have to be set on the action, because the README says they cannot be defined in the config file.

yaml
- name: Run Trivy vulnerability scanner in fs mode
  uses: aquasecurity/[email protected]
  with:
    scan-type: 'fs'
    scan-ref: '.'
    trivy-config: trivy.yaml

The `trivy.yaml` file then carries the rest. The README's example sets `format: json`, `exit-code: 1`, `severity: CRITICAL` and points secrets at a separate config, which shows that the file is not limited to vulnerability scanning settings.

yaml
format: json
exit-code: 1
severity: CRITICAL
secret:
  config: config/trivy/secret.yaml

When the job runs, expect the table or JSON on stdout and a non-zero step result under the `exit-code` rule you chose.

The cache is branch-scoped, and that shapes your workflow layout

This is the constraint that catches people after the first green run. GitHub Actions restricts cache access between branches, and the README points at the upstream documentation for it: a workflow can restore a cache created in the current branch or the default branch, nothing else. A feature branch that has never run a scan starts cold and downloads the databases itself.

The README's suggested workaround is a separate workflow on a cron schedule that populates the cache in the default branch, with a comment warning that this workflow only updates the cache and that scans should be a separate workflow. Scans then set two environment variables to skip the download:

yaml
- name: Run Trivy scanner without downloading DBs
  uses: aquasecurity/[email protected]
  with:
    scan-type: 'image'
    scan-ref: 'myimage'
  env:
    TRIVY_SKIP_DB_UPDATE: true
    TRIVY_SKIP_JAVA_DB_UPDATE: true

That is two workflows to maintain, and the second one is only correct if the first one ran. Skip the update without a fresh cache and you scan against a stale database, which is a quiet failure: the job passes and the report is wrong. The README gives the mechanism but does not document a staleness check, so freshness is on you.

Where trivy-action is the wrong tool

The action is bound to GitHub Actions. The README contains no GitLab CI, Jenkins or Gitea example, and the repository layout (a composite `action.yaml` plus `entrypoint.sh`) is not portable to those systems. If your pipeline runs elsewhere, install the Trivy CLI and call it directly; you lose the cache wiring and gain a scanner you can run locally with the same flags.

Second, the README references the action by mutable tag, `aquasecurity/[email protected]` and older tags in its own examples. Nothing in the README shows a commit SHA or digest pin, and it does not document signature verification of the action itself. For a tool whose whole purpose is supply-chain checking, that is a gap worth naming rather than glossing over. Pinning to a full commit SHA is a workflow change you make on your side, not something the README instructs.

Third, the action is a thin wrapper. It does not triage, deduplicate across runs, or track findings over time. `exit-code: '1'` is a binary gate. Teams that want a baseline and a diff between scans need a separate results store, and the README does not describe one.

Scanning by CLI instead of by action

The real alternative is not another GitHub action; it is running Trivy yourself. Install the binary, run `trivy image` or `trivy fs` in a pipeline step, and you get the same scanner, the same databases and the same config file semantics, minus the action's input layer.

The trade-off is concrete. The action gives you database caching through `actions/cache` with almost no configuration, and it gives you a stable input contract so a workflow file reads as a list of named settings rather than a shell command. The CLI gives you portability across CI systems, the ability to run the identical command on a laptop before pushing, and no dependency on an action's release cadence. The Makefile in this repository is a small illustration of the CLI-first path: it resolves a local Trivy binary, reads the required version from `action.yaml`, and installs that exact version if the local one does not match, so local and CI runs use the same scanner build.

If you already have a container image pipeline outside GitHub, the CLI wins on every axis that matters. If you are on GitHub and want the cache handled for you, the action is the shorter path.

Version pinning, licence and what a bump costs

The repository is Apache-2.0. That is a permissive licence, and it means you can use the action in commercial workflows without a separate agreement. It says nothing about the licence of the Trivy binary the action downloads, which is a different artifact from a different repository; check that separately if your legal review requires it. Nothing here is legal advice.

The upgrade surface has two moving parts. The action has its own tags (`v0.36.0`, `v0.35.0`, `0.35.0` in the recent releases), and the Trivy version is a separate input with a default recorded in `action.yaml`. The Makefile's `bump-trivy` target exists precisely because these drift: it reads `CURRENT_TRIVY_VERSION` from the action file, requires a `NEW_VERSION` environment variable, and rewrites the version string across `README.md` and `action.yaml` with `sed`. That tells you the project treats the pinned Trivy version as a value to be updated deliberately, not a floating latest.

The maintenance cost on your side is the cron workflow if you use cross-branch caching, plus a periodic review of the pinned action tag. The last push to this repository was on 2026-04-22, so the project is not dormant, but you should still pin deliberately rather than tracking `master`.

Editorial conclusion

Adopt it if your builds already run on GitHub-hosted runners and you want Trivy wired into a workflow with one `uses:` line and a pinned tag such as `aquasecurity/[email protected]`. Do not adopt it if you build on GitLab, Jenkins or Gitea, or if you need a signed or digest-pinned action, since the README shows tag references only. Before rolling it out, verify three things in your own repository: that `trivy.yaml` is picked up when you pass `trivy-config`, that your branch layout lets the cache restore (only the current branch and the default branch are readable), and that `exit-code: '1'` fails the job the way your branch protection expects rather than silently passing.

Frequently asked questions

What is the Aqua Security Trivy action?

It is the GitHub Action wrapper for Trivy, published from the aquasecurity/trivy-action repository under Apache-2.0. It installs a Trivy binary through aquasecurity/setup-trivy and runs a scan against an image, filesystem, repo or IaC directory.

What is Trivy used for in this action?

The action uses Trivy to scan container images, filesystems, Git repositories, rootfs directories and Infrastructure as Code, and it can also generate an SBOM. The scan type is selected with the `scan-type` input.

Is Trivy safe to use?

The README describes the action's behaviour and the repository is licensed Apache-2.0, but it says nothing about the project's security history, so safety cannot be judged from it. The README's examples reference the action by tag rather than by commit SHA, and it does not document verification of the action itself.

Is Trivy still compromised?

The README contains no incident report, advisory or remediation note, so it cannot answer this. The repository is not archived and its last push was on 2026-04-22, but that fact alone says nothing about any past compromise.

What is trivy action?

It is a GitHub Action that runs Trivy inside a workflow, with inputs such as `scan-type`, `scan-ref`, `image-ref` and `trivy-config`, plus built-in caching of the Trivy databases. The README documents scanning images, filesystems, repos, rootfs directories and IaC.

What is aquasecurity trivy action?

It is the same action, published under the aquasecurity organization and referenced in workflows as `aquasecurity/trivy-action`. The README's examples pin it to tags such as `aquasecurity/[email protected]`.

Official sources

  1. Official README
  2. Project repository
  3. Release notes
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/aquasecurity-trivy-action.svg)](https://hysenlabs.com/projects/aquasecurity-trivy-action)