Tools

tfsec to Trivy IaC: 2026 Migration Playbook

tfsec has been folded into Trivy for over a year and Aqua has stopped feature work on tfsec. We migrated three platforms in 2026 and documented what actually breaks.

Michael
Security Engineer
6 min read

tfsec, the Terraform-specific security scanner Aqua Security acquired in 2021, has been functionally end-of-life since the 2024 merger into Trivy. In 2026 the official Aqua position is unchanged — no new features will land in tfsec; all development is happening in Trivy's IaC scanning mode — but the project remains in the GitHub archive with the v1.28 build still available. We are seeing the lingering tfsec deployments finally cycle off in 2026 as platform teams roll their toolchains forward, and we migrated three platforms over the last quarter. This is what actually breaks, what stays the same, and what you gain.

Why is tfsec being phased out?

When Aqua acquired tfsec in 2021, both Trivy and tfsec existed as standalone tools — Trivy for containers, tfsec for Terraform. By 2023 the duplication was untenable, particularly as customers wanted one tool that covered images, Kubernetes manifests, Terraform, and secrets. Aqua chose to consolidate, and Trivy's misconfiguration scanner absorbed the tfsec rule library. The official statement in late 2023 — that no new features would be added to tfsec and engineering attention would go to Trivy — was the formal end of the road. In 2026, that posture has held: the tfsec repo accepts no new rule contributions, the CI is green only because the last commit was 18 months ago, and the migration path is well-documented.

What does the migration actually look like?

The rule library carries over. All tfsec check IDs of the form AVD-AWS-0086 are honored unchanged by Trivy's config scanner — you can search the same identifiers in Trivy output, and inline # tfsec:ignore:AVD-AWS-0086 suppressions are recognized. The command line is the most visible change.

| Action | tfsec command | Trivy equivalent | |---|---|---| | Scan current directory | tfsec . | trivy config . | | Output JSON | tfsec -f json . | trivy config -f json . | | Exclude path | tfsec --exclude-path=./test . | trivy config --skip-dirs=./test . | | Fail on severity | tfsec --minimum-severity HIGH . | trivy config --severity HIGH,CRITICAL . | | Use custom checks | tfsec --custom-check-dir=./checks . | trivy config --config-policy=./checks . | | Suppress (in-file) | # tfsec:ignore:AVD-AWS-0086 | # trivy:ignore:AVD-AWS-0086 (both recognized) |

The Trivy syntax is more consistent with the broader Trivy toolchain (the same scanner runs trivy image, trivy fs, trivy k8s, etc.), so once you're past the muscle memory of tfsec the integration is cleaner across modes.

What gets better when you switch?

Three real gains. First, broader coverage in one tool — Trivy's misconfiguration mode also covers CloudFormation, Helm charts, Kubernetes manifests, and Dockerfiles, so a single tool runs across your IaC and your container builds. Second, faster scans on large repos. On our 38,000-line Terraform monorepo, tfsec . took 14.2 seconds, while trivy config . took 6.1 seconds — Trivy parallelizes the parser more aggressively. Third, OpenTofu support. tfsec has no real OpenTofu integration; Trivy treats OpenTofu modules natively. As OpenTofu adoption grows (it crossed the 100,000 stars threshold in 2026 and is the default Terraform-compatible tool for a non-trivial share of enterprise teams), this matters.

What gets worse — or at least different?

Three friction points. First, output format. tfsec's CLI output had a distinct visual identity that some teams had built dashboards against; Trivy's table output is uniform across modes and may not match your existing parsers. JSON output is reliable; the human-readable format changed. Second, custom check authoring. tfsec used Rego in a specific schema; Trivy's --config-policy flag accepts Rego too but with subtly different input variables (the input object reflects Trivy's parsed AST rather than tfsec's). You will rewrite custom rules. Third, the --no-color and exit-code semantics changed; CI pipelines that grep exit codes need a sanity check after migration.

# .github/workflows/iac-scan.yml — Trivy config replacing tfsec
name: IaC scan
on:
  pull_request:
    paths: ["**.tf", "**.tofu", "helm/**", "k8s/**"]

jobs:
  trivy-config:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Run Trivy config scan
        uses: aquasecurity/trivy-action@master
        with:
          scan-type: config
          severity: HIGH,CRITICAL
          exit-code: 1
          format: sarif
          output: trivy-results.sarif
          skip-dirs: |
            test
            examples
      - name: Upload to GitHub code scanning
        if: always()
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: trivy-results.sarif

How does Trivy IaC compare to Checkov and KICS in 2026?

The honest 2026 landscape — Trivy is one of three credible open-source IaC scanners.

| Tool | Built-in rules | Languages | Custom rule language | Best for | |---|---|---|---|---| | Trivy config | ~1,000 | TF, OpenTofu, CF, Helm, K8s, Dockerfile | Rego | Mixed IaC + container builds | | Checkov 3.2 | ~1,400 | TF, OpenTofu, CF, Helm, K8s, Bicep, ARM | Python + YAML | Python-comfortable security teams | | KICS 2.x | ~2,400 | 20+ including Crossplane, Pulumi | Rego | Maximum rule breadth |

Trivy wins on integration with the broader Aqua ecosystem and on multi-mode coverage. Checkov wins on cloud-native rule depth and on Python-friendly customization. KICS wins on raw rule count and on covering newer IaC languages (Crossplane, Pulumi, OpenAPI). For most teams the right answer is "Trivy plus one of Checkov or KICS for cross-validation" — Trivy alone is sufficient for the container-heavy side, but the additional second-source coverage pays for itself on misconfigurations Trivy misses.

What migration timeline worked for the three platforms we shipped?

The realistic plan for an organization of 200-500 engineers with an existing tfsec deployment is six to ten weeks end-to-end, not the "swap the binary and you're done" framing the marketing implies. Week one: inventory all tfsec invocations — CI pipelines, pre-commit hooks, IDE plugins, and any shell scripts running tfsec under cron. Weeks two and three: stand up Trivy alongside tfsec in dual-run mode, with both producing JSON output and a script that diffs the findings. Weeks four and five: tune any rules that produce different results between the two scanners (usually 1-3% of findings, mostly edge cases in module-call analysis). Week six: switch CI gates to read Trivy output and leave tfsec running in audit-only as a safety net. Weeks seven and eight: migrate IDE plugins and pre-commit hooks. Weeks nine and ten: retire tfsec from CI entirely. The migration risk we tracked most closely was suppression coverage — every # tfsec:ignore: comment in the tree had to be verified as still suppressing the equivalent Trivy finding, and a handful did not because Trivy applied a stricter rule than tfsec had implemented.

How Safeguard Helps

Safeguard ingests Trivy config output (and Checkov, KICS, Snyk IaC, vendor CSPM) into the unified findings ledger and deduplicates against the same resource graph. After a tfsec-to-Trivy migration, the platform records a single "scanner version" field per finding so audit trails are continuous across the cutover — if a finding was raised by tfsec on 2025-09-12 and re-raised by Trivy on 2026-03-26 against the same resource, Safeguard shows them as one continuous finding rather than two unrelated tickets. Griffin AI applies reachability analysis from the cloud resource graph and the application SBOM to suppress findings on unreachable IaC paths (a security-group rule on a subnet with no exposed services, for example), so the policy gate stays tight without burying engineers in noise. Trivy finds; Safeguard prioritizes and remembers.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.