The scanner landscape
tfsec/Trivy, Terrascan, KICS, Snyk.
Checkov is one smoke detector in a house that has several. tfsec, Trivy, Terrascan, KICS and Snyk all sniff the same air: your Terraform, your Kubernetes manifests, your CloudFormation templates. They are all hunting for misconfigured infrastructure as code (IaC, meaning your cloud setup lives in files you commit like source) before any of it reaches a real account. What changes from tool to tool is the sensor. Some are tuned tightly to Terraform. Some watch every room in the house. And they disagree, loudly, about how you write your own rules.
Here is how that bites. Security runs Trivy on a nightly job. The platform team runs Checkov in the pipeline. The same public S3 bucket then produces two tickets with two different rule IDs, two different severities and two different suggested fixes, and the on-call engineer gets to referee. Knowing which scanners exist, what each is genuinely good at, and who owns which signal, ends that argument before it reaches your pipeline.
Pick one primary scanner and stay with it. Add a second only when it sees something the first cannot. And treat the pass/fail totals from two different tools as two different currencies, because they never convert cleanly.
The neighbors, one command each
Every one of these tools has a scan-this-directory command, so you can learn the shape of the field in an afternoon. tfsec was Terraform only and has been folded into Trivy's config scanner. Trivy covers IaC misconfiguration, container images, secrets and SBOM (software bill of materials, the ingredient list of what went into a build) from one binary. Terrascan writes its checks in Rego, the policy language that comes from OPA (Open Policy Agent). KICS supports the widest spread of file formats. Snyk IaC is commercial and reports into a hosted backend. Point all of them at the same repository and compare what they find, not what they count.
$ tfsec .$ trivy config .$ terrascan scan -i terraform -d .$ kics scan -p . -o ./results --report-formats sarif$ checkov -d . --compact --quiet
tfsec: 28 potential problemsTrivy: 31 misconfigurations (HIGH: 4, CRITICAL: 1)Terrascan: 24 violationsKICS: Scan completed - 19 failed queriescheckov: Passed 812, Failed 37
Where they really differ: the policy engine
Out of the box, every one of these tools prints a similar-looking list of HIGH and CRITICAL findings. The split opens the day you write your own rule. Most of the field speaks Rego: Trivy, Terrascan, KICS and Snyk. Checkov is the odd one out, with checks written in Python or YAML, plus graph-aware CKV2_ checks that reason about how resources relate to each other instead of reading one block in isolation. The trade runs both ways. If your organization already runs OPA for Kubernetes admission control, a Rego-native scanner keeps everyone in one language. Checkov's counter-offer is graph checks, plan scanning and baselines.
$ checkov -d . -o sarif --output-file-path .$ trivy config . --format sarif -o trivy.sarif
Wrote SARIF output to ./results_sarif.sarifWrote trivy.sarif# Both feed the same code-scanning dashboard — IDs differ, format is portable
Choosing without stacking four scanners
Running Checkov, Trivy, Terrascan and KICS together sounds thorough. In practice it multiplies noise and suppressions while adding very little real coverage, because the catalogs overlap heavily at the top end. Pick one primary IaC scanner. Standardize on its output format and its skip syntax, so every developer learns one way to suppress a finding. Add a second tool only for a capability the first lacks, for example Trivy for container images while Checkov owns IaC. Standalone tfsec is in maintenance mode, so anyone still running it should move to trivy config.
$ trivy config . --severity HIGH,CRITICAL$ checkov -d . --framework terraform --compact --quiet
Total: 5 (HIGH: 3, CRITICAL: 2)checkov Failed checks: 37# different counts, different catalogs — compare on real catches, not totals
When Checkov should be the primary
Checkov earns the primary slot when you want one pass over a mixed repo: Terraform, Kubernetes manifests, Dockerfiles and GitHub Actions workflows in a single command. On top of that you get the CKV2_ graph checks, scanning of a rendered Terraform plan, baselines for legacy repositories, and custom policies in Python or YAML with nobody having to learn Rego. For most Terraform and Kubernetes estates, that combination removes the reason to stack three scanners.
Where Trivy earns a place beside Checkov
Keep Checkov as the owner of IaC, then bring in trivy image and trivy fs for container CVEs (Common Vulnerabilities and Exposures, the public catalog of known flaws in released software) and application dependencies. Those are domains Checkov only partly reaches (cv-overlap). Note that trivy config overlaps Checkov on IaC, so do not point both at the same .tf files without a reason you can write down. One IaC scanner, one image scanner, both emitting SARIF (Static Analysis Results Interchange Format, the shared file format code-scanning dashboards read) into the same dashboard.
$ checkov -d . --framework terraform -o sarif --output-file-path .$ trivy image --format sarif -o trivy-image.sarif myapp:1.4.2
Wrote SARIF output to ./results_sarif.sarifWrote trivy-image.sarif
How to run the bake-off
Give it one afternoon and one repository. Run each candidate over the same code and write down five things: which genuine misconfigurations it caught, how much of its output was wrong on your files, how painful its custom-rule format felt, how long it took in CI (continuous integration, the automated build that runs on every change), and whether its SARIF output was clean enough to load into a dashboard. Ignore the totals at the bottom of the screen. Choose one primary, and only write up a second tool if it fills a gap the primary cannot.
The custom-rule test is the one people skip and later regret. Take a real rule your organization already argues about, something like "every resource must carry an Owner tag", and write it in each candidate before you decide. Terrascan and KICS push you into Rego. Snyk offers a hosted catalog and a report. Checkov takes Python or YAML. The rule you write in week one will still be running in year three, long after the comparison spreadsheet is lost.
SARIF is what makes the bake-off practical. Every one of these tools can emit it, so you load four sets of results into one dashboard and read them side by side instead of learning four user interfaces. The rule IDs will never line up. Checkov's CKV_AWS_20 and Trivy's AVD-AWS-0089 can describe the same public bucket. Line results up by resource address instead, then apply one human test to each finding: would we block a merge on this?
Fit matters more than feature lists. KICS pulls ahead when your estate sprawls across Ansible playbooks, Pulumi-adjacent YAML and five cloud dialects, though Checkov covers a lot of that too, so compare the noise on your own files. Terrascan appeals when security already employs people who write Rego all day. Trivy wins when leadership has mandated one vendor for IaC, images and secrets, and in that case you tune the overlap with Checkov rather than pointing both at identical paths.
Snyk IaC sits in a different conversation because it is commercial. It adds hosted policy management and a smoother developer experience. Ask what is actually broken today. If the findings themselves are poor, an open-source CLI (command line interface) bake-off answers that. If the findings are fine and nobody acts on them, you are buying workflow, and the real question becomes who keeps the policy catalog current when nobody has spare time.
Be careful with the phrase "we are already a Rego shop". Trivy, Terrascan, KICS and Snyk all use Rego, and not one of them feeds it the same input. The document your policy receives has a different shape in each tool, so a working Terrascan policy does not drop into Trivy and run. If shared rules are the argument that decides your choice, test that claim on day one by porting a single real policy across two tools before anyone signs anything.
When a director asks why you chose Checkov over Trivy, do not answer with failure counts. Answer with the program features you depend on: baselines, so a ten-year-old monorepo can adopt scanning without hitting a wall of findings; terraform_plan scanning, so you catch what the source files cannot show; CKV2_ graph checks; and custom rules in a language your teams already write.
When the same director asks why you do not run both on every pull request, the answer is alert fatigue and duplicate suppressions. Two scanners over the same .tf means the same public bucket arrives twice under two IDs, and every agreed exception has to be written twice in two syntaxes. Gates that multiply get bypassed, and both the pipeline enforcement (cv-cicd) and the wider program (cv-program) quietly die when that happens.
Some concrete pointers to save you a week. If you inherited tfsec from an old pipeline, move to trivy config, which is where those checks now live and get maintained. Look seriously at Terrascan, KICS or Snyk only when Rego or format breadth genuinely matches your estate. And treat every scanner after the first as something you have to justify in writing.
Set side by side, the split is easy to hold in your head. Checkov brings CKV2_ graph checks, terraform_plan scanning, baselines, and Python or YAML custom rules. Trivy brings image CVE scanning, trivy fs for dependency inventory, and secrets, all from one binary. Record whichever you pick in an ADR (architecture decision record, a short dated file in the repo saying what you decided and why), so the engineer who joins next year does not bolt Terrascan on beside Checkov "for coverage".
Score the shortlist against your own estate, not against a vendor slide claiming thousands of checks. Do you need to scan a rendered plan before apply, or is the source enough? Do your developers write Python already, or is Rego the house language because OPA gates admission? Can you start scanning a legacy monorepo without a baseline feature, honestly? Run the same three modules through each CLI, export SARIF into one dashboard, and ask the blunt question on every finding: would we block a merge on this? An afternoon of that evidence beats three weeks of opinion.
Try this
Run Checkov and one neighbor on the same directory (trivy config is the usual partner), export SARIF from both, and walk the unique findings one at a time asking whether you would block a merge on each. Whichever tool printed the bigger number wins nothing.
$ checkov -d . --compact --quiet -o sarif --output-file-path .$ trivy config . --severity HIGH,CRITICAL --format sarif -o trivy.sarif$ checkov -d . -o json | jq 'if type=="array" then .[].summary.failed else .summary.failed end'$ echo "Compare: would you block merge on each unique finding?"
checkov: Passed 812, Failed 37Wrote SARIF output to ./results_sarif.sarifTrivy: 31 misconfigurations (HIGH: 4, CRITICAL: 1)Wrote trivy.sarif37Compare: would you block merge on each unique finding?
Takeaway
Bake-offs go wrong when raw failure counts decide them. Tools disagree on catalog coverage, on graph depth, on whether they can read a plan, and on how you write a custom rule. Pick one primary and hold it: Checkov if you need baselines, terraform_plan, CKV2_ graph checks and Python or YAML policies; Trivy if a single binary for images plus config already matches how your platform team works.
Next step: run trivy config beside checkov -d . on one repo this week, load both SARIF files into the same dashboard, and count how many findings are genuinely new rather than the same bucket wearing a second ID. That number, not a total, decides whether a second scanner earns a place. Then map domain ownership so secrets and CVE scanning stop triple-reporting one bucket (cv-overlap), and wire the winner into CI (cv-cicd).