How to Fix API Key Exposure in Bolt.new Apps
Bolt.new generates code fast, but often places API keys directly in frontend files. If your app has been deployed with exposed keys, attackers can extract them from the JavaScript bundle. This guide walks you through finding, rotating, and properly securing every exposed key.
Find security issues automatically before attackers do.
Follow These Steps
Search your codebase for hardcoded keys
Scan all source files for API key patterns. Bolt.new may embed keys in component files, utility functions, or configuration files.
grep -rn "sk-\|api_key\|apiKey\|secret_key\|OPENAI\|ANTHROPIC\|STRIPE" src/ --include="*.ts" --include="*.tsx" --include="*.js"Check your git history for previously committed keys
Even if you already removed a key from code, it may still exist in git history.
git log --all --full-history -p -- "*.ts" "*.tsx" "*.env" | grep -i "sk-\|api_key\|secret"If a key was ever committed, consider it compromised and rotate it immediately.
Rotate all compromised keys
Go to each API provider dashboard and generate new keys. Deactivate the old keys. Do this before fixing the code.
# Common providers to check:
# OpenAI: platform.openai.com/api-keys
# Stripe: dashboard.stripe.com/apikeys
# Anthropic: console.anthropic.com/settings/keys
# Supabase: app.supabase.com/project/_/settings/apiCreate a .env file and add to .gitignore
Set up environment variables for local development.
# Create .env.local
OPENAI_API_KEY=sk-proj-your-new-key
STRIPE_SECRET_KEY=sk-live-your-new-key
# Add to .gitignore (create if it does not exist)
echo ".env*" >> .gitignore
echo "!.env.example" >> .gitignore
# Create .env.example with placeholder values
OPENAI_API_KEY=sk-proj-your-key-here
STRIPE_SECRET_KEY=sk-live-your-key-hereCreate server-side API routes
Replace direct frontend API calls with server-side routes that access secrets from environment variables.
// app/api/ai/route.ts (Next.js)
import { NextResponse } from 'next/server'
export async function POST(req: Request) {
const { prompt } = await req.json()
if (!prompt || typeof prompt !== 'string') {
return NextResponse.json({ error: 'Invalid input' }, { status: 400 })
}
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 NextResponse.json(await response.json())
}Update frontend to use the API route
Change frontend code to call your API route instead of the third-party API directly.
// Before (INSECURE)
const res = await fetch('https://api.openai.com/v1/chat/completions', {
headers: { 'Authorization': 'Bearer sk-proj-EXPOSED' }
})
// After (SECURE)
const res = await fetch('/api/ai', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ prompt: userInput })
})Configure environment variables in your hosting platform
Add the new API keys as environment variables in Vercel, Netlify, or wherever you deploy.
Never use NEXT_PUBLIC_ prefix for secret keys. That prefix makes the variable available in the browser bundle.
Scan to verify the fix
Deploy and run a VAS scan to confirm no keys remain in the frontend bundle.
Also check DevTools > Sources > Search for any remaining key patterns.
What You'll Achieve
All exposed API keys are rotated, removed from frontend code, and stored securely in server-side environment variables. API calls are now proxied through server-side routes where secrets are never exposed to browsers.
Common Mistakes to Avoid
Mistake
Using NEXT_PUBLIC_ prefix for secret keys
Fix
NEXT_PUBLIC_ makes the variable available in the browser. Only use it for truly public values. Secret keys must not have this prefix.
Mistake
Forgetting to add .env to .gitignore before committing
Fix
If .env was committed, it is in git history forever. Add .env to .gitignore, then remove with git rm --cached .env, and rotate all keys.
Mistake
Only removing the key from the latest code without rotating
Fix
Once a key has been in code or git history, assume it is compromised. Rotate it at the provider before fixing the code.
Frequently Asked Questions
How do I know if someone has used my exposed key?
Check the usage dashboard of each API provider. Look for unusual spikes in usage, requests from unknown IPs, or unexpected charges. Most providers offer usage monitoring and alerts.
Is it enough to just delete the key from my code?
No. If the key was ever deployed or committed to git, it is compromised. You must generate a new key at the provider and deactivate the old one.
Which keys are safe in frontend code?
Firebase API keys and Supabase anon keys are designed for frontend use. Their security comes from Security Rules and RLS policies respectively. All other API keys should be server-side only.
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