Fix Guides

How to Remove Exposed API Keys From Frontend Code

UbserveFebruary 12, 20262 min read
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.

Dark client-to-server wireframe with a highlighted secret crossing the browser boundary.

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:

  1. NEXT_PUBLIC_
  2. apiKey
  3. service_role
  4. sk_live_
  5. Bearer
  6. 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:

  1. window.__APP_CONFIG__
  2. JSON blobs in script tags
  3. serialized settings in layouts
  4. 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:

  1. remove it from the client
  2. deploy the fix
  3. rotate the key
  4. verify the old key no longer works

Reclassify keys correctly

Treat keys as one of three types:

  1. public identifiers
  2. scoped publishable browser keys
  3. 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?+
No. If the browser can use it, an attacker can too.
What keys are okay in frontend code?+
Only deliberately public identifiers or scoped publishable keys designed for browser use.
Next step

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.