# Checkov Cheat Sheet

> **Tool:** Checkov
> **Category:** Security & Compliance
> **Verified against:** Checkov 3.3.15, flags verified via `checkov --help` run locally, 2026-08-29
> **Official docs:** https://www.checkov.io/1.Welcome/What%20is%20Checkov.html

## What it is and where it fits 🎯

Checkov is the broadest IaC static analyzer in this series — unlike tfsec (Terraform-only), it covers
Terraform, CloudFormation, Kubernetes manifests, Helm, Dockerfiles, Ansible, ARM/Bicep, Serverless Framework,
GitHub Actions/GitLab CI pipeline definitions, and more, from one tool. It also blurs into SCA territory:
`--framework sca_package`/`sca_image` runs dependency and image vulnerability checks alongside the pure
misconfiguration checks, which is functionality that overlaps with Snyk/Trivy/Grype elsewhere in this set.

## Installation

```bash
pipx install checkov          # isolated, recommended if you manage multiple Python CLI tools
pip3 install checkov          # official docs' primary method
brew install checkov          # macOS/Linux Homebrew

checkov --version
```

> [!WARNING]
> **CKV2 (graph-based) checks don't run under the Homebrew build** — only under pip/pipx. If Checkov seems to
> be missing checks you'd expect (cross-resource checks that require understanding relationships between two
> Terraform blocks, not just one in isolation), confirm you're not on the Homebrew install before assuming
> the check doesn't exist.

## Core concepts ⚙️

- **Framework** — the IaC/config type being scanned (`terraform`, `kubernetes`, `dockerfile`, `sca_package`,
  ...). A single `checkov -d .` run auto-detects and scans every framework present in the directory.
- **CKV vs BC check IDs** — `CKV_AWS_20` is a Checkov-native check id; `BC_AWS_GENERAL_20` is the same check's
  id on the Bridgecrew/Prisma Cloud platform. Both refer to the same underlying rule; `--output-bc-ids` swaps
  which id format is shown, useful when cross-referencing platform findings against local CLI output.
- **Graph checks (CKV2)** — checks that need Checkov's dependency graph of the whole IaC tree, not just one
  resource block in isolation (e.g., "is this security group referenced anywhere with an overly permissive
  ingress rule attached").

## Scanning

```bash
checkov -d .                                  # scan a directory recursively, auto-detect all frameworks present
checkov -f main.tf                            # scan a single file
checkov -d . --framework terraform             # limit to one framework
checkov -d . --framework terraform,secrets
checkov -d . --skip-framework sca_package      # e.g. skip the slower dependency-scanning framework
```

## Filtering checks

```bash
checkov -d . --check CKV_AWS_20                          # run only this check
checkov -d . --check HIGH,CRITICAL                        # or filter by severity
checkov -d . --skip-check CKV_AWS_8,CKV_AWS_20
checkov -d . -c CKV_AWS_20 --skip-check LOW                # combine include + exclude (include list applied first, then exclusions)
```

Inline suppression, directly above the resource:

```hcl
#checkov:skip=CKV_AWS_20:"reason this is an accepted exception"
resource "aws_s3_bucket" "example" {
  # ...
}
```

## CI gating

```bash
checkov -d . --soft-fail                       # always exit 0 — reporting only
checkov -d . --hard-fail-on HIGH,CRITICAL       # non-zero exit only for these severities, everything else soft
checkov -d . --soft-fail-on LOW                  # inverse: only LOW is non-blocking
```

> [!NOTE]
> Default (no `-s`/`--hard-fail-on`/`--soft-fail-on`) is a hard fail on **any** finding — non-zero exit
> whenever a single check fails, regardless of severity. Same "fails by default" behavior as tfsec, the
> opposite of Trivy/Grype's "reports by default" behavior — worth knowing before wiring three different
> scanners into one pipeline and being surprised only one of them blocked the build.

## Output formats

```bash
checkov -d . -o json --output-file-path console,results.json     # multiple outputs, one to console + one to a file
checkov -d . -o sarif                                              # for GitHub code scanning
checkov -d . -o cyclonedx_json                                     # SBOM-shaped output for the sca_package/sca_image frameworks
checkov -d . --compact                                             # hide code snippets in CLI output
checkov -d . --quiet                                                # only show failed checks
```

Sample output shape (illustrative — actual check counts/IDs depend entirely on the scanned IaC):

```
terraform scan results:

Passed checks: 20, Failed checks: 3, Skipped checks: 0

Check: CKV_AWS_18: "Ensure the S3 bucket has access logging enabled"
	FAILED for resource: aws_s3_bucket.example
	File: /main.tf:3-8
	Guide: https://docs.bridgecrew.io/docs/s3_13-enable-logging

		3 | resource "aws_s3_bucket" "example" {
		4 |   bucket = "my-bucket"
		5 | }
```

## Baselining existing findings 💡

```bash
checkov -d . --create-baseline               # snapshot current findings into .checkov.baseline
checkov -d . --baseline .checkov.baseline      # only report NEW findings vs. the baseline
```

> [!TIP]
> **This is the practical way to adopt Checkov on a large pre-existing codebase without a wall of noise on
> day one.** Baseline the current state, wire the baseline-diff mode into CI immediately, and tackle the
> backlog on its own timeline — new misconfigurations still get caught right away, existing debt doesn't
> block anyone.

## Listing available checks

```bash
checkov --list                                # every built-in check, by ID and framework
```

## Real-world scenario: scanning a Dockerfile alongside its Terraform

A service's IaC repo often has both the infrastructure definition and the Dockerfile in one place. Checkov's
multi-framework auto-detection means one invocation covers both without separate tool invocations:

```bash
checkov -d . --framework terraform,dockerfile,secrets
```

This single command catches a misconfigured S3 bucket, a Dockerfile running as root, and a hardcoded secret
in the same pass — a genuinely useful "first thing to run against a new service repo" default.

## Real-world scenario: GitHub Actions CI recipe

```yaml
# .github/workflows/checkov.yml
name: Checkov
on: [pull_request]
jobs:
  checkov:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: bridgecrewio/checkov-action@master
        with:
          directory: .
          framework: terraform,dockerfile,kubernetes
          output_format: sarif
          output_file_path: reports/results.sarif
          soft_fail: false
      - uses: github/codeql-action/upload-sarif@v3
        if: always()
        with:
          sarif_file: reports/results.sarif
```

## Common pitfalls

- **Installing via Homebrew and losing CKV2 checks silently** — see the WARNING above.
- **Assuming "fails by default"** applies elsewhere — it's the opposite of Trivy/Grype.
- **Not scoping `--framework`** on a very large multi-purpose repo — an unscoped `checkov -d .` on a monorepo
  with unrelated non-IaC content can be noticeably slower than necessary; narrow the framework list to what's
  actually present.

## Exit codes

`0` clean, or `--soft-fail` set · non-zero when a check fails and isn't soft-failed.

## When to reach for something else

For pure Terraform, tfsec/`trivy config` are lighter-weight and faster. Checkov's advantage is genuine
multi-framework breadth (Ansible, Bicep, Serverless Framework specifically) that neither of those cover —
reach for Checkov when the IaC footprint spans more than Terraform/Kubernetes/CloudFormation/Dockerfile.
