All stories
Incident

The Viral Vibe Coding Nightmare: How a Supabase Key Went Public

An AI assistant placed a service_role key into a NEXT_PUBLIC variable. The entire database was publicly readable for 48 hours before anyone noticed.

The Setup

A solo developer — let’s call him Marcus — was building a SaaS dashboard over a weekend. He was using Cursor with Claude to scaffold his Next.js app. Everything was flowing. Auth, database queries, Stripe webhooks. Vibes were immaculate.

Then Claude suggested a quick fix for a row-level security issue: move the Supabase client initialization into a shared utility file. Reasonable advice. Except the generated code stored the service_role key in an environment variable prefixed with NEXT_PUBLIC_.

Why This Matters

In Next.js, any environment variable prefixed with NEXT_PUBLIC_ is bundled into the client-side JavaScript. It’s visible to anyone who opens DevTools. The service_role key bypasses all row-level security policies — it’s the master key to the entire Postgres database.

Marcus didn’t notice. Why would he? The app worked perfectly. RLS appeared to be functioning because his queries were scoped correctly in code. The key was just… also available to the entire internet.

The Discovery

Forty-eight hours later, Marcus noticed anomalous reads in his Supabase dashboard. Someone — or some bot — had been systematically dumping every table. User emails, hashed passwords, billing metadata. All of it.

He traced the leak to his client bundle. The service_role key was sitting in plain text in the compiled JavaScript, served from Vercel’s CDN to every visitor.

The Autopsy

The root cause wasn’t malice or incompetence. It was a naming convention. NEXT_PUBLIC_SUPABASE_SERVICE_ROLE_KEY looks almost identical to SUPABASE_SERVICE_ROLE_KEY at a glance. The AI assistant didn’t distinguish between client-safe and server-only variables because that distinction lives in framework documentation, not in the variable’s value.

No linter caught it. No CI check flagged it. The Supabase dashboard didn’t warn about it. It was a silent, invisible vulnerability that only becomes dangerous after deployment — exactly the kind of thing that automated monitoring catches in seconds.

The Fix

  1. Rotate the service_role key immediately in the Supabase dashboard.
  2. Move the key to a server-only env var (no NEXT_PUBLIC_ prefix).
  3. Audit the client bundle for any other leaked secrets: grep -r "NEXT_PUBLIC_" .env*.
  4. Set up automated scanning to catch this class of mistake before it ever reaches production.

The Takeaway

AI coding assistants don’t understand deployment contexts. They generate code that works locally and looks correct in review. The vulnerability only manifests after the build step, in production, where nobody is watching — unless you have automated monitoring.