I built a scanner that guesses S3 bucket names and looks for .tfstate files. Terraform state is a JSON file that happens to contain all your secrets because that is how Terraform works. I ran it for three days on a cheap VPS and found 900 state files. 40 of them had raw AWS keys sitting in plaintext. I could not find a single person to report this to at any of these companies.
Why I even started this
I got into bug bounty last year and kept hitting walls. Companies with no security contact, auto-responders that go nowhere, reports that sit unread for months. I wanted to find something where the impact was obvious and the companies could not ignore it. Terraform state files kept coming up in writeups. People treat them like config files but they are actually secret vaults.
By default, terraform.tfstate contains everything including resource IDs, connection strings, and if you ever used aws_iam_access_key resources, the actual secret keys. Terraform warns you about this but nobody reads warnings.
How my scanner works
I call it tfstate-scanner.
The seed wordlist comes from Crunchbase company names, DNS certificate transparency logs, and GitHub repo names. Then it permutes them into common patterns like {name}-terraform, {name}-tfstate, {name}-infrastructure, and {name}-devops.
It checks if {permutation}.s3.amazonaws.com resolves and if it does, it sends a HEAD request to /{permutation}/terraform.tfstate. If that returns 200, it parses the JSON for aws_access_key_id, password, private_key, and connection_string.
That is the whole thing. It only looks at what is already public.
When I ran it
I ran it for 72 hours on a $20 per month VPS. I kept it at 10 requests per second because I was not trying to DDoS anyone.
| Metric | Number |
|---|---|
| Bucket permutations checked | 4,200 |
Valid .tfstate files found | 912 |
| Parseable JSON | 847 |
| Live AWS key pairs | 41 |
| Azure Service Principal secrets | 12 |
| GCP service account keys | 3 |
I spot-checked 5 AWS keys and all of them were valid. One belonged to a healthcare company with 2 million patient records. Another belonged to a fintech processing $400M a year. I checked they worked with aws sts get-caller-identity and then I closed the terminal.
What I built instead of reporting
None of these companies had a security contact. I tried security@, abuse@, and support@. They all bounced or sent auto-responders.
I could have reported to AWS Abuse but they just suspend accounts with no remediation path. The company wakes up to a dead AWS account and no idea why. That does not help anyone fix anything.
So I built something else instead.
I made terraform-state-guardian, a free GitHub Action that catches this before it happens. It scans your repo history for committed .tfstate files using git log --all -- '*.tfstate'. It checks if your S3 backend bucket is publicly listable. It validates that terraform { backend "s3" { encrypt = true } } is actually set. And it fails the CI build if state files are committed or encryption is missing.
I open-sourced it and it got 3,400 stars in a week.
The healthcare company, the one with 2 million patient records, found it on GitHub and ran it. They discovered 6 other exposed buckets I had not even hit. They emailed me a thank-you. No bounty came out of it. They just fixed it and said thanks. I will take that.
The thing that still bugs me
AWS does not tell you when your bucket is being scanned. I hit 4,200 bucket permutations and nobody got an alert. There is no CloudTrail event for someone checking if your bucket exists. There is no GuardDuty signal for repeated HEAD requests on .tfstate files. You only find out when someone worse than me finds it first.