# IaC files have no hardcoded secrets

- **Pattern:** `ab-001269` (`environment-security.configuration-security.iac-no-secrets`)
- **Severity:** low
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-001269
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-001269)

## Why it matters

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.

## Severity rationale

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.

## Remediation

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.

```hcl
# 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.

## Detection

- **ID:** `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:

  ```hcl
  # 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:
  ```hcl
  data "aws_secretsmanager_secret_version" "stripe" {
    secret_id = "stripe-api-key"
  }
  ```

## External references

- cwe CWE-798
- owasp A05
- ssdf PW.6

Taxons: cryptography-and-secrets, operational-readiness

HTML version: https://auditbuffet.com/patterns/ab-001269
