Infra Audit6 min readUpdated November 4, 2026

Your Terraform State File Is a Plaintext Credential Store

In the SCARLETEEL incident, one state file in an S3 bucket exposed a key to a second AWS account. A researcher found 900 public state files, 41 with live credentials.

terraform.tfstate records every attribute of every resource in plaintext, including passwords and private keys. The sensitive flag is display-only. Check where your state lives and who can read it.

State is a JSON snapshot of every managed resource's full attribute set: what the provider returned after apply. A random_password resource lands in state. An aws_db_instance master password lands in state. A tls_private_key resource writes the full private key. An aws_iam_access_key writes the secret.

What is actually in the file

State is a JSON snapshot of every managed resource's full attribute set: what the provider returned after apply. A random_password resource lands in state. An aws_db_instance master password lands in state. A tls_private_key resource writes the full private key. An aws_iam_access_key writes the secret.
State is a JSON snapshot of every managed resource's full attribute set: what the provider returned after apply. A random_password resource lands in state. An aws_db_instance master password lands in state. A tls_private_key resource writes the full private key. An aws_iam_access_key writes the secret. One file is a census of every secret the stack ever touched, which is why a single leak often crosses account boundaries.

The SCARLETEEL chain

Sysdig documented an attacker who compromised a container, escalated into the AWS account, and found a terraform.tfstate in an S3 bucket the role could read. Inside: an IAM access key and secret for a second, connected account. One file turned a contained incident into a multi-account breach. No Terraform bug involved.
Sysdig documented an attacker who compromised a container, escalated into the AWS account, and found a terraform.tfstate in an S3 bucket the role could read. Inside: an IAM access key and secret for a second, connected account. One file turned a contained incident into a multi-account breach. No Terraform bug involved. The file did exactly what state files do.

The scale of the leak

A researcher who spent three days scanning likely bucket names found about 900 publicly exposed state files, 41 containing live AWS credentials valid enough to authenticate. The method needs no credentials and produces no alert, because S3 has no anomaly detection for unauthenticated enumeration of already-public buckets.
A researcher who spent three days scanning likely bucket names found about 900 publicly exposed state files, 41 containing live AWS credentials valid enough to authenticate. The method needs no credentials and produces no alert, because S3 has no anomaly detection for unauthenticated enumeration of already-public buckets.

The audit check

Find every backend declaration in the code. Local backend: check the file for secret-shaped strings and report shapes, never values. S3 backend: check the bucket policy, public access block, and whether state locking is on. Git: run git log --all --full-history -- '*.tfstate' and treat any hit as a rotation event, not a cleanup task.
Find every backend declaration in the code. Local backend: check the file for secret-shaped strings and report shapes, never values. S3 backend: check the bucket policy, public access block, and whether state locking is on. Git: run git log --all --full-history -- '*.tfstate' and treat any hit as a rotation event, not a cleanup task. Every secret that ever entered a state file is treated as exposed.

4 Tips to Get Started

1

Never commit .tfstate to git. Add it to .gitignore before the first terraform init, not after.

2

Deleting the file does not help: git history keeps it. git log --all --full-history -- '*.tfstate' pulls it back.

3

Use a remote backend with encryption and a locked-down bucket policy. encrypt=true does not fix a public bucket.

4

Terraform 1.10+ ephemeral values and 1.11 write-only arguments keep new secrets out of state. Old state still needs rotation.

Ready to Stop Worrying About Infra?

Knowledge is the first step. Get a free 1-hour diagnostic and see where your infrastructure leaks time, money, and focus.

R

Ron Cohen — DevOps engineer & founder, roqy.io

Content reviewed by the roqy.io team. Our guides are based on publicly available data.

Disclaimer: This content is for informational and educational purposes only. It does not constitute professional advice or a guarantee of specific results. Infrastructure needs vary by team, stack, and stage. Consult a qualified engineer for advice tailored to your situation.

Frequently Asked Questions

What is a Terraform state file leak?

terraform.tfstate records every attribute of every managed resource, including database passwords, IAM secret keys and TLS private keys, in plaintext. The sensitive = true flag only hides values from terminal output, not from the file. In the SCARLETEEL incident one state file exposed a key to a second AWS account.

Does sensitive = true encrypt state?

No. It redacts the value from CLI output and plan diffs. The JSON on disk, in S3 or in Terraform Cloud still holds the plaintext. HashiCorp documents this. Anyone who can read the state file reads every secret with terraform show or jq.

How do attackers find state files?

They guess bucket names from crt.sh subdomains plus patterns like -terraform-state and -tfstate, and send unauthenticated HEAD requests. They search GitHub for filename:terraform.tfstate. No credentials needed, and S3 has no anomaly detection for public bucket enumeration.

Get the DevOps Ecosystem Behind You

One accountable engineer. Full platform behind him. Month-to-month, no lock-in.