Infrastructure-as-Code files are source code: they are version-controlled, shared with teams, reviewed in pull requests, and often mirrored on GitHub. A Terraform file containing a hardcoded database password or a CloudFormation template with an embedded API key exposes those credentials to everyone with repository access and permanently records them in git history. CWE-798 applies directly to IaC secrets. OWASP A05 covers misconfigured infrastructure. SSDF PW.6 requires protecting code from unauthorized disclosure, which IaC with embedded secrets violates by definition.
Low because IaC files are versioned and broadly accessible, meaning a hardcoded secret in a Terraform file exposes credentials to the entire development team and any future repository clone.
Replace every hardcoded credential in IaC files with a variable marked sensitive = true or a direct secrets manager reference. Never pass secrets through Terraform output values unless they are also marked sensitive.
# BEFORE (wrong)
resource "aws_db_instance" "main" {
password = "my-real-db-password"
}
# AFTER (correct) — variable with sensitive flag
variable "db_password" {
type = string
sensitive = true
}
resource "aws_db_instance" "main" {
password = var.db_password
}
# AFTER (correct) — secrets manager reference
data "aws_secretsmanager_secret_version" "db" {
secret_id = "prod/db-password"
}
resource "aws_db_instance" "main" {
password = jsondecode(data.aws_secretsmanager_secret_version.db.secret_string)["password"]
}
Pass variable values via TF_VAR_db_password environment variables in CI, never via -var flags that appear in shell history.
ID: environment-security.configuration-security.iac-no-secrets
Severity: low
What to look for: Check Terraform, CloudFormation, CDK, or Pulumi files for hardcoded secrets. Look for API keys, database passwords, private keys, or tokens in .tf, .yaml, .yml, .json files.
Pass criteria: Count all IaC files (.tf, .yaml, .yml, .json in infrastructure directories). 0% of IaC files may contain hardcoded credentials -- all sensitive values must use variable references or secrets manager references.
Fail criteria: Hardcoded API keys, passwords, tokens, or private keys in IaC files.
Skip (N/A) when: The project does not use IaC (infrastructure as code).
Detail on fail: "Terraform file contains hardcoded database password" or "CloudFormation includes API key in resource definition".
Remediation: Move secrets to variables or secrets manager:
# BEFORE (wrong)
resource "aws_api_key" "stripe" {
key = "sk_live_51234567890"
}
# AFTER (correct)
variable "stripe_api_key" {
type = string
sensitive = true
}
resource "aws_api_key" "stripe" {
key = var.stripe_api_key
}
Or reference a secrets manager:
data "aws_secretsmanager_secret_version" "stripe" {
secret_id = "stripe-api-key"
}