# Credential Handling ## Rule Never hardcode secrets. Load from environment or secret manager at runtime. **Source:** [CWE-798: Use of Hard-coded Credentials](https://cwe.mitre.org/data/definitions/798.html) ## Correct Pattern ```python import os from functools import lru_cache @lru_cache(maxsize=1) def get_api_key() -> str: """Load API key from environment. Fail fast if missing.""" key = os.environ.get("API_KEY") if not key: raise RuntimeError("API_KEY environment variable not set") return key # For cloud environments, use secret manager def get_secret(name: str) -> str: """Load secret from cloud secret manager.""" from google.cloud import secretmanager client = secretmanager.SecretManagerServiceClient() response = client.access_secret_version(name=name) return response.payload.data.decode("UTF-8") ``` ## Incorrect Pattern ```python # Wrong: hardcoded secret API_KEY = "sk-1234567890abcdef" # Wrong: secret in config file checked into git config = {"api_key": "sk-1234567890abcdef"} # Wrong: secret in default argument def call_api(key="sk-1234567890abcdef"): ... # Wrong: secret in error message def validate_key(key): if key != expected_key: raise ValueError(f"Invalid key: {key}") # Leaks the key! # Wrong: secret in log logging.info(f"Using API key: {api_key}") ``` ## Secret Detection Block these patterns in CI: ```python import re SECRET_PATTERNS = [ r'(?i)(api[_-]?key|apikey)\s*[=:]\s*["\'][^"\']+["\']', r'(?i)(secret|password|passwd|pwd)\s*[=:]\s*["\'][^"\']+["\']', r'(?i)bearer\s+[a-zA-Z0-9_-]+', r'sk-[a-zA-Z0-9]{32,}', # OpenAI-style keys r'ghp_[a-zA-Z0-9]{36}', # GitHub PAT ] def scan_for_secrets(content: str) -> list[str]: findings = [] for pattern in SECRET_PATTERNS: if re.search(pattern, content): findings.append(f"Potential secret: {pattern}") return findings ``` ## Environment Separation | Environment | Source | Notes | |-------------|--------|-------| | Development | `.env` file (gitignored) | Never commit | | CI | CI secrets / vault | Injected at runtime | | Production | Secret manager | Rotated automatically | ## Edge Cases - Secrets in Docker build args leak to image history - Environment variables visible in `/proc` on Linux - Secrets in URLs get logged by proxies/load balancers - Clipboard managers may capture pasted secrets