Three tools have now run against the Range's Terraform: Checkov found 26, tfsec 14, trivy config 11. A fourth opinion on an artefact you already know this well is worth more than a first opinion on a new one — you can tell immediately whether a difference is a real gap or a naming difference.
Snyk also returned 11. That is the most misleading number in this track.
Verified against Snyk CLI 1.1306.3, org
jaybilgaye, against the Range Terraform. Output copied from a real run.
Step 1 — Run it
brew install snyk-cli
snyk auth # opens a browser; do not paste a token
git clone https://github.com/jaybilgaye/aiopsone-range
cd aiopsone-range
snyk iac test terraform/Test Summary
Organization: jaybilgaye
Project name: jaybilgaye/aiopsone-range
✔ Files without issues: 1
✗ Files with issues: 1
Total issues: 11 [ 0 critical, 4 high, 3 medium, 4 low ]Zero criticals, on Terraform that declares a public S3 bucket, a security group open to the internet in both directions, and an IAM policy granting full administrative rights.
snyk auth opens a browser and stores the token for you. Do not paste an API token into a terminal you are recording, and do not export SNYK_TOKEN= in a shell whose history is saved.
Step 2 — The eleven
snyk iac test terraform/ --json-file-output=snyk-iac.json| Severity | ID | Finding |
|---|---|---|
| high | SNYK-CC-TF-95 |
S3 block public ACLs disabled |
| high | SNYK-CC-TF-96 |
S3 block public policy disabled |
| high | SNYK-CC-TF-97 |
S3 ignore public ACLs disabled |
| high | SNYK-CC-TF-98 |
S3 restrict public bucket disabled |
| medium | SNYK-CC-TF-1 |
Security Group allows open ingress |
| medium | SNYK-CC-TF-1 |
Security Group allows open ingress |
| medium | SNYK-CC-TF-119 |
IAM Policy grants full administrative rights |
| low | SNYK-CC-TF-45 |
S3 server access logging disabled |
| low | SNYK-CC-TF-124 |
S3 bucket versioning disabled |
| low | SNYK-CC-TF-127 |
S3 bucket MFA delete disabled |
| low | SNYK-CC-TF-73 |
Security Group allows open egress |
Step 3 — Same total, different set
Match Snyk's eleven against Trivy's eleven by what they actually describe:
| Finding | Trivy | Snyk |
|---|---|---|
| S3 block public ACLs | AWS-0086 |
TF-95 |
| S3 block public policy | AWS-0087 |
TF-96 |
| S3 ignore public ACLs | AWS-0091 |
TF-97 |
| S3 restrict public bucket | AWS-0093 |
TF-98 |
| S3 access logging | AWS-0089 |
TF-45 |
| S3 versioning | AWS-0090 |
TF-124 |
| SG open ingress ×2 | AWS-0107 |
TF-1 |
| SG open egress | AWS-0104 |
TF-73 |
| S3 encryption uses CMK | AWS-0132 |
— absent — |
| SG rule missing description | AWS-0124 |
— absent — |
| IAM full administrative rights | — absent — | TF-119 |
| S3 MFA delete disabled | — absent — | TF-127 |
Nine shared. Two unique to each. Identical totals.
If you had run only the totals — 11 and 11 — you would have concluded the tools agree and that swapping one for the other is free. It is not: each is blind to two things the other sees, and one of those is full administrative IAM access.
This is why the Grype versus Trivy lesson insisted on comparing the set difference rather than the count. Here the counts are not merely uninformative, they are actively misleading. Two tools agreeing on a number is not two tools agreeing.
Step 4 — Now put all four side by side
checkov -d terraform/ --compact
tfsec terraform/
trivy config terraform/
snyk iac test terraform/| Total | Open ingress | Open egress | IAM full admin | |
|---|---|---|---|---|
| Checkov 3.2 | 26 | flagged | flagged | flagged |
| tfsec 1.28.14 | 14 | CRITICAL | CRITICAL | HIGH |
| trivy config 0.72.0 | 11 | HIGH | CRITICAL | not checked |
| Snyk IaC 1.1306.3 | 11 | MEDIUM | LOW | MEDIUM |
Read the egress column. The identical line of Terraform is CRITICAL to two tools and LOW to a third.
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"] # everything, anywhere
}Neither rating is indefensible. Unrestricted egress is how data leaves during an exfiltration and how a compromised host reaches a command-and-control server — that is the CRITICAL argument. It is also the default in most AWS accounts and in the majority of Terraform ever written, and a tool that pages you for the default configuration gets muted — that is the LOW argument.
The same split appears on ingress: CRITICAL, HIGH, MEDIUM across three tools.
Severity is a vendor's opinion, not a property of your infrastructure. Every one of these tools is calibrated against an imagined median user who is not you. A gate written as
--severity CRITICALis not a risk threshold; it is a bet that your scanner's product team shares your risk appetite.
Step 5 — What this does to your gate
Take one policy — "block the build on CRITICAL" — and apply it to all four:
- tfsec: blocks on the security group. Two criticals.
- trivy config: blocks on egress only. One critical.
- Snyk IaC: blocks on nothing. Zero criticals in this entire file.
- Checkov: does not use a critical band at all, so the policy does not translate.
Same infrastructure, same intent, four different outcomes — including one pipeline that is green on a public bucket, an open security group, and full-admin IAM.
Gate on findings you have decided matter, named explicitly, rather than on a severity band you do not control:
# .github/workflows/iac.yml
- name: Snyk IaC
run: |
snyk iac test terraform/ \
--severity-threshold=medium \
--report # sends results to the Snyk UI
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}--severity-threshold=medium is what it takes to catch the IAM policy here, and it is a decision you have to make per tool. A threshold copied between scanners does not mean the same thing on the other side.
Step 6 — Where Snyk IaC earns its place
Findings are the commodity; four tools produce them and largely overlap. Two things here are not commodity:
It found MFA delete. SNYK-CC-TF-127 appears in none of the other three. Bucket versioning without MFA delete means an attacker with the credentials can permanently remove objects — the exact control that separates "we have versioning" from "we have a recoverable bucket" in a ransomware scenario. That is a genuinely good check.
--report puts the result somewhere durable. The finding goes to the Snyk UI with a project, an owner and a history, rather than into CI output that expires with the log. That is the same argument the GitGuardian lesson made about incident state, and it is the same reason it matters for CPS 234: the auditable artefact is the record of assessment and remediation, not the scan.

