Key Takeaways
- Never hardcode secrets in source code — use environment variables or secrets managers
- Use a dedicated secrets manager (HashiCorp Vault, AWS Secrets Manager, Azure Key Vault)
- Rotate secrets regularly and automatically where possible
- Add .env files to .gitignore to prevent accidental commits
- Use git-secrets or truffleHog to scan for accidentally committed credentials
What NOT to Do
1. Never Hardcode Secrets
# BAD - Hardcoded credentials in source code
database_password = "SuperSecret123!"
api_key = "sk-1234567890abcdef"
# BAD - Credentials in config files committed to Git
# config.py
DB_HOST = "localhost"
DB_USER = "admin"
DB_PASS = "password123" # NEVER!
# BAD - Connection strings with embedded passwords
connection_string = "mysql://root:password@localhost/mydb"
What Attackers Find in Public Git Repos
| Secret Type | Risk Level | Impact |
|---|---|---|
| AWS Access Keys | Critical | Full cloud account takeover, crypto mining |
| Database Passwords | Critical | Complete data breach |
| API Keys (Stripe, Twilio) | High | Financial fraud, service abuse |
| JWT Secrets | Critical | Token forgery, authentication bypass |
| SSH Private Keys | Critical | Server access, lateral movement |
Environment Variables
2. Use Environment Variables
Setting Environment Variables
# Linux/macOS - Temporary (current session)
export DATABASE_PASSWORD="SecurePassword123!"
export API_KEY="sk-1234567890abcdef"
# Linux/macOS - Permanent (add to ~/.bashrc or ~/.zshrc)
echo 'export DATABASE_PASSWORD="SecurePassword123!"' >> ~/.bashrc
source ~/.bashrc
# Windows Command Prompt
set DATABASE_PASSWORD=SecurePassword123!
# Windows PowerShell
$env:DATABASE_PASSWORD = "SecurePassword123!"
# Windows - Permanent (System Properties > Environment Variables)
setx DATABASE_PASSWORD "SecurePassword123!"
Reading Environment Variables in Code
# Python
import os
db_password = os.environ.get('DATABASE_PASSWORD')
api_key = os.getenv('API_KEY', 'default_value')
# Node.js
const dbPassword = process.env.DATABASE_PASSWORD;
const apiKey = process.env.API_KEY || 'default_value';
# PHP
$db_password = getenv('DATABASE_PASSWORD');
$api_key = $_ENV['API_KEY'] ?? 'default_value';
# Java
String dbPassword = System.getenv("DATABASE_PASSWORD");
# C# / .NET
string dbPassword = Environment.GetEnvironmentVariable("DATABASE_PASSWORD");
# Go
dbPassword := os.Getenv("DATABASE_PASSWORD")
# Ruby
db_password = ENV['DATABASE_PASSWORD']
.env Files
3. Using .env Files Securely
Create .env File
# .env file (in project root)
DATABASE_HOST=localhost
DATABASE_PORT=5432
DATABASE_NAME=myapp
DATABASE_USER=app_user
DATABASE_PASSWORD=SecurePassword123!
API_KEY=sk-1234567890abcdef
JWT_SECRET=super-secret-jwt-key-change-this
# AWS Credentials
AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
# Third-party APIs
STRIPE_SECRET_KEY=sk_live_xxxxxxxxxxxxx
SENDGRID_API_KEY=SG.xxxxxxxxxxxxxxxxxxxx
.gitignore Configuration
# .gitignore - MUST include these
.env
.env.local
.env.*.local
.env.production
.env.development
# Also ignore
*.pem
*.key
*.p12
config/secrets.yml
config/credentials.yml.enc
# IDE files that might contain secrets
.idea/
.vscode/settings.json
Loading .env Files
# Python - using python-dotenv
pip install python-dotenv
from dotenv import load_dotenv
import os
load_dotenv() # Loads .env file
db_password = os.getenv('DATABASE_PASSWORD')
# Node.js - using dotenv
npm install dotenv
require('dotenv').config();
const dbPassword = process.env.DATABASE_PASSWORD;
# PHP - using vlucas/phpdotenv
composer require vlucas/phpdotenv
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->load();
$dbPassword = $_ENV['DATABASE_PASSWORD'];
# Ruby - using dotenv
gem install dotenv
require 'dotenv/load'
db_password = ENV['DATABASE_PASSWORD']
Create .env.example Template
# .env.example (commit this to Git as a template)
DATABASE_HOST=localhost
DATABASE_PORT=5432
DATABASE_NAME=myapp
DATABASE_USER=
DATABASE_PASSWORD=
API_KEY=
JWT_SECRET=
# Instructions for developers:
# 1. Copy this file to .env
# 2. Fill in the actual values
# 3. NEVER commit .env to Git
Secret Scanning
4. Scan for Leaked Secrets
git-secrets (AWS)
# Install git-secrets
brew install git-secrets # macOS
# or
git clone https://github.com/awslabs/git-secrets.git
cd git-secrets && make install
# Set up in repository
cd your-repo
git secrets --install
git secrets --register-aws
# Scan existing commits
git secrets --scan-history
# Add to pre-commit hook (automatic scanning)
git secrets --install
TruffleHog
# Install TruffleHog
pip install trufflehog
# Scan Git repository
trufflehog git https://github.com/user/repo.git
# Scan local directory
trufflehog filesystem /path/to/project
# Scan with JSON output
trufflehog git https://github.com/user/repo.git --json
Gitleaks
# Install Gitleaks
brew install gitleaks # macOS
# or download from GitHub releases
# Scan repository
gitleaks detect --source /path/to/repo
# Scan and generate report
gitleaks detect --source /path/to/repo --report-path report.json
# Use in CI/CD
gitleaks detect --source . --verbose
GitHub Secret Scanning
GitHub automatically scans public repos for known secret patterns and alerts you. Enable in: Repository Settings → Security & Analysis → Secret Scanning
Secrets Managers
5. Use a Secrets Manager (Production)
HashiCorp Vault
# Install Vault
brew install vault # macOS
# Start dev server (testing only)
vault server -dev
# Store a secret
vault kv put secret/myapp/database password="SecurePass123!"
# Retrieve a secret
vault kv get secret/myapp/database
# Use in application (Python)
import hvac
client = hvac.Client(url='https://vault.example.com:8200')
client.token = 'your-vault-token'
secret = client.secrets.kv.read_secret_version(path='myapp/database')
db_password = secret['data']['data']['password']
AWS Secrets Manager
# Create secret via AWS CLI
aws secretsmanager create-secret \
--name myapp/database \
--secret-string '{"username":"admin","password":"SecurePass123!"}'
# Retrieve secret via CLI
aws secretsmanager get-secret-value --secret-id myapp/database
# Python (boto3)
import boto3
import json
client = boto3.client('secretsmanager', region_name='us-east-1')
response = client.get_secret_value(SecretId='myapp/database')
secret = json.loads(response['SecretString'])
db_password = secret['password']
# Node.js
const AWS = require('aws-sdk');
const client = new AWS.SecretsManager({ region: 'us-east-1' });
const data = await client.getSecretValue({ SecretId: 'myapp/database' }).promise();
const secret = JSON.parse(data.SecretString);
const dbPassword = secret.password;
Azure Key Vault
# Create Key Vault
az keyvault create --name myapp-vault --resource-group mygroup
# Store secret
az keyvault secret set --vault-name myapp-vault --name db-password --value "SecurePass123!"
# Retrieve secret
az keyvault secret show --vault-name myapp-vault --name db-password
# Python
from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient
credential = DefaultAzureCredential()
client = SecretClient(vault_url="https://myapp-vault.vault.azure.net/", credential=credential)
secret = client.get_secret("db-password")
db_password = secret.value
Google Cloud Secret Manager
# Create secret
echo -n "SecurePass123!" | gcloud secrets create db-password --data-file=-
# Access secret
gcloud secrets versions access latest --secret=db-password
# Python
from google.cloud import secretmanager
client = secretmanager.SecretManagerServiceClient()
name = "projects/my-project/secrets/db-password/versions/latest"
response = client.access_secret_version(request={"name": name})
db_password = response.payload.data.decode("UTF-8")
Docker Secrets
6. Secrets in Containers
Docker Secrets (Swarm)
# Create secret
echo "SecurePass123!" | docker secret create db_password -
# Use in docker-compose.yml
version: '3.8'
services:
app:
image: myapp
secrets:
- db_password
environment:
- DB_PASSWORD_FILE=/run/secrets/db_password
secrets:
db_password:
external: true
Kubernetes Secrets
# Create secret
kubectl create secret generic db-credentials \
--from-literal=username=admin \
--from-literal=password=SecurePass123!
# Or from file
kubectl create secret generic db-credentials --from-env-file=.env
# Use in Pod
apiVersion: v1
kind: Pod
metadata:
name: myapp
spec:
containers:
- name: app
image: myapp
envFrom:
- secretRef:
name: db-credentials
# Or individual keys
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: password
What To Do If Secrets Are Exposed
7. Emergency Response
# 1. IMMEDIATELY rotate the exposed credential
# - Generate new API key/password
# - Update in secrets manager
# - Deploy to production
# 2. Revoke the old credential
# - Disable/delete old API keys
# - Change passwords
# - Rotate JWT secrets
# 3. Remove from Git history (if committed)
# Using BFG Repo-Cleaner (faster than git filter-branch)
brew install bfg
# Remove file containing secrets
bfg --delete-files .env
# Remove specific text
bfg --replace-text passwords.txt
# Clean up
git reflog expire --expire=now --all
git gc --prune=now --aggressive
# Force push (coordinate with team!)
git push --force
# 4. Audit for unauthorized access
# - Check logs for API usage
# - Review database access logs
# - Check cloud provider activity logs
# 5. Scan entire codebase
gitleaks detect --source . --verbose
trufflehog filesystem .
Security Checklist
☐ No hardcoded secrets in source code
☐ .env files added to .gitignore
☐ .env.example template provided for developers
☐ Environment variables used for configuration
☐ Secret scanning enabled in CI/CD pipeline
☐ Pre-commit hooks prevent secret commits
☐ Production uses secrets manager (Vault, AWS, etc.)
☐ Secrets rotated regularly
☐ Least privilege access to secrets
☐ Audit logging enabled for secret access
☐ Emergency rotation procedure documented
Related Resources
Test Your Knowledge
FixTheVuln Store
Get the HashiCorp Vault Study Planner
Fillable PDF study planners with domain trackers, weekly schedules, and progress tracking. Available in Standard, ADHD-Friendly, Dark Mode, and 4-Format Bundle.
HashiCorp Vault Planner60+ certifications available — from $5.99
CyberFolio
Choosing your next cert? Track them all in one place.
Build a shareable cybersecurity portfolio that highlights your certifications, projects, and skills — free.
Build Your Portfolio →