Security scanning of your code with Trivy
Security vulnerabilities in your codebase need to be dealt with. Trivy is an open source tool that is straightforward to set up.
Trivy doesn't just scan for known vulnerabilities in your dependencies. It examines Docker images, filesystem content, repository configurations, secrets, and even license compliance.
This blog will help you set up Trivy scanning in GitHub Actions and publish security reports to GitHub Pages, giving you visibility and control over your security posture. These foundations provide a solid base for building your security toolchain.
Other commercial security scanning tools include Snyk, GitHub Advanced Security, GitLab Security Scanning, JFrog Xray, SonarQube, and FOSSA. They are all solid tools, however here we'll focus on Trivy since it is open source and free to use. It offers many of the same capabilities as commercial security scanning tools without licensing costs.
Running locally
First, install Trivy on your system. Then you can run scans against your local repository:
# Scan filesystem for vulnerabilities
trivy fs .
# Scan container images
trivy image your-app:latest
# Check repository for misconfigurations and secrets
trivy repo .
This gives you essential scans: filesystem vulnerabilities, container image analysis, and repository security issues. Run trivy fs .
and you'll immediately see any known vulnerabilities in your dependencies, along with severity ratings and available fixes.
GitHub Actions Integration
Now let's get this into our pipelines. Trivy provides a GitHub Action that is easy to drop into place.
name: Security Scan
on:
push:
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Trivy filesystem scanner
uses: aquasecurity/trivy-action@0.32.0
with:
scan-type: "fs"
scan-ref: "."
format: "table"
- name: Run Trivy image scanner
uses: aquasecurity/trivy-action@0.32.0
with:
image-ref: "your-app:latest"
format: "table"
- name: License compliance scan
uses: aquasecurity/trivy-action@0.32.0
with:
scan-type: "fs"
scan-ref: "."
scanners: "license"
format: "table"
This setup runs on every push. The table
format provides human-readable output
directly in your GitHub Actions logs. For example, the pipeline logs might look like:
Running Trivy with options: trivy image hello-world
2025-08-07T15:35:44Z INFO [vuln] Vulnerability scanning is enabled
2025-08-07T15:35:44Z INFO [secret] Secret scanning is enabled
2025-08-07T15:35:44Z INFO [secret] If your scanning is slow, please try '--scanners vuln' to disable secret scanning
2025-08-07T15:35:44Z INFO [secret] Please see also https://trivy.dev/v0.64/docs/scanner/secret#recommendation for faster secret detection
2025-08-07T15:35:46Z INFO Detected OS family="alpine" version="3.21.2"
2025-08-07T15:35:46Z INFO [alpine] Detecting vulnerabilities... os_version="3.21" repository="3.21" pkg_num=15
2025-08-07T15:35:46Z INFO Number of language-specific files num=0
2025-08-07T15:35:46Z WARN Using severities from other vendors for some vulnerabilities. Read https://trivy.dev/v0.64/docs/scanner/vulnerability#severity-selection for details.
Report Summary
┌─────────────────────────────┬────────┬─────────────────┬─────────┐
│ Target │ Type │ Vulnerabilities │ Secrets │
├─────────────────────────────┼────────┼─────────────────┼─────────┤
│ hello-world (alpine 3.21.2) │ alpine │ 6 │ - │
├─────────────────────────────┼────────┼─────────────────┼─────────┤
│ /bad-secret.txt │ text │ - │ 1 │
└─────────────────────────────┴────────┴─────────────────┴─────────┘
Legend:
- '-': Not scanned
- '0': Clean (no security findings detected)
hello-world (alpine 3.21.2)
===========================
Total: 6 (UNKNOWN: 2, LOW: 0, MEDIUM: 2, HIGH: 2, CRITICAL: 0)
┌────────────┬────────────────┬──────────┬────────┬───────────────────┬───────────────┬─────────────────────────────────────────────────────────────┐
│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │
├────────────┼────────────────┼──────────┼────────┼───────────────────┼───────────────┼───────────────────────────────────��─────────────────────────┤
│ libcrypto3 │ CVE-2024-12797 │ HIGH │ fixed │ 3.3.2-r4 │ 3.3.3-r0 │ openssl: RFC7250 handshakes with unauthenticated servers │
│ │ │ │ │ │ │ don't abort as expected │
│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2024-12797 │
You might want the pipeline to fail if certain security checks fail. For example, fail pipeline on secret violation, using the exit code to halt deployments when secrets are detected:
- name: Scan for secrets (fail on detection)
uses: aquasecurity/trivy-action@0.32.0
with:
scan-type: "fs"
scan-ref: "."
scanners: "secret"
exit-code: 1
format: "table"
This configuration returns exit code 1 if any secrets are detected, causing CI/CD pipelines to fail and preventing deployment of compromised code.
Generate HTML reports
You can generate JSON reports that can be processed by other tools or integrated into dashboards:
# Create output directory
mkdir -p out/report
# Detailed filesystem scan with JSON output
trivy fs . \
--scanners secret,vuln,misconfig,license \
--format json \
--output out/report/fs-report.json
# Detailed image scan with JSON output
trivy image your-app:latest \
--scanners secret,vuln,misconfig,license \
--format json \
--output out/report/image-report.json
The --scanners
flag lets you specify exactly what to examine. Beyond vulnerabilities (vuln
), you can detect hardcoded secrets (secret
), configuration issues (misconfig
), and license violations (license
).
The scan2html
plugin converts Trivy's JSON output into interactive single page HTML reports.
# Install the plugin first
trivy plugin install scan2html
# Generate HTML reports from JSON output
trivy scan2html generate --scan2html-flags --output out/report/index.html \
--from out/report/fs-report.json,out/report/image-report.json
These HTML reports can be published to GitHub Pages or internal sites, giving everyone on your team a clear view of security issues. To deploy them to GitHub pages you can use the following:
jobs:
scan:
runs-on: ubuntu-latest
steps:
# steps to scan
# then ...
- name: Upload Pages artifact
uses: actions/upload-pages-artifact@v3
with:
path: out/report
deploy:
needs: scan
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: $
runs-on: ubuntu-latest
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
Beyond the scan2html
plugin, the Trivy ecosystem includes several other community reporting tools that are worth a look at.
Software Bill of Materials (SBOM)
Compliance often requires Software Bill of Materials generation. Trivy handles this natively:
# Generate SPDX-format SBOM for filesystem
trivy fs . --format spdx-json --output out/fs-sbom.json
# Generate SPDX-format SBOM for container image
trivy image your-app:latest --format spdx-json --output out/image-sbom.json
SPDX - "The System Package Data Exchange" is a standard format for SBOM data, supported by tools across the security ecosystem.
Practical Tips
Your first scan may reveal several vulnerabilities. Some may be in transitive dependencies. Focus on HIGH and CRITICAL vulnerabilities first. Trivy provides clear remediation guidance—dependency updates or configuration changes.
Customise severity thresholds and focus on actionable issues by filtering severity levels:
trivy fs . --severity HIGH,CRITICAL
Manage false positives with a .trivyignore
file to suppress known issues:
# .trivyignore
CVE-2021-44228 # Log4j - not applicable to our usage
CVE-2022-12345 # Fixed in our custom build
Use this sparingly and document why each CVE is being ignored. Regular reviews of ignored vulnerabilities help ensure they remain valid exceptions.
Policy Enforcement by defining custom security policies using Rego. You can create policy file, e.g. policy.rego
:
package trivy
deny[res] {
input.Results[_].Vulnerabilities[_].Severity == "CRITICAL"
res := sprintf("Critical vulnerability found: %s", [input.Results[_].Vulnerabilities[_].VulnerabilityID])
}
And use the custom policy
trivy fs . --config-policy policy.rego
And, worth noting, Trivy has experimental features covering the scanning of kubernetes resources and VMs.
Wrap up
Trivy provides visibility into your actual security posture - often revealing gaps you didn't know existed.
The value is setting up security checks that grow with your development pace. Trivy makes this setup straightforward.
Security scanning should be as routine as running tests. Once you've added Trivy to your workflow, you'll see vulnerabilities, secrets, and misconfigurations across your codebase. Local scanning, automated checks, and visual reports give you a solid security base that grows with your team.
Start with basic filesystem and image scans, then add reporting and policies as you need them. The goal isn't perfect security scores - it's catching issues before they hit production.