How Moltbook Exposed 1.5 Million API Keys in Client-Side Code

Share

TL;DR

Moltbook launched in late January 2026 with their Supabase database wide open. No Row Level Security configured. Anyone could access nearly 1.5 million API keys and agent records on the platform. The vulnerability was discovered by security researcher Jamieson O'Reilly just days after launch. The fix would have taken two SQL statements. A basic security scan before launch would have caught this immediately.

What Is Moltbook?

Moltbook is a social network where AI agents interact with each other. Users create AI agents that post, interact, and build relationships with other agents. It launched in late January 2026 and grew quickly - by the time of the incident, it had 1.5 million registered agents with 17,000 human owners behind them.

"A lot of these vibe coders and new developers, even some big companies, are using Supabase. The reason a lot of vibe coders like to use it is because it's all GUI driven, so you don't need to connect to a database and run SQL commands."

- Jamieson O'Reilly, security researcher

What Went Wrong

On January 31, 2026 - just days after Moltbook launched - security researcher Jamieson O'Reilly discovered something alarming. The entire database was publicly accessible. Not just some of it. All of it.

The Technical Details

Moltbook was built on Supabase, a popular backend-as-a-service that's become a favorite among indie developers and vibe coders. Supabase exposes REST APIs by default, which is fine when configured correctly.

The problem: Moltbook launched without enabling Row Level Security (RLS) or configuring any access policies. Without RLS, the "anon" API key that's designed to be used in client-side code can query everything.

What was exposed: O'Reilly found a Supabase API key sitting in client-side JavaScript. Using just that key, anyone could access the entire production database - with full read and write access to all tables. This included API keys for every single account on the platform.

In practical terms: anyone who knew where to look could visit the database URL and take control of any account on Moltbook. They could post as that user, read their data, or do whatever they wanted.

How Bad Was It?

Let's put some numbers on this:

  • ~1.5 million agent records with exposed API keys
  • 35,000+ email addresses exposed
  • 17,000 human users whose credentials were compromised
  • Full read/write access to the entire database
  • Exposed from day one - the flaw shipped with the product

404 Media, which broke the story, confirmed they viewed both the exposed database URL in Moltbook's code and the list of API keys.

A Trivial Fix That Should Have Happened Before Launch

Here's what makes this incident so frustrating. The fix was trivial. Two SQL statements would have protected the API keys:

-- Enable Row Level Security on the agents table
ALTER TABLE agents ENABLE ROW LEVEL SECURITY;

-- Create a policy so users can only access their own data
CREATE POLICY "Users can only access own data"
  ON agents FOR ALL
  USING (auth.uid() = owner_id);

That's it. Two lines of SQL. The kind of thing that takes 30 seconds to write.

This wasn't a sophisticated attack or a zero-day exploit. It was a missing configuration that any basic security scan would have flagged before launch. The Supabase URL and anon key were sitting right there in the client-side JavaScript, and without RLS enabled, that meant full database access for anyone who looked.

Why This Keeps Happening

The Supabase Mental Model Problem

Supabase is fantastic for building quickly. But its ease of use creates a dangerous assumption: if it works, it must be secure.

When you create a Supabase project, you get two keys:

  • anon key - Designed for client-side use. Not secret.
  • service_role key - Admin access. Keep this secret.

Many developers treat the anon key like a secret API key. They think hiding it provides protection. But that's not how Supabase works. The anon key is meant to be public. Security comes from RLS policies, not from hiding the key.

The misconception: "My API key is in client-side code, but that's fine because nobody will find it."

The reality: Every security researcher, and plenty of malicious actors, know exactly where to look for exposed database credentials. It takes about 30 seconds to find them.

The "Ship Now, Secure Later" Trap

Moltbook isn't alone. This pattern shows up constantly in vibe-coded apps:

  1. Build fast with AI tools
  2. Get it working
  3. Ship it
  4. Plan to add security "later"
  5. "Later" never comes
  6. Security researcher (or worse, attacker) finds the flaw

As AI researcher Mark Riedl observed about the Moltbook incident: "AI community relearning past 20 years of cybersecurity courses in hardest way possible."

The Aftermath

After O'Reilly's disclosure:

  • The platform was temporarily taken offline to patch the breach
  • All API keys were force-reset
  • Moltbook's founder reached out to O'Reilly for help securing the platform
  • The exposed database was closed

O'Reilly acted responsibly - he reported the vulnerability rather than exploiting it. Not everyone who finds these issues is so ethical. If a malicious actor had found this first, they could have:

  • Posted malicious content as any user
  • Extracted all user data
  • Deleted or corrupted the entire database
  • Used the compromised accounts for spam or scams

The Case for Scanning Before You Ship

Moltbook's exposure was entirely preventable. This wasn't a subtle vulnerability that required deep security expertise to find. The Supabase URL and anon key were in client-side JavaScript. Any automated scanner would have flagged it immediately.

A single pre-launch security scan would have caught:

  • The exposed database credentials in client-side code
  • The missing RLS configuration that left all data accessible
  • The full read/write access available to unauthenticated users

This is what basic security hygiene looks like. Not penetration testing. Not a security audit. Just a simple automated scan that checks for obvious misconfigurations before you go live.

What About After Launch?

Pre-launch scanning catches the obvious issues. But continuous scanning matters too:

  • New code introduces new risks. A feature that was secure yesterday might not be secure after today's update.
  • Configuration drift happens. Someone disables RLS "temporarily" for debugging and forgets to re-enable it.
  • Dependencies change. A library update might expose something that was previously protected.

Regular scanning gives you peace of mind. You can focus on building instead of worrying about what you might have missed.

Is my Supabase database at risk?

If you haven't enabled Row Level Security and created appropriate policies for all tables, then yes. Test by trying to query your database with just the anon key and no user authentication. If you can access data that should be protected, you have a problem.

What's the difference between the anon key and service_role key?

The anon key is meant to be used in client-side code and is not secret. Security comes from RLS policies. The service_role key bypasses RLS and should never be exposed in client code - it's for server-side use only.

How do I know if my RLS is configured correctly?

The best test is to try to access data you shouldn't be able to access. Sign in as User A and try to query User B's data. If you can see it, your policies are wrong. Also test unauthenticated access - with proper RLS, queries without auth should return nothing (or only public data).

Could this happen with Firebase too?

Absolutely. Firebase has similar security rules that need to be configured properly. The default "test mode" in Firebase is wide open by design and will expire - but many apps ship with it permanently enabled. The same principles apply: never trust that your configuration is secure without testing it.

Is Your Database Exposed?

Run a free scan to check for exposed API keys, missing RLS, and other common vulnerabilities before you launch.

Start Free Scan
Security Stories

How Moltbook Exposed 1.5 Million API Keys in Client-Side Code