Critical CWE-798 OWASP A07:2021

Hardcoded Secrets in Vibe Coded Apps

How to find and fix exposed API keys, passwords, and credentials in your codebase

Quick Answer

Hardcoded secrets are API keys, passwords, and tokens embedded directly in code. Bots scan GitHub and exploit exposed secrets within minutes. Classified under OWASP A07:2021. AI tools generate these constantly.

A07:2021
OWASP Category
CWE-798
<1 min
To Exploit
Critical
Severity

Source: OWASP Top 10 (2021)

What are hardcoded secrets?

Hardcoded secrets are sensitive credentials (API keys, passwords, tokens) written directly into source code instead of environment variables or secret managers. Common examples include Stripe/OpenAI/AWS API keys, database connection strings, JWT signing secrets, and OAuth client secrets.

Once committed to version control, secrets persist in git history forever, even after you "delete" them. Automated bots continuously scan public repositories and can exploit exposed secrets within minutes. According to GitGuardian's 2024 State of Secrets Sprawl Report, over 12 million new secrets were detected in public GitHub commits in 2023.

According to OWASP, identification and authentication failures (which includes exposed credentials) ranked #7 in the Top 10 Web Application Security Risks. The CWE Top 25 also lists hardcoded credentials as a dangerous weakness. For vibe coders, this is the most common security mistake.

How do AI tools cause hardcoded secrets?

AI tools cause hardcoded secrets by generating complete, working examples with placeholder credentials that developers forget to replace. When you ask for "Stripe integration," the AI produces functional code with inline API keys because that's what works immediately.

Common AI-generated patterns

AI tools frequently generate code like this:

// AI generates this "working" example
const stripe = new Stripe('sk_live_EXAMPLE_KEY_HERE', {
  apiVersion: '2023-10-16'
})

// Or database connections with inline credentials
const db = new Pool({
  connectionString: 'postgresql://user:password123@localhost:5432/mydb'
})

// Or JWT secrets directly in code
const JWT_SECRET = 'super-secret-key-change-me'

This code works immediately, which is exactly what AI optimizes for. The security problem comes later when developers forget to externalize these values.

Why this happens: AI models are trained on code examples that often include placeholder credentials for demonstration. The AI doesn't distinguish between "example code" and "production code". It generates what works.

All major AI coding tools (Cursor, Claude Code, Bolt, v0, and Copilot) can generate these patterns. Whether you're vibe coding with Bolt (which is particularly prone due to its "ready to run" philosophy) or any other AI tool, always check for hardcoded credentials before committing.

What could happen if I have hardcoded secrets?

Hardcoded secrets can result in financial damage, data breaches, service abuse, and account takeover within minutes of exposure.

  • Financial damage: Attackers use your AWS/GCP/Azure credentials to spin up crypto miners, running up thousands in charges
  • Data breach: Database credentials expose all user data: emails, passwords, payment info, personal details
  • Service abuse: Your OpenAI/Stripe/Twilio API keys get used until rate limits hit or accounts are suspended
  • Account takeover: OAuth and JWT secrets let attackers forge authentication tokens and impersonate any user
  • Lateral movement: One exposed credential often leads to others. Database access reveals more secrets stored in tables

How do I detect hardcoded secrets?

Detect hardcoded secrets by searching for API key prefixes (sk_live_, AKIA, ghp_), database connection strings, and variable names like API_KEY, SECRET, or PASSWORD with inline values.

Patterns to search for
# API key patterns
sk_live_    # Stripe live keys
sk_test_    # Stripe test keys (still sensitive!)
AKIA        # AWS access key IDs
ghp_        # GitHub personal access tokens
xoxb-       # Slack bot tokens

# Database connection strings
postgresql://
mongodb+srv://
mysql://

# Common variable names with inline values
const API_KEY = '...'
const SECRET = '...'
const PASSWORD = '...'
const TOKEN = '....'

