Secrets Management & Infrastructure Security
Secrets in CI/CD: Risks and Anti-Patterns
3 min read
Secrets—API keys, passwords, certificates, tokens—are the crown jewels attackers seek. A leaked secret can compromise your entire infrastructure in minutes.
The Scale of the Problem
Real incidents:
- 2023: Okta source code leaked via compromised GitHub token
- 2022: Uber breach started with hardcoded credentials
- 2021: Codecov supply chain attack via exposed secrets
- 2019: Capital One breach from misconfigured IAM role
Statistics:
- 4.6 million secrets detected in public GitHub repos (2023)
- 67% of leaked secrets still active 24 hours later
- Average cost: $4.5M per breach involving credentials
- 65% of organizations have hardcoded secrets in code
Common Secret Types in CI/CD
| Secret Type | Example | Risk Level |
|---|---|---|
| API Keys | OPENAI_API_KEY=sk-abc123... |
Critical |
| Database Credentials | DATABASE_URL=postgres://user:pass@... |
Critical |
| Cloud Credentials | AWS_SECRET_ACCESS_KEY=... |
Critical |
| SSH Private Keys | -----BEGIN RSA PRIVATE KEY----- |
Critical |
| JWT Signing Keys | JWT_SECRET=supersecret |
High |
| OAuth Tokens | GITHUB_TOKEN=ghp_xxxx |
High |
| Certificates | .pem, .key files |
High |
| Internal URLs | INTERNAL_API=http://10.0.0.x |
Medium |
Anti-Patterns: What NOT to Do
1. Hardcoded Secrets
# NEVER DO THIS
api_key = "sk-1234567890abcdef" # Hardcoded secret
db_password = "production_pass123" # Hardcoded password
2. Secrets in Environment Files
# .env file committed to git
DATABASE_URL=postgres://admin:secret@db.example.com/prod
AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
3. Secrets in CI/CD Logs
# Bad: Prints secrets to logs
- name: Debug
run: |
echo "API Key: ${{ secrets.API_KEY }}" # Exposed in logs!
env # Dumps ALL environment variables
4. Over-Privileged Secrets
# Bad: Using production credentials in development
- name: Deploy
env:
AWS_ACCESS_KEY_ID: ${{ secrets.PROD_AWS_KEY }} # Full admin access!
5. Long-Lived Tokens
# Bad: Token that never expires
GITHUB_TOKEN: ghp_xxxxxxxxxxxxxxxxxxxx # Created 2 years ago
Secret Exposure Vectors
┌─────────────────────────────────────────────────────┐
│ Secret Exposure Vectors │
├─────────────────────────────────────────────────────┤
│ │
│ Source Code ──────▶ Git History │
│ │ │ │
│ ▼ ▼ │
│ CI/CD Logs GitHub Forks │
│ │ │ │
│ ▼ ▼ │
│ Container Images Error Messages │
│ │ │ │
│ ▼ ▼ │
│ Terraform State Documentation │
│ │
└─────────────────────────────────────────────────────┘
Detection: Finding Leaked Secrets
Pre-Commit Scanning
# Install detect-secrets
pip install detect-secrets
# Create baseline
detect-secrets scan > .secrets.baseline
# Add to pre-commit
# .pre-commit-config.yaml
repos:
- repo: https://github.com/Yelp/detect-secrets
rev: v1.4.0
hooks:
- id: detect-secrets
args: ['--baseline', '.secrets.baseline']
CI/CD Scanning
# GitHub Actions secret scanning
- name: Scan for secrets
uses: trufflesecurity/trufflehog@main
with:
path: ./
extra_args: --only-verified
Git History Scanning
# Scan entire git history
trufflehog git file://. --since-commit=HEAD~100
# Find specific patterns
git log -p | grep -E "(password|api_key|secret)"
What Happens When Secrets Leak
Secret Committed
│
▼
Pushed to GitHub ─────▶ Bots scan within minutes
│
▼
In Git History ─────▶ Forks preserve the secret
│
▼
Attacker Access ─────▶ Lateral movement begins
│
▼
Full Compromise ─────▶ Data exfiltration
Response timeline:
- 0-5 minutes: Automated bots detect exposed secrets
- 5-30 minutes: Attackers begin exploitation
- Hours-Days: Lateral movement and persistence established
- Weeks-Months: Impact discovered (if at all)
Next, we'll explore HashiCorp Vault for secure secrets management. :::