How to Remove Exposed API Keys From Frontend Code
- Focus
- Fix Guide
- Risk
- Critical
- Stack
- Supabase/Next.js
- Detection
- Ubserve Runtime Simulation
A step-by-step fix guide for API keys, admin tokens, and service credentials that leaked into the browser during AI-assisted development.
When an AI agent wants the feature to work quickly, it often chooses the shortest path: put the key where the code runs.
That is how privileged credentials end up inside frontend helpers, client SDK wrappers, and hydration payloads.
Find the leak first
Search for:
NEXT_PUBLIC_apiKeyservice_rolesk_live_Bearer- internal vendor secrets
One recurring edge case looks like this:
export const analyticsClient = new VendorClient({
apiKey: process.env.NEXT_PUBLIC_INTERNAL_ANALYTICS_KEY!,
});
The key may not look critical, but if it enables broad read or write access, it does not belong in the client.
Move the privileged operation behind a server boundary
The browser should call your server. Your server should call the privileged upstream.
export async function POST(request: Request) {
const body = await request.json();
const response = await fetch("https://api.vendor.com/events", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.INTERNAL_ANALYTICS_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
return Response.json(await response.json());
}
Now the browser sends data, but not privilege.
[Component: DarkWireframeKey]
The DarkWireframeKey diagram should show the browser on the left, a server route in the center, and the privileged vendor or database on the right. The red path should illustrate the old design, where the secret crosses straight into the browser, while the green path shows the fixed design.
Check hydration and config objects
Secrets do not only leak from obvious env usage. They also leak when teams serialize “config” into the client to simplify setup.
Review:
window.__APP_CONFIG__- JSON blobs in script tags
- serialized settings in layouts
- debug panels and admin pages
Rotate the secret after fixing the code
If a privileged key was exposed in the bundle, assume it was compromised. The correct sequence is:
- remove it from the client
- deploy the fix
- rotate the key
- verify the old key no longer works
Reclassify keys correctly
Treat keys as one of three types:
- public identifiers
- scoped publishable browser keys
- privileged server-only secrets
AI-generated code tends to collapse those distinctions. Your fix needs to restore them.
Related resources
FAQs
Is an obfuscated key in the bundle safe enough?+
What keys are okay in frontend code?+
Turn this resource into a real security check.
Review the guidance, then run Ubserve to validate whether this issue is actually exploitable in your app and get fix-ready output.