Step-by-Step Guide
6 steps

How to Fix API Key Exposure in Windsurf Apps

Windsurf can embed API keys directly in source files during rapid prototyping. If those keys reach production, they are visible to anyone inspecting your JavaScript bundle. This guide helps you find every exposed key, rotate it, and set up secure secret management.

Find security issues automatically before attackers do.

Follow These Steps

1

Audit your project for hardcoded secrets

Search all source files for API key patterns and credential strings.

Code Example
grep -rn "sk-\|api_key\|apiKey\|secret\|password\|token" src/ --include="*.ts" --include="*.tsx" --include="*.js" --include="*.jsx"
2

Check environment variable usage for misconfigurations

Verify that no secret keys are being exposed via client-side environment variable prefixes.

Code Example
# Find client-exposed env vars that might be secrets
grep -rn "NEXT_PUBLIC_.*KEY\|NEXT_PUBLIC_.*SECRET\|VITE_.*SECRET" src/ .env*
3

Rotate all compromised keys at the provider

Generate new keys from each API provider dashboard and deactivate old ones immediately.

4

Set up proper .env configuration

Create environment files with the correct variable naming conventions for your framework.

Code Example
# .env.local (for Next.js)
OPENAI_API_KEY=sk-proj-new-key    # Server-side only
DATABASE_URL=postgresql://...       # Server-side only
NEXT_PUBLIC_APP_URL=https://...     # Safe for client

# .gitignore
.env
.env.local
.env.production
5

Move API calls to server-side routes

Create API routes that handle third-party API calls server-side.

Code Example
// app/api/generate/route.ts
export async function POST(req: Request) {
  const session = await auth()
  if (!session) return Response.json({ error: 'Unauthorized' }, { status: 401 })
  
  const { prompt } = await req.json()
  const response = await fetch('https://api.openai.com/v1/chat/completions', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.OPENAI_API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ model: 'gpt-4o', messages: [{ role: 'user', content: prompt }] })
  })
  return Response.json(await response.json())
}
6

Deploy and verify

Deploy your fixes and run a VAS scan to confirm no keys are exposed.

Check the browser Sources tab in DevTools to verify no secrets appear in the client-side JavaScript.

What You'll Achieve

All API keys are rotated, moved to server-side environment variables, and API calls are proxied through server-side routes. Your Windsurf app no longer exposes secrets to the browser.

Common Mistakes to Avoid

Mistake

Using VITE_ prefix for secret keys in Vite projects

Fix

VITE_ prefix exposes variables to the browser. Use non-prefixed names for secrets and access them only in server-side code.

Mistake

Only fixing the code without rotating compromised keys

Fix

Any key that was in frontend code is compromised. Rotate it at the provider before deploying the fix.

Frequently Asked Questions

Which environment variable prefixes expose secrets to the browser?

NEXT_PUBLIC_ in Next.js and VITE_ in Vite expose variables to the client bundle. Never use these prefixes for secret API keys.

Can I use a .env file safely with Windsurf?

Yes, but add .env to .gitignore before your first commit. Variables without client-safe prefixes (NEXT_PUBLIC_, VITE_) remain server-side only.

How do I prevent Windsurf from generating code with hardcoded keys?

Use project rules or a windsurf-rules file to instruct the AI to always use environment variables. Avoid pasting real keys into the chat context.

Ready to Secure Your App?

VAS automatically scans your deployed app for the security issues covered in this guide. Get actionable results in minutes.

Start Security Scan