Hardcoded secrets in source code violate CWE-798 (Use of Hard-coded Credentials) and OWASP A07 (Identification & Authentication Failures), and they are permanent: unlike a leaked .env file, a credential baked into a function call survives every deployment, every refactor, and every repo clone. A Stripe live key or database password embedded in a TypeScript file is readable by every developer, CI runner, contractor, and open-source contributor who touches the repo. NIST IA-5 requires credential management controls — hardcoded values have no rotation path, no access control, and no audit trail.
Critical because hardcoded credentials are unrevokable without a code change and are visible to everyone with repository access, making targeted rotation impossible.
Move every secret out of source files and into environment variables. Validate presence at startup so missing config fails fast rather than failing silently mid-request.
// src/config/secrets.ts
// BEFORE (wrong)
export const STRIPE_KEY = 'sk_live_51234...'
// AFTER (correct)
export const STRIPE_KEY = process.env.STRIPE_SECRET_KEY
if (!STRIPE_KEY) throw new Error('STRIPE_SECRET_KEY not set')
For each secret removed from source code, generate a new credential in the service dashboard (the old one is compromised), store it in your secrets manager or CI environment, and delete it from git history with git filter-repo.
ID: environment-security.secrets-management.no-hardcoded-secrets
Severity: critical
What to look for: Search the entire codebase for hardcoded secrets. Use tools like truffleHog, gitleaks, detect-secrets, or manual grep patterns. Search for API keys, tokens, passwords, private keys, database credentials, and OAuth tokens. Check both source files and configuration files (vite.config.ts, next.config.ts, etc.).
Pass criteria: Count every source file searched and enumerate all pattern matches for secret-like strings. 0% of files may contain hardcoded secrets (except clearly marked placeholders like xxx_placeholder or CHANGEME). Report the count of files scanned even on pass.
Fail criteria: Any hardcoded secret found in source code or config files — API key, token, password, private key, or database URL with credentials embedded. Quote the variable name and file location (never the actual secret value). Should not pass when even a single secret-like pattern is found outside environment variables.
Skip (N/A) when: Never — hardcoded secrets are a critical vulnerability.
Detail on fail: Specify the type of secret found and the file location. Example: "Stripe API key found hardcoded in src/payment/stripe.ts line 12; AWS access key found in terraform/main.tf line 45". Do NOT include the actual secret value.
Remediation: Move all secrets to environment variables. Use a tool like dotenv to load .env files in development:
// src/config/secrets.ts — BEFORE (wrong)
export const STRIPE_KEY = 'sk_live_51234...'
// src/config/secrets.ts — AFTER (correct)
export const STRIPE_KEY = process.env.STRIPE_SECRET_KEY
if (!STRIPE_KEY) throw new Error('STRIPE_SECRET_KEY not set')
For each rotated secret, generate a new one and update it in your secrets manager or CI/CD environment.