AWS CloudFormation Credential Exposure: Extracting Secrets from Stack Templates
Theory
Why This Matters
In 2020, multiple organizations discovered that their CloudFormation stack templates — stored in S3 and accessible via the CloudFormation API — contained plaintext database passwords, API keys, and IAM user credentials that had been hardcoded during initial infrastructure deployments years earlier. Security researchers scanning exposed S3 buckets routinely find .template and .json CloudFormation files with credentials in UserData bootstrap scripts or Parameters default values. Because CloudFormation stores the full rendered template (including parameter values) in the stack's event history and in S3, a single overly-permissive IAM policy or public bucket exposes every secret ever passed to that stack — including secrets that have since been rotated in the application but remain visible in the deployment artifact.
Core Concept
AWS CloudFormation is the Infrastructure-as-Code service that provisions AWS resources from declarative JSON or YAML templates. Templates have several sections where secrets commonly appear: Parameters (the Default field stores the value in plaintext), Metadata (arbitrary key-value pairs often used to pass configuration), and UserData (base64-encoded bootstrap scripts that frequently contain export DB_PASSWORD=... or aws configure set commands).
CloudFormation stores templates in two durable locations: an S3 bucket specified at deploy time (or an auto-created bucket prefixed cf-templates-), and the stack's internal storage accessible via GetTemplate. Stack Events and Outputs can also expose secret values — a template that outputs a generated password or an IAM access key created by the stack will show those values in the Outputs section indefinitely.
NoEcho is the CloudFormation parameter attribute that masks a parameter value in the console and API — it is not encryption, it is masking. The value is still stored in plaintext; it is simply not returned in describe-parameters calls. An attacker with cloudformation:GetTemplate bypasses NoEcho entirely by reading the raw template.
The correct remediation pattern is to store secrets in AWS Secrets Manager or AWS Systems Manager Parameter Store (SecureString), then reference them in the template as dynamic references ({{resolve:secretsmanager:MySecret:SecretString:password}}) — the secret value is never written into the template document.
Technical Deep-Dive
# List all CloudFormation stacks in the current region
aws cloudformation list-stacks
--stack-status-filter CREATE_COMPLETE UPDATE_COMPLETE
--query 'StackSummaries[*].{Name:StackName,Status:StackStatus,Created:CreationTime}'
--output table
# Retrieve the full template for a stack (bypasses NoEcho — full parameter values visible)
aws cloudformation get-template --stack-name TargetStack
--query 'TemplateBody' --output text > stack_template.json
# Scan the template for common secret patterns
grep -Ei 'password|passwd|secret|apikey|api_key|token|credential|private_key'
stack_template.json
# List stack parameters — DefaultValue shown even for NoEcho params in some API versions
aws cloudformation describe-stacks --stack-name TargetStack
--query 'Stacks[0].Parameters[*].{Key:ParameterKey,Value:ParameterValue}'
--output table
# List stack outputs — may contain access keys, generated passwords, connection strings
aws cloudformation describe-stacks --stack-name TargetStack
--query 'Stacks[0].Outputs[*].{Key:OutputKey,Value:OutputValue}'
--output table
# Enumerate auto-created CF template S3 buckets (prefixed cf-templates-)
aws s3 ls | grep cf-templates-
# Download and scan all templates from the CF template bucket
BUCKET="cf-templates-ACCOUNTID-REGION"
aws s3 sync s3://${BUCKET}/ ./cf_templates/ --no-sign-request 2>/dev/null ||
aws s3 sync s3://${BUCKET}/ ./cf_templates/
# Run truffleHog on downloaded templates
trufflehog filesystem ./cf_templates/ --json |
python3 -c "import sys,json; [print(json.dumps(r,indent=2)) for r in
(json.loads(l) for l in sys.stdin) if r.get('Verified')]"
Security Assessment Methodology
- Enumerate all stacks. Run
aws cloudformation list-stackswith all non-deleted status filters. Note creation dates — older stacks are more likely to predate Secrets Manager adoption and contain hardcoded values. - Retrieve templates and scan for secrets. For each stack, call
GetTemplateand run truffleHog or gitleaks against the output. Pay particular attention toUserDatafields (base64-decode them first) andParameters.Defaultvalues. - Check stack outputs and events.
describe-stacksOutputs section may contain generated credentials. Stack events (describe-stack-events) can show parameter values that were passed at creation time and logged beforeNoEchowas respected. - Enumerate the CF template S3 bucket. Find the bucket with
aws s3 ls | grep cf-templates-. Check its bucket policy and ACL — if it is publicly readable, every template version ever deployed is accessible without authentication. - Check change sets.
aws cloudformation list-change-setsanddescribe-change-setmay expose parameter values provided during update operations. - Remediate: Replace all plaintext parameter defaults with
{{resolve:secretsmanager:...}}dynamic references. Remove anyOutputsthat expose secret values. Enable S3 Block Public Access on the CF template bucket. Rotate any credentials found during the assessment and audit CloudTrail for evidence they were accessed.
Common Assessment Errors
- Assuming NoEcho means encrypted. NoEcho only suppresses display in the console and certain API responses.
GetTemplatestill returns the raw template with the plaintext value. Assessors who mark NoEcho parameters as "protected" are wrong. - Missing UserData base64 encoding. UserData is base64-encoded in the template. Tools scanning for plaintext secrets will miss credentials inside UserData unless the field is decoded first. Always pipe UserData through
base64 -dbefore scanning. - Ignoring nested stacks. CloudFormation supports nested stacks via
AWS::CloudFormation::Stackresources. The parent template may be clean while a child template contains secrets. Recursively retrieve templates for all nested stack resources. - Not checking deleted stacks.
list-stackswith filterDELETE_COMPLETEreturns deleted stacks. Their templates may still exist in the S3 bucket andGetTemplatemay still work for recently deleted stacks. Old secrets in deleted stacks may still be valid. - Overlooking Outputs in automation pipelines. CI/CD pipelines that call
describe-stacksto read Outputs and pass values to downstream jobs may be logging secret values in build logs. Check CloudTrail forDescribeStackscalls from pipeline roles. - Forgetting that Checkov can pre-empt this. Run
checkov -d ./templates --check CKV_AWS_124on the IaC repository. Catching hardcoded secrets before deployment is orders of magnitude cheaper than post-compromise credential rotation.
NICE Framework Alignment
| Code | Knowledge/Skill/Task Statement | How This Card Develops It |
|---|---|---|
| K0053 | Knowledge of security risk management processes | Quantifying the risk of credential exposure in IaC artifacts: the durability of CloudFormation storage means secrets persist long after rotation |
| K0167 | Knowledge of system administration, network, and OS hardening techniques | Hardening IaC pipelines by replacing hardcoded secrets with Secrets Manager dynamic references and enforcing pre-commit scanning |
| S0073 | Skill in conducting vulnerability scans and recognizing vulnerabilities | Applying truffleHog and Checkov to CloudFormation templates to detect plaintext credentials before and after deployment |
| T0144 | Conduct penetration testing as required for new or updated applications | Systematically retrieving and analysing CloudFormation templates and outputs during an AWS penetration test to harvest credentials |
| T0395 | Write code to address security vulnerabilities | Refactoring CloudFormation templates to use {{resolve:secretsmanager}} dynamic references, eliminating plaintext credential storage |
Further Reading
- AWS CloudFormation Security Best Practices — AWS Documentation (docs.aws.amazon.com/cloudformation)
- Hacking the Cloud: CloudFormation Enumeration — Nick Frichette (hackingthe.cloud)
- Secrets Management with AWS Secrets Manager — AWS re:Invent 2022 session SEC317 (AWS Events)
Challenge Lab
Reinforce your learning with a hands-on generated challenge based on this card's competency.