← All posts
hardcoded secretscursorai generated codesecuritysecret leak

How to Fix Hardcoded Secrets in Cursor AI Generated Code

O

OverMCP Team

Quick answer

Hardcoded secrets in Cursor AI generated code—like API keys, database credentials, and JWT tokens—are a common security risk because AI models often output example values directly into source files. To fix them, immediately move all secrets to environment variables or a secrets manager, then scan your entire repository with a dedicated tool like OverMCP's secret leak scanner to catch any you missed. Never commit secrets to Git; use .gitignore and pre-commit hooks to block them automatically.

What to check first

Before writing a single line of fix code, audit your project for all possible hardcoded secrets. Here is a concrete checklist:

  • API keys – OpenAI, Stripe, Supabase, Firebase, AWS, GitHub, SendGrid, etc.
  • Database connection strings – PostgreSQL, MongoDB, Redis URLs containing credentials.
  • JWT secrets – Often found in auth.js, middleware.js, or lib/auth.js.
  • Service role / admin keys – Supabase service_role, Firebase admin SDK keys.
  • OAuth client secrets – Google, GitHub, Apple OAuth credentials.
  • Private SSH keys or tokens – NPM tokens, GitHub personal access tokens.
  • Hardcoded URLs with embedded credentials – e.g., http://user:pass@internal-api.com.
  • Search your entire project for patterns like sk-, AKIA, eyJ (base64 JWT), password=, secret=, api_key=, key=. Use grep -r or the built-in Cursor search with regex: (sk-[A-Za-z0-9]{20,}|AKIA[0-9A-Z]{16}|eyJ[A-Za-z0-9_-]{10,}). Run a free AI app security scanner to get a quick inventory of all exposed secrets.

    Step-by-step fix

    Follow this exact workflow to fix hardcoded secrets in your Cursor AI generated code. We'll use a Next.js app with Supabase as an example, but the pattern applies to any framework.

    1. Identify all hardcoded secrets

    Open your project and list every file containing secrets. Common culprits:

  • lib/supabaseClient.js
  • pages/api/auth.js
  • utils/constants.js
  • .env.local (if accidentally committed)
  • next.config.js
  • 2. Move secrets to environment variables

    Create a .env.local file (ensure it's in .gitignore already) and define variables:

    # .env.local
    NEXT_PUBLIC_SUPABASE_URL=https://yourproject.supabase.co
    SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
    OPENAI_API_KEY=sk-proj-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    JWT_SECRET=my-custom-jwt-secret-that-is-long-and-random

    Then reference them in your code:

    // lib/supabaseClient.js (before fix - hardcoded)
    import { createClient } from '@supabase/supabase-js'
    
    const supabaseUrl = 'https://yourproject.supabase.co'
    const supabaseKey = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
    export const supabase = createClient(supabaseUrl, supabaseKey)
    // lib/supabaseClient.js (after fix - env vars)
    import { createClient } from '@supabase/supabase-js'
    
    const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!
    const supabaseKey = process.env.SUPABASE_SERVICE_ROLE_KEY!
    export const supabase = createClient(supabaseUrl, supabaseKey)

    For the JWT secret, update your authentication middleware:

    // pages/api/auth.js (before - hardcoded)
    const JWT_SECRET = 'supersecretkey123'
    
    // After - from environment
    const JWT_SECRET = process.env.JWT_SECRET

    3. Remove all hardcoded values from source

    Search for every occurrence you identified and replace with process.env.VARIABLE_NAME. For public keys (like NEXT_PUBLIC_*), use the NEXT_PUBLIC_ prefix so they're available client-side.

    4. Scan for remaining secrets

    After the manual fix, run an automated scan to catch anything you missed. Use OverMCP's secret leak scanner – it checks your entire Git history, staged files, and even common misconfigurations. If you're on Vercel, you can connect your project for continuous monitoring.

    5. Add pre-commit hooks to prevent future leaks

    Install husky and lint-staged, then use a tool like secretlint or talisman:

    npx husky add .husky/pre-commit "npx secretlint --secretlintignore .gitignore **/*"

    Or use a simpler regex check in .husky/pre-commit:

    #!/bin/sh
    . "$(dirname "$0")/_/husky.sh"
    
    # Block files containing patterns like API keys
    if git diff --cached --name-only | xargs grep -l 'sk-[A-Za-z0-9]{20,}\|AKIA[0-9A-Z]{16}'; then
      echo "ERROR: Found potential secret in staged files. Commit aborted."
      exit 1
    fi

    6. Rotate any leaked credentials

    If you ever committed a secret, assume it's compromised. Go to the respective service (OpenAI, Supabase, AWS, etc.) and rotate the key immediately. For Supabase, go to Settings > API > Rotate service role key.

    Common mistakes

    Cursor AI generated apps often make these specific errors:

  • Hardcoding in example files – The AI might create a utils/example.js with dummy secrets that you forget to replace.
  • Using `.env` without `.gitignore` – The .env file is generated but not added to .gitignore, so it gets committed. Always check .gitignore includes .env, .env.local, .env.*.local.
  • Committing `.env.example` with real values – Developers copy .env.example to .env and fill in real keys, then accidentally commit the example file with real data.
  • Secrets in client-side code – Using NEXT_PUBLIC_ for keys that should be server-only (like SUPABASE_SERVICE_ROLE_KEY). This exposes the secret in the browser.
  • Hardcoded in configuration filesnext.config.js, firebase.config.js, or aws.config.js often contain static secrets generated by Cursor.
  • Forgetting Git history – Even after fixing a file, the secret remains in Git history. You must use git filter-branch or BFG Repo-Cleaner to purge it. After cleanup, rotate the key anyway.
  • Why Cursor loves hardcoding secrets

    Cursor's AI model is trained on public code, which often includes example API keys like sk-test-xxx or placeholder secrets. When you prompt it to generate a Supabase client or OpenAI wrapper, it naturally outputs inline values because that's the training pattern. The AI doesn't understand your deployment environment or security best practices — it just completes the code you asked for. That's why you must treat every Cursor-generated file as a security risk until verified.

    Continuous prevention

    Don't rely on a one-time fix. Set up continuous security monitoring to scan every new commit and deployment. This catches secrets that slip through code review, especially in fast-moving projects. Also, educate your team (or future you) to always ask Cursor to refactor secrets into environment variables as part of the prompt: "Generate this function using environment variables for all secrets."

    FAQ

    What is a hardcoded secret?

    A hardcoded secret is any sensitive credential (API key, password, token, or certificate) written directly into source code instead of stored securely in environment variables or a secrets manager. This makes it visible in Git history and easy to steal.

    Can I use Cursor to fix hardcoded secrets automatically?

    You can prompt Cursor to refactor hardcoded values to environment variables, but always verify the output manually. Cursor might miss some occurrences or introduce new secrets. Pair it with an automated scanner for thorough results.

    How do I check if my Cursor project has hardcoded secrets?

    Use a regex search across your codebase for common key patterns (e.g., sk-, AKIA, eyJ), or run a dedicated scanner like OverMCP's secret leak scanner which detects over 100+ secret types and checks Git history.

    Is your app secure?

    Free scan in 30 seconds. No signup needed.

    Scan My App Free