If your pipeline still calls tfsec, it is running a project that no longer exists independently — tfsec was folded into Trivy, and its checks now ship as trivy config. Terrascan, the other common alternative, was archived in November 2025.
This is worth more than a find-and-replace in a workflow file. A scanner can die quietly while still exiting zero. A pipeline calling an unmaintained binary against a rule database that stopped updating is worse than no gate at all — it produces a green check that means nothing, and nobody looks at a green check.
Verified against Trivy 0.72.0, scanning the same Range Terraform the Checkov lesson used. Every output is copied from a real terminal.
Step 1 — Install and scan
brew install trivy
trivy --versiongit clone https://github.com/jaybilgaye/aiopsone-range
cd aiopsone-range
trivy config terraform/Tests: 11 (SUCCESSES: 0, FAILURES: 11)
Failures: 11 (UNKNOWN: 0, LOW: 2, MEDIUM: 1, HIGH: 7, CRITICAL: 1)No AWS account, no credentials, nothing applied — same as Checkov, same input.
Step 2 — The mapping from tfsec
Old check IDs became AWS-####:
AWS-0086 (HIGH): Public access block does not block public ACLs
AWS-0087 (HIGH): Public access block does not block public policies
AWS-0089 (LOW): Bucket has logging disabled
AWS-0090 (MEDIUM): Bucket does not have versioning enabled
AWS-0091 (HIGH): Public access block does not ignore public ACLs
AWS-0093 (HIGH): Public access block does not restrict public buckets
AWS-0104 (CRITICAL): Security group rule allows unrestricted egress to any IP address
AWS-0107 (HIGH): Security group rule allows unrestricted ingress from any IP address
AWS-0107 (HIGH): Security group rule allows unrestricted ingress from any IP address
AWS-0124 (LOW): Security group rule does not have a description
AWS-0132 (HIGH): Bucket does not encrypt data with a customer managed keyThe migration itself is small:
- tfsec ./terraform
+ trivy config ./terraformIgnores move from tfsec:ignore:aws-s3-enable-bucket-encryption comments to trivy:ignore:AWS-0132. If you have many, migrate them deliberately rather than mechanically — an ignore written three years ago for a reason nobody remembers is a finding in itself.
Step 3 — Now compare it with Checkov
Same directory. Same Terraform. Two tools:
| Checkov | trivy config | |
|---|---|---|
| Findings | 26 | 11 |
| Severity model | pass/fail per check | LOW → CRITICAL |
| Unrestricted egress | CKV_AWS_382 (no severity) |
AWS-0104 CRITICAL |
| Customer-managed KMS key | not flagged | AWS-0132 HIGH |
| IAM data exfiltration | CKV_AWS_288 |
not flagged |
IAM "*" admin |
CKV_AWS_62, CKV_AWS_355 |
not flagged |
Read that table before you pick a tool.
Trivy is the only one that rates unrestricted egress CRITICAL. Checkov reports it without a severity, so in a soft_fail_on: LOW,MEDIUM gate it lands wherever your config puts it. Trivy makes it the single most severe thing in the repository — defensible, since egress to anywhere is how data leaves.
Checkov is the only one that flagged the IAM role at all. The Range contains an Action: "*", Resource: "*" policy attached to an EC2 role — a wildcard admin grant. Trivy's Terraform rules did not report it. If you ran only trivy config, the worst IAM configuration in the repository would pass silently.
Neither reports the missing CloudTrail, for the same structural reason: there is no resource to attach a rule to.
The uncomfortable conclusion. Neither tool is a superset. Trivy is stronger on network egress and encryption specifics; Checkov is stronger on IAM policy semantics. "We scan our Terraform" is not a control statement until you can say which checks actually run.
Step 4 — Run both, and say why
They are both fast and both free, so the sensible pipeline runs both:
# .github/workflows/iac.yml
name: iac
on: [pull_request]
permissions:
contents: read
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Checkov (IAM policy semantics)
uses: bridgecrewio/checkov-action@master
with:
directory: terraform/
soft_fail_on: LOW,MEDIUM
- name: Trivy config (network and encryption)
run: trivy config terraform/ --exit-code 1 --severity HIGH,CRITICALThe step names carry the reasoning. Six months from now, when someone asks whether one can be dropped to save forty seconds, the answer is in the workflow file rather than in somebody's memory.
Step 5 — Do not let a dead tool stay green
Whatever you run, pin the version and watch it:
- run: |
trivy --version
trivy config terraform/ --exit-code 1 --severity HIGH,CRITICALPrinting the version into the build log costs nothing and means a stale scanner is visible in every run rather than discovered during an audit. tfsec's last independent release still exits zero on a clean scan today — it simply stopped learning about new misconfigurations. That is what a dead gate looks like from the inside: green.
What you learned
- tfsec is now
trivy config; Terrascan is archived. The command change is one line, the ignore-comment migration deserves actual review. - 26 findings versus 11 on identical input. Different rule sets, not different quality.
- Trivy rates unrestricted egress CRITICAL and catches KMS specifics; Checkov is the only one that flagged a wildcard admin IAM policy. Running one leaves a real gap.
- Neither can report a missing CloudTrail. IaC scanning is blind to absence.
- Print the scanner version in CI. A dead scanner exits zero, and a green check nobody questions is the worst outcome available.