Most teams that adopt an infrastructure as code scanner either drown developers in findings and switch it to warn-only, or suppress so much that it stops catching anything, and in 2026 the scanners themselves became a supply chain target. Checkov, Trivy, KICS and Conftest are the main open source engines for checking Terraform, CloudFormation, Kubernetes manifests, Helm charts and Dockerfiles before they reach the cloud. This guide compares them, explains how Checkov's check IDs, suppressions, baselines and fail thresholds actually work, shows where plan scanning beats source scanning, and covers how to run a scanner without handing it your pipeline secrets. It is for platform engineers, DevSecOps teams and cloud security architects. For what the scanners should find, see the Top 10 Infrastructure as Code Misconfigurations; for the wider programme, the Infrastructure as Code Security Guide.
This is an independent guide from NHI Mgmt Group, based on the public documentation of Checkov, Trivy, KICS and Conftest as of November 2026. It is not sponsored or reviewed by any of those projects or their maintainers. Tools change, so confirm behaviour against each project's current documentation.
Key takeaways
- Pick the engine by policy language and coverage, not by rule count. Checkov offers Python and YAML policies and graph checks across many frameworks; Trivy and Conftest use Rego; KICS uses its own query library. All catch the common misconfigurations.
- Scan the plan as well as the source. Source scans give fast feedback with line numbers; Terraform plan scans see resolved variables and module output, which is where many real misconfigurations hide.
- Suppressions are risk acceptances. Every inline skip should carry a reason, an owner and a review date, and a baseline file should only ever shrink.
- Gate on a short list first. Hard-fail on a small set of critical checks, soft-fail the rest, and widen the gate as teams clear their backlog.
- The scanner is a privileged pipeline component. The 2026 Trivy and KICS supply chain compromises turned trusted scanners into credential stealers, so pin versions, verify images and give scan jobs no cloud credentials.
The open source engines compared
| Engine | Maintainer and status | Inputs (from project docs) | Custom policy language | Notes |
|---|---|---|---|---|
| Checkov | Prisma Cloud (Palo Alto Networks), active | Terraform, Terraform plan and JSON, OpenTofu, CloudFormation, AWS SAM, Kubernetes, Helm, Kustomize, Dockerfile, Serverless, Ansible, Bicep, ARM, plus CI files for GitHub Actions, GitLab CI, Azure Pipelines, Bitbucket, CircleCI and Argo Workflows | Python (attribute checks), YAML (attribute and composite checks) | Over 1,000 built-in policies; graph-based checks across connected resources; secrets and SCA scanning |
Trivy (trivy config) | Aqua Security, active | Terraform, CloudFormation, ARM, Kubernetes, Helm, Dockerfile | Rego, written against a unified cloud structure | Same binary scans images, file systems and repositories for vulnerabilities and secrets; misconfiguration scanning is off by default outside config |
| tfsec | Aqua Security, superseded | Terraform | Carried forward in Trivy | The project asks users to move to Trivy, which now carries the tfsec engine |
| KICS | Checkmarx, active | Terraform, Kubernetes, Docker, CloudFormation and many more platforms | Rego queries | Large query library; check image provenance after the 2026 incident |
| Conftest | Open Policy Agent project | Any structured configuration: Kubernetes, Tekton, Terraform, Serverless and more | Rego | No built-in rule library; you write every policy, which suits organisation-specific rules |
| Terrascan | Tenable, archived | Terraform, Kubernetes and others | Rego | Repository archived and no longer maintained: plan a migration if you still run it |
Commercial platforms often embed one of these engines and add a central policy store, dashboards, enforcement rules and fix suggestions. Checkov's own README notes that it powers Prisma Cloud Application Security. For buying criteria, see the Infrastructure-as-Code Scanning Buyer's Guide.
How Checkov works in practice
Check IDs and policy types
- Check IDs: built-in checks have IDs such as
CKV_AWS_20(S3 bucket must not allow public read) orCKV_K8S_20. Graph checks that evaluate relationships between resources use theCKV2_prefix, for exampleCKV2_AWS_6. Secrets checks useCKV_SECRET_. - Attribute checks test one resource's settings. Graph (composite) checks test connections, such as a bucket with no public access block attached, or a security group attached to a resource with a public IP. Graph checks catch misconfigurations that are invisible when each block is read alone.
- Custom policies: Python classes for attribute checks, or YAML definitions for attribute and composite checks, loaded with
--external-checks-dir. YAML is easier to review and to keep in a central policy repository. - Variables: Checkov evaluates variables to their default values, and
--var-fileloads extra tfvars for source Terraform and Helm scans. Values set only at apply time are invisible to a source scan.
Suppressions and baselines
- Inline suppression: a comment inside the resource block of the form
checkov:skip=<check_id>:<reason>. Kubernetes manifests use annotations of the formcheckov.io/skip1: <check_id>=<reason>. Results show as SKIPPED, with the reason, so they remain auditable. - CLI skips:
--skip-checkaccepts check IDs and wildcards. A wildcard such as every AWS check silently removes whole classes of control, so restrict who can change pipeline flags. - Baselines:
--create-baselinewrites a.checkov.baselinefile with current results (directory scans only);--baselinethen reports only failures that are new compared with it. This is the cleanest way to adopt a scanner on a large existing codebase: block new problems now, burn down old ones over time. - Configuration file: settings can live in
.checkov.yaml, which keeps flags under code review rather than hidden in pipeline variables.
Fail thresholds
| Option | Behaviour (per the CLI reference) | Use it for |
|---|---|---|
--soft-fail | Always exits 0 | Observation phase only |
--hard-fail-on | Non-zero exit for listed check IDs or for severities at or above the lowest listed | Blocking a short list of critical checks |
--soft-fail-on | Exits 0 if only the listed checks or severities fail | Known noisy checks while a fix is planned |
--check / --skip-check | Allow list or deny list of checks; severity values need the platform API key | Scoping a scan to one framework or team |
Output formats include CLI, JSON, JUnit XML, CSV, SARIF, CycloneDX, SPDX, GitLab SAST and GitHub markdown. SARIF is the natural choice for code scanning dashboards; JSON for feeding a findings database.
Source scanning versus plan scanning
| Aspect | Source scan (.tf, templates) | Plan scan (Terraform plan JSON) |
|---|---|---|
| When it runs | Pre-commit, pull request | After terraform plan, before apply |
| Speed and feedback | Fast, line numbers in the developer's file | Slower, needs provider credentials to plan |
| Sees variables and module output | Defaults only, unless var files are supplied | Resolved values |
| Remote modules | Only if downloaded (--download-external-modules) | Included in the plan |
| Suppressions | Inline comments work | Need --repo-root-for-plan-enrichment to map back to files and honour suppressions |
| Secret exposure risk | Low | Plan JSON can contain sensitive values: treat it as a secret |
Use both: source scans for fast developer feedback, plan scans as the merge or apply gate. For the plan step's credentials, see the Terraform and IaC Pipeline Credential Security Guide; plan files and state carry secrets, as covered in How to find secrets in Terraform state.
Writing and testing custom policies
Built-in rules encode general good practice; your own rules encode decisions that only your organisation can make, such as approved Regions, mandatory tags, approved module sources and which roles may be trusted across accounts. Treat these policies as code.
- Give every policy an owner and an ID scheme. Use a prefix that cannot collide with vendor IDs, record the owning team and the risk it addresses, and reference the internal standard it enforces.
- Know each engine's model. Checkov YAML policies describe attribute conditions and connections between resource types. Conftest policies are Rego rules (for example
denyrules that return a message) evaluated against the parsed file. Trivy custom checks are Rego written against a unified structure that its documentation says covers only exported resources and attributes, so a check for an unexported attribute is not possible there. - Test with fixtures. Keep a passing and a failing example for every policy and run them in the policy repository's own pipeline. A policy without a failing fixture may never fire.
- Version and release policies. Publish policy sets as tagged releases that pipelines consume by version, so a broken rule can be rolled back without editing every repository.
- Reuse at runtime where possible. Rego policies written for Conftest can often be shared with admission control in Kubernetes, which keeps pipeline and cluster rules consistent.
Securing the scanner itself
A scanner reads your whole repository, often runs with the pipeline's token, and sometimes downloads modules and policy updates from the internet. That makes it a high-value supply chain target. The Trivy supply chain attack of 2026 turned a widely trusted scanner into a credential stealer after a stolen personal access token and an incomplete rotation, and credentials stolen in that campaign were then used to poison KICS Docker images and VS Code extensions, as described in the Checkmarx KICS supply chain attack page.
- Pin by digest or commit: reference container images by digest and CI actions by full commit SHA, not by mutable tags. The tj-actions/changed-files compromise showed how quickly a retagged action spreads.
- No cloud credentials in source scan jobs: source scans need read access to the repository and nothing else. Keep plan scans in a separate job whose credentials are read-only and short-lived.
- Control outbound access: decide whether the scanner may download external modules and policy metadata. Checkov's
--skip-downloadstops platform downloads; module downloads should come from a private registry or a vetted cache. - Keep results in-house unless agreed: when a scanner is linked to a commercial platform, results and code snippets may be uploaded. Checkov offers
--skip-results-upload; confirm data handling for any engine. - Update deliberately: take new versions through the same review as other dependencies, with a short delay and a changelog check, so a poisoned release does not reach every pipeline at once.
Where identity fits
Identity is where IaC scanning pays back fastest. Wildcard IAM actions, roles trusted by any principal, CI roles with administrator rights, and hard-coded keys in providers, EC2 user data and Lambda environment variables are all detectable before deployment. Checkov's README lists detection of AWS credentials in EC2 user data, Lambda environment variables and Terraform providers. Build a dedicated identity policy set rather than relying on defaults; the IaC identity policy checks guide covers which rules to write.
How to implement
- Inventory IaC and choose the engine. List frameworks in use, existing policy languages (Rego elsewhere favours Trivy or Conftest), and whether you need graph checks. Retire Terrascan and tfsec.
- Run in observation mode. Soft-fail across all repositories for two to four weeks, export JSON results, and find the 10 to 20 checks that matter most to you.
- Create baselines. Generate a baseline per repository so only new failures appear. Commit the baseline and require review for any change that adds entries.
- Gate on critical checks. Hard-fail on the short list (public storage, wildcard IAM, open admin ports, unencrypted databases, hard-coded secrets). Everything else stays soft-fail and visible.
- Add plan scanning at the apply gate. Scan the plan JSON with file enrichment so suppressions carry through; protect the plan artefact as a secret.
- Write custom policies for organisation rules (tagging, approved Regions, approved module sources) in a central repository with tests.
- Widen and roll back safely. Promote checks from soft to hard fail one batch at a time; rolling back means moving a check back to the soft list, not disabling the scanner.
Decision guidance
- Small team, mostly Terraform: one engine in pre-commit and pull requests with built-in rules and a baseline is enough. Add plan scanning when environments diverge.
- Large estate with many frameworks: Checkov or Trivy for breadth, plus Conftest for organisation-specific rules shared with Kubernetes admission control.
- Already using OPA: prefer Rego-based engines so one policy skill set covers pipeline and runtime.
- Two scanners or one: running two engines raises coverage slightly and noise substantially. Use one as the gate and a second only for periodic comparison.
- Scanning or posture management: scanners catch problems before deployment; CSPM catches drift and console changes after. You need both. See the Cloud Security Posture Management (CSPM) Guide.
Detection and measurement
- Coverage: percentage of IaC repositories with a scan on every pull request (target 100%).
- Gate strength: number of checks in hard-fail mode, rising over time.
- Baseline burn-down: entries in baseline files, falling month on month.
- Suppression hygiene: share of inline skips with a reason and a review date (target 100%), and count of wildcard CLI skips (target zero).
- Escape rate: CSPM findings in production that a pipeline scan should have caught, per month.
- Scanner integrity: pipelines referencing the scanner by digest or commit SHA (target 100%).
Common failure patterns
- Permanent soft-fail. The scanner runs, nobody reads the output, and the dashboard says "scanned".
- Suppression by wildcard. A pipeline flag that skips a whole family of checks, added once to unblock a release and never removed.
- Source-only scanning. Misconfigurations set through variables or remote modules pass the scan and reach production.
- Scanner with the keys to the kingdom. A scan job that inherits the deploy role's credentials turns any scanner compromise into a cloud compromise.
- Unmaintained engines. Archived projects stop gaining rules for new cloud services, so coverage decays without anyone noticing.
Framework mapping
| Framework | Reference | How it applies |
|---|---|---|
| NIST SP 800-53 Rev 5 | CM-6, CM-7, SA-11, RA-5, SR-3 | Configuration settings, least functionality, developer testing, scanning, supply chain controls for the scanner |
| NIST CSF 2.0 | PR.PS-01, PR.PS-06, ID.RA-01 | Configuration management, secure development, finding weaknesses |
| CIS Controls v8.1 | 4.1, 16.12 | Secure configuration process, code-level security checks |
| ISO/IEC 27001:2022 | A.8.9, A.8.25, A.8.28, A.8.29 | Configuration management, secure development life cycle, secure coding, security testing |
Practitioner checklist
- Choose one gating engine and retire archived or superseded scanners.
- Scan every IaC pull request and scan Terraform plans at the apply gate.
- Create and commit a baseline per repository; review any additions.
- Hard-fail on a short critical list and widen it each quarter.
- Require a reason and review date on every inline suppression; ban wildcard skips.
- Keep custom policies, including identity rules, in a tested central repository.
- Pin scanner images by digest and actions by commit SHA.
- Run source scans with no cloud credentials and protect plan JSON as a secret.
- Track escape rate against CSPM findings.
Standards and references
- Checkov: project documentation
- Checkov: CLI command reference
- Trivy: Misconfiguration scanning
- Aqua Security: tfsec to Trivy migration
- Checkmarx: KICS project documentation
- Open Policy Agent: Conftest
- Tenable: Terrascan repository (archived)
Related NHI Mgmt Group resources: Infrastructure as Code Security Guide · IaC identity policy checks · Top 10 Infrastructure as Code Misconfigurations · IaC Security Review Checklist · Policy-as-Code for Authorisation Guide