On 14 October 2026 two tools in most infrastructure pipelines shipped releases on the same day: Terraform v1.16.6 and Trivy v0.76.0. The Terraform release notes include a note on CVE-2026-78669, an HTTP/2 resource exhaustion issue that needs a compromised provider or module registry to exploit, and which HashiCorp considers outside the perimeter of Terraform core security guarantees. It is still a good prompt to look at the pipeline that runs these tools on every pull request.
This guide builds a gate that catches misconfigurations before merge, keeps the tool versions pinned, and handles the part teams get wrong: exceptions.
What's affected
Anything that runs terraform init, plan or apply in CI inherits the version of Terraform on the runner. The 1.16.6 release also fixes two bugs: workspaces selected by tags with uppercase keys in terraform init, and module tests that use deprecated outputs. Trivy v0.76.0 is the scanner release used in the examples below. Its highlights are listed in the project's release discussion, and the commands here come from the Trivy documentation rather than from anything new in 0.76.0.
How to check if you're exposed
Find out what version your pipeline actually runs. Add this to the start of the job and read it in a recent log:
terraform version
trivy version
Then check which steps can reach credentials. A plan needs read access to cloud state and APIs, so the runner that scans plans is a more sensitive place than the runner that scans HCL.
What to do now
- Pin Terraform and Trivy in the CI image or installer step. Move to Terraform v1.16.6 on the 1.16 line, and record the version in the job log.
- Scan the code on every pull request, with no credentials needed. Trivy recursively finds and scans Terraform files and evaluates variables and imports:
trivy config --severity HIGH,CRITICAL --exit-code 1 ./infrastructure
- Pass the same variable files you deploy with, so defaults do not hide real values. The Trivy docs show the override flag:
trivy config --tf-vars dev.terraform.tfvars ./infrastructure/tf
- In a second job with read-only cloud access, scan the plan, which sees resolved values and module output. Trivy's Terraform page documents both snapshot and JSON forms:
terraform plan -out tfplan
terraform show -json tfplan > tfplan.json
trivy config --severity HIGH,CRITICAL --exit-code 1 tfplan.json
- Treat the plan file as sensitive. The Terraform docs state that with the JSON flag, sensitive values in state are displayed in plain text. Keep the file in the runner workspace, never upload it as a build artifact, and delete it after the scan.
- Write exceptions in the ignore file with an expiry. Trivy supports a date on an entry, after which the finding returns:
# Accepted until the logging bucket migration lands
AVD-AWS-0089 exp:2026-12-31
- Require a code owner review for any change to the ignore file, so an exception is a visible, reviewed decision.
- Vendor your modules or use a private registry mirror, which also narrows the registry risk in the Terraform note.
How this could have been avoided
This is a hardening guide, so the question is what the CVE note teaches about the pipeline:
- Treat the registry as a trust boundary. The Terraform note says exploitation requires an untrusted provider or module registry. Pin providers with the lock file, and pull modules only from sources you control.
- Pin tool versions, not just providers. An unpinned Terraform on a shared runner means the fix lands when someone rebuilds the image, not when you decide.
- Scan in two places. Code scans catch policy gaps at review time. Plan scans catch values that only exist after variables and modules resolve.
- Keep exceptions short and owned. A permanent ignore line is a finding nobody is looking at.
Why it matters
Infrastructure code is reviewed by people who read diffs, and diffs do not show what a module expands to. A scanner reads the same HCL a machine would and reports what a tired reviewer cannot see.
The weak points are rarely the rules. They are the credentials on the runner, the unpinned versions, and the ignore file nobody revisits. Fix those and the gate stays useful.
Try it yourself
Take one Terraform repository and run the code scan locally with the severity filter. Fix or ignore each finding, giving every ignore an expiry date under 90 days out. Then open a pull request that adds a public bucket on purpose and confirm the job fails. See how a pull request gate looks end to end.
Click through it at your own pace, or open it full screen.
Quick check
Why should a Terraform plan file not be uploaded as a build artifact?
The JSON form can show sensitive values in plain text, so the file should stay in the runner workspace and be deleted after scanning.
What does the exp date on a Trivy ignore entry do?
The finding is ignored until that date and then reported again.