PCI-DSS 4.0 Req 2.1 requires that all default passwords and unnecessary default accounts are removed before system components enter production. Req 8.3 mandates strong authentication for all users. Hardcoded credentials — postgres:postgres in a Dockerfile, sk_live_ keys in a .env committed to git — are the lowest-effort, highest-yield targets for attackers. CWE-798 (Use of Hard-coded Credentials) and CWE-1188 (Initialization with Default Value) are both directly exploitable. OWASP A05 (Security Misconfiguration) rates this category as endemic. A leaked Stripe live key means unauthorized charges or refunds; a leaked DB admin password means direct CDE access.
Critical because a hardcoded live credential found in a public or semi-public repository enables immediate unauthorized access to payment systems or the database with no additional exploitation needed.
Replace every hardcoded value with an environment variable reference and add those variable names to .gitignore-protected .env.local. Use a secrets manager (AWS Secrets Manager, Supabase Vault) in production — no secret should exist anywhere in the codebase, even in git history.
# Before (fails Req 2.1)
ENV POSTGRES_PASSWORD=postgres
# After
ENV POSTGRES_PASSWORD=${DB_PASSWORD}
For Terraform, use var.db_password sourced from a tfvars file that is git-ignored, or use aws_secretsmanager_secret_version as the password source. Audit git history with git log -S 'sk_live_' to confirm secrets were never committed.
ID: ecommerce-pci.cardholder-data.no-default-credentials
Severity: critical
What to look for: Enumerate all infrastructure files that could contain credentials: Dockerfile, docker-compose.yml, Terraform configs, CloudFormation templates, database init scripts, and .env files committed to version control. For each file, count every hardcoded credential pattern: postgres:postgres, root:root, admin:admin, sa:password, password=, SECRET_KEY=sk_live_, or any literal password/key value (not a ${VAR} reference). Before evaluating, quote the actual credential lines found.
Pass criteria: Exactly 0 default or hardcoded credentials found across all infrastructure files examined. All credentials (at least 1 must exist) are sourced from environment variable references (${VAR}, process.env.VAR, var.name) or secure secret management services. Report: "Scanned X files, found 0 hardcoded credentials, Y environment variable references."
Fail criteria: At least 1 hardcoded username/password or API key found in infrastructure configs, Dockerfile, or application code. Do NOT pass when credentials appear as defaults with an override option (e.g., POSTGRES_PASSWORD=${DB_PASS:-postgres} still contains a hardcoded fallback).
Skip (N/A) when: No infrastructure files exist (no Dockerfile, no docker-compose, no Terraform, no CloudFormation, no .env files — fully managed PaaS with no credential configuration).
Detail on fail: List all locations where default credentials were found. Example: "docker-compose.yml line 8 contains POSTGRES_PASSWORD=postgres. Dockerfile line 12 contains ENV STRIPE_SECRET_KEY=sk_live_hardcoded. 2 hardcoded credentials found in 2 files."
Remediation: Remove all default credentials and replace with environment variables. Example:
# Before (insecure)
ENV POSTGRES_USER=postgres
ENV POSTGRES_PASSWORD=postgres
# After (secure)
ENV POSTGRES_USER=${DB_USER}
ENV POSTGRES_PASSWORD=${DB_PASSWORD}
# docker-compose.yml
services:
db:
environment:
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: ${DB_NAME}
For Terraform:
resource "aws_db_instance" "main" {
username = var.db_username # from tfvars, not hardcoded
password = random_password.db.result
}
Use a secrets manager (AWS Secrets Manager, Supabase Vault, GitHub Secrets) for production credentials. Never commit secrets to version control — use .gitignore and .env.local.