A demo repository that uses Trivy to detect misconfigurations in Terraform code.
It provides intentionally vulnerable code in insecure/ alongside hardened code in secure/, so you can see how static analysis detects and resolves security issues.
Trivy is an open-source security scanner developed by Aqua Security. While widely known for container image scanning, Trivy also supports Infrastructure as Code (IaC) including Terraform, CloudFormation, Kubernetes manifests, and more. It assigns severity levels (CRITICAL / HIGH / MEDIUM / LOW) to each finding, using check IDs from the Aqua Vulnerability Database (AVD-AWS-XXXX).
├── insecure/ # Intentionally vulnerable Terraform code
│ ├── provider.tf
│ ├── s3.tf # No encryption, public access, versioning disabled
│ ├── sg.tf # All ports open, SSH exposed to 0.0.0.0/0
│ ├── rds.tf # No encryption, public access, hardcoded password
│ ├── iam.tf # Wildcard Action/Resource (*)
│ └── cloudtrail.tf # No log encryption, validation disabled
├── secure/ # Hardened Terraform code (all Trivy checks passed)
│ ├── provider.tf
│ ├── s3.tf # KMS encryption, public access block, versioning, logging
│ ├── sg.tf # Restricted ports, SSH limited to specific CIDR
│ ├── rds.tf # Encrypted, private, Multi-AZ, IAM auth, Performance Insights
│ ├── iam.tf # Least privilege policy
│ └── cloudtrail.tf # KMS encryption, log validation, CloudWatch integration
└── .github/workflows/
└── trivy.yml # GitHub Actions automated scanning
# Install Trivy
brew install trivy
# Scan vulnerable code (many FAILURES expected)
trivy config insecure/
# Scan hardened code (0 FAILURES)
trivy config secure/
# Filter by severity
trivy config --severity HIGH,CRITICAL insecure/
# Show PASSED results too
trivy config --include-non-failures insecure/Scanned with Trivy v0.69.3.
S3 (s3.tf) — 11 FAILURES
| AVD ID | Severity | Description | Fix |
|---|---|---|---|
| AWS-0086 | HIGH | No public access block — not blocking public ACLs | Add aws_s3_bucket_public_access_block with block_public_acls = true |
| AWS-0087 | HIGH | No public access block — not blocking public policies | block_public_policy = true |
| AWS-0089 | LOW | Bucket has logging disabled | Add aws_s3_bucket_logging targeting a log bucket |
| AWS-0090 | MEDIUM | Bucket does not have versioning enabled | Add aws_s3_bucket_versioning with status = "Enabled" |
| AWS-0091 | HIGH | No public access block — not ignoring public ACLs | ignore_public_acls = true |
| AWS-0092 | HIGH | Bucket has a public ACL: "public-read" | Remove ACL resource, add public access block |
| AWS-0093 | HIGH | No public access block — not restricting public buckets | restrict_public_buckets = true |
| AWS-0094 | LOW | Bucket does not have a corresponding public access block | Add aws_s3_bucket_public_access_block |
| AWS-0132 | HIGH | Bucket does not encrypt data with a customer managed key | Create KMS key and set kms_master_key_id |
| AWS-0161 | CRITICAL | Trail S3 bucket is publicly exposed | Protect with public access block |
| AWS-0163 | LOW | Trail S3 bucket does not have logging enabled | Enable access logging to log bucket |
Security Group (sg.tf) — 6 FAILURES
| AVD ID | Severity | Description | Fix |
|---|---|---|---|
| AWS-0104 | CRITICAL | Unrestricted egress to any IP address | Restrict egress to internal network CIDR |
| AWS-0107 | HIGH | Unrestricted ingress — all ports open to 0.0.0.0/0 (x2) | Allow HTTPS only, restrict SSH to specific CIDR |
| AWS-0124 | LOW | Security group rule does not have a description (x3) | Add description to each rule |
RDS (rds.tf) — 6 FAILURES
| AVD ID | Severity | Description | Fix |
|---|---|---|---|
| AWS-0077 | MEDIUM | Very low backup retention period | backup_retention_period = 7 |
| AWS-0080 | HIGH | Storage encryption disabled | storage_encrypted = true |
| AWS-0133 | LOW | Performance Insights not enabled | performance_insights_enabled = true with CMK |
| AWS-0176 | MEDIUM | IAM Database Authentication not enabled | iam_database_authentication_enabled = true |
| AWS-0177 | MEDIUM | Deletion Protection not enabled | deletion_protection = true |
| AWS-0180 | HIGH | Instance has Public Access enabled | publicly_accessible = false |
CloudTrail (cloudtrail.tf) — 4 FAILURES
| AVD ID | Severity | Description | Fix |
|---|---|---|---|
| AWS-0014 | MEDIUM | Trail is not enabled across all regions | is_multi_region_trail = true |
| AWS-0015 | HIGH | CloudTrail does not use a customer managed key | Create KMS key and set kms_key_id |
| AWS-0016 | HIGH | Log file validation disabled | enable_log_file_validation = true |
| AWS-0162 | LOW | CloudWatch logging not configured | Add CloudWatch Logs group and role |
IAM (iam.tf) — 0 FAILURES
Trivy v0.69.3 did not flag wildcard IAM policies (Action: "*", Resource: "*"). Checkov detects these as CKV_AWS_1 / CKV_AWS_289 / CKV_AWS_290.
All checks passed.
| Item | Checkov | Trivy |
|---|---|---|
| Developer | Prisma Cloud (Palo Alto Networks) | Aqua Security |
| Check ID format | CKV_AWS_XXX, CKV2_AWS_XXX |
AVD-AWS-XXXX |
| Severity levels | PASSED / FAILED only | CRITICAL / HIGH / MEDIUM / LOW |
| Install | pip install checkov |
brew install trivy |
| Scan command | checkov -d <dir> |
trivy config <dir> |
| Scope | IaC focused | Container images, filesystems, IaC, SBOM, and more |
| Custom policies | Python | Rego (OPA) |
| GitHub Actions | bridgecrewio/checkov-action |
aquasecurity/trivy-action |
| Show passed checks | Shown by default | Requires --include-non-failures flag |
See checkov-terraform-demo for a Checkov comparison using the same Terraform code.
Trivy scans run automatically on push and pull requests. Results are posted as PR comments.
- scan-insecure:
exit-code: "0"— failures do not block CI (expected to fail) - scan-secure:
exit-code: "1"— any failure blocks CI
- Trivy (GitHub)
- Trivy Documentation
- Aqua Vulnerability Database — Misconfig
- checkov-terraform-demo — Checkov version for comparison