This is what --report produces: terraform/broken.tf recorded with its 4 high, 3 medium, 4 low — the same eleven the CLI printed — and terraform/main.tf clean, each timestamped and owned. A terminal prints once and scrolls away; this persists, and that persistence is the product. When an assessor asks "when did you last scan this Terraform, and what was open", the answer is a page, not a grep through CI logs.
Against that: it is the only one of the four that needs an account, sends your configuration to a hosted service, and consumes a monthly test allowance on the free tier.
The recommendation from this track does not change: Checkov owns the IaC gate. It found 26 where the others found 11–14, it is actively maintained, and it flags the wildcard IAM policy that Trivy cannot see. Run Snyk alongside it if you want the MFA-delete class of check and a durable record — not instead of it.
What you learned
- Snyk IaC and
trivy configboth reported 11 — and only 9 were the same. Two blind spots each. Equal totals are not agreement. - Snyk reported zero criticals on Terraform with a public bucket, an open security group and full-admin IAM.
- Unrestricted egress: CRITICAL to tfsec and Trivy, LOW to Snyk. Ingress spans CRITICAL / HIGH / MEDIUM across three tools.
- Snyk does flag the IAM wildcard (
TF-119, medium) that Trivy has no check for — and is the only one of four to flag S3 MFA delete. - A
--severity CRITICALgate is a bet on a vendor's calibration. The same policy blocks twice, once, or never depending on which tool you picked. - Gate on named findings and a threshold you set per tool. Thresholds do not port between scanners.
- Checkov still owns the gate. Snyk adds a check class and a durable record, not a replacement.