Why Dependency Scanning Matters
Modern applications rely on hundreds of open-source dependencies. A single vulnerable package can expose your entire system:
- Log4Shell (CVE-2021-44228): Critical RCE in Log4j affected millions of applications
- Spring4Shell (CVE-2022-22965): Zero-day in Spring Framework
- Heartbleed (CVE-2014-0160): OpenSSL vulnerability exposed sensitive data
- event-stream incident: Malicious code injected into npm package
The average application contains 203 open-source components, with 91% containing known vulnerabilities (Synopsys 2024 OSSRA Report).
Why Trivy?
Trivy stands out among dependency scanning tools for several reasons:
🚀 Fast & Comprehensive
Scans in seconds using pre-built vulnerability databases. Covers OS packages, application dependencies, and IaC misconfigurations.
🆓 Open Source & Free
No licensing fees, no API keys required. Actively maintained by Aqua Security with daily database updates.
🔄 CI/CD Native
Designed for automation with exit codes, JSON output, and GitHub Actions integration out of the box.
Installation
macOS/Linux
# Homebrew (macOS/Linux)
brew install trivy
# Debian/Ubuntu
sudo apt-get install wget apt-transport-https gnupg lsb-release
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo apt-key add -
echo "deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main" | sudo tee -a /etc/apt/sources.list.d/trivy.list
sudo apt-get update
sudo apt-get install trivy
# Verify installation
trivy --version
Docker
# Run Trivy as a Docker container
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
aquasec/trivy image nginx:latest
Basic Scanning
Scan Container Images
# Scan local image
trivy image myapp:latest
# Scan remote image (no pull required)
trivy image nginx:1.21
# Scan with severity filtering (CRITICAL and HIGH only)
trivy image --severity CRITICAL,HIGH myapp:latest
# Output as JSON
trivy image --format json --output results.json myapp:latest
# Exit with error if vulnerabilities found
trivy image --exit-code 1 --severity CRITICAL myapp:latest
Scan Filesystems
Perfect for scanning your local development environment or CI workspace:
# Scan current directory
trivy fs .
# Scan specific directory
trivy fs ./my-project
# Scan only application dependencies (skip OS packages)
trivy fs --scanners vuln --security-checks vuln .
# Generate SARIF for GitHub Security tab
trivy fs --format sarif --output trivy-results.sarif .
Scan Git Repositories
# Scan remote repository
trivy repo https://github.com/your-org/your-repo
# Scan specific branch
trivy repo --branch develop https://github.com/your-org/your-repo
Understanding Results
Sample Output
myapp:latest (alpine 3.16.2)
============================
Total: 5 (CRITICAL: 2, HIGH: 3)
┌────────────┬────────────────┬──────────┬───────────────────┬───────────────┬──────────────────┐
│ Library │ Vulnerability │ Severity │ Installed Version │ Fixed Version │ Title │
├────────────┼────────────────┼──────────┼───────────────────┼───────────────┼──────────────────┤
│ openssl │ CVE-2023-12345 │ CRITICAL │ 1.1.1q │ 1.1.1r │ OpenSSL RCE │
│ curl │ CVE-2023-67890 │ HIGH │ 7.83.1 │ 7.84.0 │ Heap overflow │
│ lodash │ CVE-2021-23337 │ HIGH │ 4.17.15 │ 4.17.21 │ Command injection│
└────────────┴────────────────┴──────────┴───────────────────┴───────────────┴──────────────────┘
Severity Levels
| Severity | CVSS Score | Action |
|---|---|---|
| CRITICAL | 9.0 - 10.0 | Fix immediately, block deployment |
| HIGH | 7.0 - 8.9 | Fix within 7 days |
| MEDIUM | 4.0 - 6.9 | Fix within 30 days |
| LOW | 0.1 - 3.9 | Monitor, fix when convenient |
Advanced Configuration
Ignore Specific Vulnerabilities
Create .trivyignore to suppress known false positives or accepted risks:
# CVE-2023-12345: Not exploitable in our usage (library only used for X)
CVE-2023-12345
# Waiting for upstream fix, tracking in JIRA-1234
CVE-2023-67890
# Expired: Re-evaluate on 2025-12-31
# CVE-2023-11111
Always document why a CVE is ignored. Include ticket numbers, expiration dates, and justification. Review .trivyignore monthly.
Custom Severity Filtering
# Only fail on CRITICAL
trivy image --exit-code 1 --severity CRITICAL myapp:latest
# Warn on MEDIUM, fail on HIGH+
trivy image --exit-code 0 --severity MEDIUM myapp:latest || echo "Warnings found"
trivy image --exit-code 1 --severity HIGH,CRITICAL myapp:latest
Policy-Based Scanning
Define custom policies with Rego (Open Policy Agent):
package trivy
default ignore = false
# Ignore LOW severity in dev images
ignore {
input.Severity == "LOW"
startswith(input.ImageName, "myapp:dev-")
}
# Block CRITICAL in production images
deny[msg] {
input.Severity == "CRITICAL"
contains(input.ImageName, ":prod-")
msg := sprintf("CRITICAL vulnerability in production image: %s", [input.VulnerabilityID])
}
# Run with custom policy
trivy image --policy ./policy.rego myapp:prod-v1.2.3
CI/CD Integration
GitHub Actions
name: Trivy Vulnerability Scan
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
schedule:
- cron: '0 6 * * *' # Daily at 6 AM UTC
jobs:
scan:
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Build Docker image
run: docker build -t myapp:${{ github.sha }} .
- name: Run Trivy scan
uses: aquasecurity/trivy-action@master
with:
image-ref: 'myapp:${{ github.sha }}'
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
- name: Upload to GitHub Security
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: 'trivy-results.sarif'
- name: Check for vulnerabilities
uses: aquasecurity/trivy-action@master
with:
image-ref: 'myapp:${{ github.sha }}'
exit-code: '1'
severity: 'CRITICAL'
ignore-unfixed: true # Only fail on patchable CVEs
GitLab CI
trivy_scan:
image: aquasec/trivy:latest
stage: test
script:
- trivy image --format json --output trivy-report.json $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
- trivy image --exit-code 1 --severity CRITICAL $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
artifacts:
reports:
container_scanning: trivy-report.json
when: always
expire_in: 1 week
Vulnerability Management Workflow
1. Triage Process
┌─────────────┐
│ Daily Scan │
└─────┬───────┘
│
▼
┌─────────────────────┐
│ CRITICAL/HIGH found?│──No──▶ Continue
└─────┬───────────────┘
│ Yes
▼
┌──────────────────┐
│ Is it exploitable│──No──▶ Add to .trivyignore with reason
│ in our context? │
└─────┬────────────┘
│ Yes
▼
┌──────────────────┐
│ Fixed version │──Yes──▶ Create PR to update dependency
│ available? │
└─────┬────────────┘
│ No
▼
┌──────────────────┐
│ Apply workaround │
│ or disable │
│ vulnerable code │
└──────────────────┘
2. Automated Dependency Updates
Combine Trivy with Dependabot/Renovate for automatic PRs:
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
labels:
- "dependencies"
- "security"
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "weekly"
3. Monitoring Trends
Track vulnerability counts over time:
# Generate metrics for dashboard
trivy image --format json myapp:latest | \
jq '{
critical: [.Results[].Vulnerabilities[]? | select(.Severity=="CRITICAL")] | length,
high: [.Results[].Vulnerabilities[]? | select(.Severity=="HIGH")] | length,
medium: [.Results[].Vulnerabilities[]? | select(.Severity=="MEDIUM")] | length,
total: [.Results[].Vulnerabilities[]?] | length
}' > metrics.json
# Example output: {"critical":2,"high":5,"medium":12,"total":19}
Best Practices
🎯 Scan Early & Often
Scan on every commit, daily scheduled scans, and before production deployments.
🔒 Block CRITICAL
Use --exit-code 1 --severity CRITICAL to prevent deploying critical vulnerabilities.
📊 Track Metrics
Monitor vulnerability trends over time. Aim for reducing total count month-over-month.
🧹 Minimize Base Images
Use Alpine or distroless images. Fewer packages = smaller attack surface.
🔄 Automate Updates
Use Dependabot/Renovate to automatically create PRs for dependency updates.
📝 Document Ignores
Always explain why a CVE is in .trivyignore. Include expiration dates.
Optimizing Docker Images
Multi-Stage Builds
Reduce vulnerabilities by excluding build tools from final image:
# ❌ Bad: Includes build tools in final image (500 MB, 47 vulnerabilities)
FROM node:18
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
CMD ["node", "dist/index.js"]
# ✅ Good: Minimal runtime image (150 MB, 8 vulnerabilities)
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["node", "dist/index.js"]
Use Distroless Images
# Minimal image with only runtime dependencies
FROM gcr.io/distroless/nodejs18-debian11
COPY --from=builder /app /app
WORKDIR /app
CMD ["dist/index.js"]
Troubleshooting
Database Update Failures
# Manually update vulnerability database
trivy image --download-db-only
# Use different mirror if default is slow
trivy image --db-repository ghcr.io/aquasecurity/trivy-db myapp:latest
False Positives
- Vulnerability in unused code path: Document in
.trivyignorewith justification - Fixed in newer patch version: Update dependency in
package.jsonorrequirements.txt - Not exploitable: Verify with CVE details, add to ignore list with evidence
Performance Issues
# Use local cache to speed up repeated scans
trivy image --cache-dir .trivycache myapp:latest
# Skip DB update if recent
trivy image --skip-update myapp:latest
# Scan only specific layers
trivy image --skip-files /usr/share/doc myapp:latest
Integration with Other Tools
Combine with SAST
jobs:
security:
runs-on: ubuntu-latest
steps:
# SAST for code vulnerabilities
- name: Semgrep scan
run: semgrep scan --config=auto --sarif > semgrep.sarif
# Dependency scanning
- name: Trivy scan
run: trivy fs --format sarif --output trivy.sarif .
# Upload both results
- name: Upload SARIF
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: |
semgrep.sarif
trivy.sarif
Generate SBOMs
Software Bill of Materials for compliance:
# Generate SBOM in CycloneDX format
trivy image --format cyclonedx --output sbom.json myapp:latest
# Generate SPDX format
trivy image --format spdx --output sbom.spdx myapp:latest
Next Steps
You're now equipped to implement comprehensive dependency scanning! Continue building your security program:
- Add SAST scanning for code-level vulnerabilities
- Implement DAST for runtime testing
- Try our interactive demo to see all scanning types
- Contact us for enterprise vulnerability management
ElevatedIQ offers automated dependency scanning, vulnerability triage services, and SLA-based remediation support. Get in touch to secure your supply chain.