Skip to main content

No API keys or secrets hardcoded in source

ab-002566 · project-snapshot.secrets.no-keys-in-source
Severity: criticalactive

Why it matters

A sk_live_, AKIA, ghp_, or private-key literal inside committed source code is functionally identical to publishing the credential — git history is forever, and secret-scanning services (GitHub's built-in scanner, TruffleHog, GitGuardian) will find it faster than most teams can. AI coding tools produce this anti-pattern routinely: asked to "add Stripe", they paste the example key from docs inline; asked to "connect to the database", they inline the connection string. Even git rm doesn't help — the blob stays reachable through history until a full rewrite plus credential rotation. Stripe, AWS, and GitHub all auto-revoke detected keys, so the loud failure mode is service outage; the quiet mode is an attacker finding it first and quietly using it.

Severity rationale

Critical because a hardcoded key is already compromised the moment it hits git — there is no grace period, no mitigation short of rotation, and no way to claw the secret back from archived clones or cached views.

Remediation

Move the secret to an environment variable, delete the literal from source, rotate the credential immediately (assume it is compromised the moment it lands in git history).

Deeper remediation guidance and cross-reference coverage for this check lives in the security-hardening Pro audit — run that after applying this fix for a more exhaustive pass on the same topic.

Detection

  • ID: project-snapshot.secrets.no-keys-in-source
  • Severity: critical
  • What to look for: Search source files (excluding node_modules, .git, build output, .env*) for high-signal secret patterns. Enumerate every match. Patterns to count: sk_live_, sk_test_, rk_live_, pk_live_ (Stripe), AIza (Google), AKIA (AWS), ghp_, gho_, ghs_, github_pat_ (GitHub PATs), xoxb-, xoxp- (Slack), eyJhbGciOi (JWTs), -----BEGIN RSA PRIVATE KEY-----, -----BEGIN OPENSSH PRIVATE KEY-----. Also flag any string variable assigned process.env.X where X is the literal value (rare false positive — exclude).
  • Pass criteria: Zero hardcoded secrets matching the patterns above in any committed source file.
  • Fail criteria: One or more matches found. Include the file path and pattern name in the detail (never the secret value).
  • Skip (N/A) when: Never. Every project should be checked.
  • Do NOT pass when: A pattern match is found inside a source file, even if commented out — comments still ship to the repo.
  • Before evaluating, quote: Quote the file path of any match (file path only, NOT the secret value). If zero matches, report "0 matches across N source files searched".
  • Report even on pass: Report the count of source files scanned and the count of matches: "Scanned ~X source files, 0 secret patterns matched".
  • Detail on fail: "Hardcoded Stripe secret key in src/lib/payments.ts (sk_live_ pattern)" — never include the actual secret value.
  • Remediation: Move the secret to an environment variable, delete the literal from source, rotate the credential immediately (assume it is compromised the moment it lands in git history).

Taxons

History