No hardcoded API keys or secrets in source code
Why it matters
Hardcoded secrets in source code are the most common high-severity finding in AI-built projects: the model fills in a working API key to make the code run, and the developer ships it without noticing. A Stripe secret key (sk_live_) hardcoded in lib/stripe.ts gives anyone with repo read access the ability to create charges, refund transactions, or read customer data. A hardcoded JWT secret lets an attacker forge authentication tokens. OWASP A07 (Identification and Authentication Failures) and CWE-798 (Use of Hard-coded Credentials) directly describe this class of defect. PCI-DSS 4.0 Req 8.6.2 explicitly prohibits hard-coded credentials in any system component. Secrets in git history must be rotated even after removal from the code — the history is permanent.
Severity rationale
Critical because a hardcoded secret key gives anyone with repository read access full API-level access to the associated service, often with no rate limiting or geo restriction.
Remediation
Move every secret literal to an environment variable reference. The fix is mechanical — find the literal, move it to .env.local, and reference it via process.env.
// Before (DANGEROUS — rotate this key immediately):
const stripe = new Stripe('sk_live_abc123...')
// After (SAFE):
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!)
After moving secrets to environment variables: rotate every exposed key immediately — assume any secret that ever appeared in your git history has been seen, regardless of whether the repo was private. Use git log -S 'sk_live_' to confirm the secret is gone from all commits; if it isn't, you need a history rewrite (git filter-repo).
Detection
-
ID:
no-hardcoded-secrets -
Severity:
critical -
What to look for: Count all source code files searched and enumerate any hardcoded secret patterns found: API keys, tokens, passwords, connection strings. Only flag secret/private keys — not public keys that are intentionally embedded client-side. Look for:
- Stripe secret keys:
sk_live_,sk_test_— flag these. Do NOT flag Stripe publishable keys (pk_live_,pk_test_) — these are designed to be public and are safely embedded in client-side code. - GitHub tokens: strings starting with
ghp_,gho_,ghu_ - AWS secret access keys: strings starting with
AKIA(access key IDs) combined with a secret key value password = "...",secret = "...", orapiKey = "..."with literal string values (not environment variable references)- Keys containing
_secret_in any API key pattern - Database connection strings with credentials embedded (usernames/passwords in the URL)
- JWT signing secrets as literal strings
- Any long alphanumeric string (32+ chars) assigned to a variable named
key,secret,token,password, orcredential
Important: Only flag literal string values in source code. References to
process.env.SECRET_KEYorimport.meta.env.VITE_SECRETare correct and must NOT be flagged. - Stripe secret keys:
-
Before evaluating: List each directory and file pattern searched (e.g., "Searched
src/,lib/,app/,pages/,config/for patterns:sk_live_,sk_test_,ghp_,AKIA,password =,secret =,apiKey ="). For any flagged item, quote the variable name and assignment pattern (not the actual secret value). Example: "Foundconst stripeKey = 'sk_test_...'inlib/stripe.tsline 4." -
Pass criteria: 0 hardcoded secrets or private keys found in source code after searching at least 3 source directories. All secrets are accessed via environment variables (
process.env.*,import.meta.env.*). Publishable/public keys embedded in client code are acceptable. -
Fail criteria: At least 1 hardcoded secret key, private API key, password, or credential found as a literal string in source code files.
-
Do NOT pass when: Absence of evidence alone is insufficient — actively search all source files, config files, and test fixtures for secret patterns. A cursory scan of only top-level files is not sufficient.
-
Skip (N/A) when: Never — this check always applies.
-
Detail on fail:
"Hardcoded Stripe key found in lib/stripe.ts: sk_live_... value assigned directly instead of using process.env"or"Database connection string with credentials hardcoded in db/config.ts". Never include the actual secret value in the detail string. -
Remediation: Secrets in source code are the most common security issue in AI-built projects. Move all secrets to environment variables:
// Before (DANGEROUS): const stripe = new Stripe('sk_live_abc123...') // After (SAFE): const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!)After fixing, rotate any exposed keys immediately — they should be considered compromised if they were ever in your git history. For application-level security analysis including auth flows and authorization, the SaaS Readiness Pack covers this in depth.
External references
- cwe · CWE-798 — Use of Hard-coded Credentials
- cwe · CWE-321 — Use of Hard-coded Cryptographic Key
- cwe · CWE-259 — Use of Hard-coded Password
- owasp:2021 · A07 — Identification and Authentication Failures
- pci-dss:4.0 · Req 8.6.2 — Hard-coded credentials prohibited
Taxons
History
- 2026-04-17·v1.0.0·Initial import from security-headers·automated