← Back to Terraform Plan Secret Exposure Check
sensitive flagTerraform marks an attribute's value sensitive in two places: the provider's own schema (Sensitive: true on the field definition in the provider's Go source) and, for a value that flows in from a variable or another resource, propagated sensitivity through the graph. When either is set, terraform plan's human-readable output and the JSON from terraform show -json both replace the value with (sensitive value) or mark the corresponding path in before_sensitive/after_sensitive as true.
That only works if the schema author remembered to mark the field. It is a manual annotation on every attribute of every resource a provider exposes, and providers expose thousands of them. HashiCorp's own tracker carries recurring reports of exactly this gap: a provider adds a new attribute that can hold a credential -- a connection string, a generated password, a private key -- and it prints in plaintext until someone notices and files a fix (see, for example, hashicorp/terraform#16554, #26185, and #27577 for three separately-reported instances of this same shape of bug).
A missed sensitive flag does not just affect the terminal running terraform apply interactively. The same value prints into:
terraform show -json tfplan) committed by mistake, or attached to a support ticket when someone shares "the plan output" to debug an issue.That is a much wider audience than the apply itself ever reaches, which is what makes a missed flag more consequential than the underlying credential simply existing in state (state has its own, separate handling and risks).
Rather than trying to guess which fields "look important", this checks every string value left in the plan (after Terraform's own sensitivity marks are respected) against four fixed, high-confidence patterns:
AKIA/ASIA-style 20-character prefix format AWS itself uses.-----BEGIN ... PRIVATE KEY----- header used by RSA, EC, OpenSSH, and other key formats.scheme://user:pass@host connection string, the shape a database or message-queue URL takes when the password is inlined rather than passed separately.These were chosen over a generic "random-looking string" heuristic on purpose: a fixed format has an extremely low false-positive rate (an AMI ID, a hash, or a UUID does not coincidentally match an AWS key prefix), so a flag from this tool is worth acting on rather than something to learn to ignore. The cost is that a secret in a shape none of these four match will not be caught -- this is one gate, not a guarantee.
This is not a Terraform state scanner, a secrets-manager audit, or a policy engine like Sentinel or OPA. It reads exactly one file -- the structured plan JSON you already have from your own terraform show -json -- and reports pattern matches against unmarked values in it. It makes no claim about your state file, your provider's source code, or whether a value it does not flag is actually safe.
Because sensitivity is a manual annotation the provider's schema author adds to each attribute, not something Terraform can infer from a value's shape at plan time. Thousands of attributes across hundreds of providers means misses are a documented, recurring bug class rather than a rare edge case.
No. The same plaintext value prints into whatever CI log captured the plan step, a bot's pull-request comment, or a saved plan file shared to debug an issue — a much wider audience than the apply itself ever reaches.
A fixed format — an AWS key prefix, a PEM header, a JWT's three dot-separated segments, a URL's embedded credentials — has an extremely low false-positive rate, so a flag is worth acting on. A generic random-string heuristic would flag AMI ids, hashes, and UUIDs constantly and teach people to ignore the report.