# Regex for generic secrets
['"](sk|pk|api|key|secret|password|token)[_-]?['"]*[:=]['"]w{20,}['"]

Use automated tools: TruffleHog, GitLeaks, and GitGuardian scan your entire git history for exposed secrets.

Want to find secrets automatically?

Try Vibeship Scanner

How do I fix hardcoded secrets?

Fix hardcoded secrets by moving all credentials to environment variables and adding .env to your .gitignore before committing.

AI Fix Prompt

Copy this prompt into Cursor, Claude Code, or Bolt to automatically fix hardcoded secrets:

Copy-paste this prompt
Fix all hardcoded secrets in my codebase. ## What to look for Search for these patterns that indicate hardcoded secrets: 1. API key assignments: - const API_KEY = 'sk_live_...' - const OPENAI_KEY = 'sk-...' - apiKey: 'hardcoded-value' 2. Database connection strings with credentials: - postgresql://user:password@host - mongodb+srv://user:password@cluster - mysql://root:password@localhost 3. Secret/token/password variables with inline values: - JWT_SECRET = 'some-secret' - const password = 'admin123' - token: 'ghp_...' 4. Service-specific patterns: - sk_live_, sk_test_ (Stripe) - AKIA (AWS) - ghp_, gho_ (GitHub) - xoxb-, xoxp- (Slack) ## How to fix Replace all hardcoded secrets with environment variables: ```javascript // Before (vulnerable) const stripe = new Stripe('sk_live_abc123') // After (secure) const stripe = new Stripe(process.env.STRIPE_SECRET_KEY) ``` For each secret found: 1. Move the value to .env (and add .env to .gitignore) 2. Replace the hardcoded value with process.env.VARIABLE_NAME 3. Add the variable to .env.example with a placeholder value 4. Document required environment variables in README ## Framework-specific notes - **Next.js**: Use NEXT_PUBLIC_ prefix only for client-safe values - **Vite**: Use VITE_ prefix for client-exposed variables - **Node.js**: Use dotenv package to load .env files - **Vercel/Railway**: Use their secrets management UI ## After fixing 1. Search for any remaining patterns: grep -r "sk_live\|sk_test\|AKIA\|password.*=" . 2. Verify .env is in .gitignore 3. Create .env.example with placeholder values 4. List all files modified with before/after examples 5. IMPORTANT: If secrets were ever committed, they need to be rotated. Assume they're compromised Please proceed systematically through my codebase.

Manual Fix

The fix is always the same: move secrets to environment variables.

VULNERABLE
// Hardcoded API key - DANGEROUS
const openai = new OpenAI({
  apiKey: 'sk-abc123def456...'
})

// Database password in code - DANGEROUS
const pool = new Pool({
  connectionString: 'postgresql://admin:[email protected]/prod'
})
SECURE
// Load from environment variable - SAFE
const openai = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY
})

// Connection string from env - SAFE
const pool = new Pool({
  connectionString: process.env.DATABASE_URL
})

// Add to .env (never commit this file!)
// OPENAI_API_KEY=sk-abc123def456...
// DATABASE_URL=postgresql://admin:[email protected]/prod

Critical steps after moving secrets:

  1. Add .env to .gitignore (before committing!)
  2. Create .env.example with placeholder values for documentation
  3. If secrets were ever committed, rotate them immediately. Assume they're compromised
  4. Set up secrets in your deployment platform (Vercel, Railway, AWS, etc.)

Frequently asked questions

What counts as a hardcoded secret?

Any sensitive credential embedded directly in your source code: API keys, database passwords, JWT secrets, OAuth tokens, encryption keys, service account credentials, and webhook URLs with tokens. If it grants access to something and it's in your code (not environment variables), it's a hardcoded secret.

Can't I just use a private GitHub repository?

Private repos don't protect you. Secrets in code can leak through: employees leaving, accidental repo visibility changes, compromised developer machines, CI/CD logs, error messages, and client-side bundles. The only safe approach is to never put secrets in code. Use environment variables and secret managers instead.

How do I know if my secrets are already exposed?

Check your git history with tools like TruffleHog or GitLeaks. Secrets persist in commits even after deletion. Search GitHub for your organization name plus common key patterns. Check haveibeenpwned.com for credential breaches. If you find exposed secrets, rotate them immediately and assume they're compromised.

Why do AI coding tools generate hardcoded secrets?

AI tools generate working code fast. When vibe coding a "Stripe integration," the AI produces a complete example, often with placeholder keys that look real. Vibe coders copy these examples into production without replacing the credentials. AI prioritizes "it works" over "it's secure."

What if I already pushed secrets to GitHub?

Act fast: 1) Rotate the compromised credentials immediately. This is your priority. 2) Remove secrets from your code and use environment variables. 3) Use git filter-branch or BFG Repo-Cleaner to purge secrets from history. 4) Force push the cleaned history. Note: GitHub caches commits, so always assume exposed secrets are compromised.

Related content

Scan your code for hardcoded secrets

Check your codebase for exposed API keys, passwords, and other credentials.

Try Vibeship Scanner